[Libreoffice-commits] core.git: 5 commits - offapi/com offapi/type_reference sw/CppunitTest_sw_mailmerge.mk sw/inc sw/Module_sw.mk sw/qa sw/source

Jan-Marek Glogowski glogow at fbihome.de
Wed Oct 1 01:34:40 PDT 2014


 offapi/com/sun/star/text/MailMergeType.idl                   |    9 
 offapi/type_reference/offapi.idl                             |    1 
 sw/CppunitTest_sw_mailmerge.mk                               |   93 +++
 sw/Module_sw.mk                                              |    1 
 sw/inc/anchoreddrawobject.hxx                                |    2 
 sw/inc/anchoredobject.hxx                                    |    4 
 sw/inc/dbmgr.hxx                                             |   50 +-
 sw/inc/doc.hxx                                               |    2 
 sw/inc/docary.hxx                                            |   14 
 sw/inc/ndarr.hxx                                             |    2 
 sw/inc/ndhints.hxx                                           |    4 
 sw/inc/ndtxt.hxx                                             |    2 
 sw/inc/node.hxx                                              |    4 
 sw/inc/numrule.hxx                                           |    2 
 sw/inc/swabstdlg.hxx                                         |    2 
 sw/qa/extras/inc/swmodeltestbase.hxx                         |  161 ++++++
 sw/qa/extras/mailmerge/data/4_v01.ods                        |binary
 sw/qa/extras/mailmerge/data/multiple-page-anchored-draws.odt |binary
 sw/qa/extras/mailmerge/mailmerge.cxx                         |   76 +++
 sw/source/core/docnode/nodedump.cxx                          |   36 -
 sw/source/core/inc/MarkManager.hxx                           |    2 
 sw/source/core/inc/flyfrm.hxx                                |    2 
 sw/source/core/inc/frame.hxx                                 |    8 
 sw/source/core/inc/sectfrm.hxx                               |    2 
 sw/source/core/inc/tabfrm.hxx                                |    2 
 sw/source/core/inc/txtfrm.hxx                                |    2 
 sw/source/core/text/xmldump.cxx                              |   22 
 sw/source/ui/dbui/mailmergewizard.cxx                        |    2 
 sw/source/ui/dialog/swdlgfact.cxx                            |    4 
 sw/source/ui/dialog/swdlgfact.hxx                            |    2 
 sw/source/ui/envelp/mailmrge.cxx                             |    7 
 sw/source/uibase/dbui/dbmgr.cxx                              |  271 ++++++-----
 sw/source/uibase/inc/mailmrge.hxx                            |    6 
 sw/source/uibase/uno/unomailmerge.cxx                        |  172 +++---
 34 files changed, 700 insertions(+), 269 deletions(-)

New commits:
commit 4687ce06757e75432bde17bf4077e45ce88bb126
Author: Jan-Marek Glogowski <glogow at fbihome.de>
Date:   Wed Sep 24 20:02:57 2014 +0200

    Constify dumpAsXml and friends
    
    All these dump functions should never change the dumped objects
    so 'const' all of them.
    
    Change-Id: Id83422e3950a73e48feb4708fbd4c251506997e0

diff --git a/sw/inc/anchoreddrawobject.hxx b/sw/inc/anchoreddrawobject.hxx
index e49185e..55fdb78 100644
--- a/sw/inc/anchoreddrawobject.hxx
+++ b/sw/inc/anchoreddrawobject.hxx
@@ -188,7 +188,7 @@ class SW_DLLPUBLIC SwAnchoredDrawObject : public SwAnchoredObject
 
         /** The element name to show in the XML dump.
           */
-        virtual const char* getElementName( ) SAL_OVERRIDE { return "SwAnchoredDrawObject"; }
+        virtual const char* getElementName( ) const SAL_OVERRIDE { return "SwAnchoredDrawObject"; }
 };
 
 #endif
diff --git a/sw/inc/anchoredobject.hxx b/sw/inc/anchoredobject.hxx
index 14750c8..c31afee 100644
--- a/sw/inc/anchoredobject.hxx
+++ b/sw/inc/anchoredobject.hxx
@@ -542,11 +542,11 @@ class SW_DLLPUBLIC SwAnchoredObject
         /** Dump a bunch of useful data to an XML representation to ease
             layout understanding, debugging and testing.
           */
-        virtual void dumpAsXml( xmlTextWriterPtr pWriter );
+        virtual void dumpAsXml( xmlTextWriterPtr pWriter ) const;
 
         /** The element name to show in the XML dump.
           */
-        virtual const char* getElementName( ) { return "SwAnchoredObject"; }
+        virtual const char* getElementName( ) const { return "SwAnchoredObject"; }
 };
 
 /// Helper class for notify that positioning of an anchored object is in progress.
diff --git a/sw/inc/doc.hxx b/sw/inc/doc.hxx
index 1742d8e..209c745 100644
--- a/sw/inc/doc.hxx
+++ b/sw/inc/doc.hxx
@@ -1669,7 +1669,7 @@ public:
      * Dumps the entire nodes structure to the given destination (file nodes.xml in the current directory by default)
      * @since 3.5
      */
-    void dumpAsXml( xmlTextWriterPtr writer = NULL );
+    void dumpAsXml( xmlTextWriterPtr writer = NULL ) const;
 
     std::vector<Color> GetDocColors();
 
diff --git a/sw/inc/docary.hxx b/sw/inc/docary.hxx
index 2c7c75a..0f75324 100644
--- a/sw/inc/docary.hxx
+++ b/sw/inc/docary.hxx
@@ -81,7 +81,7 @@ public:
     virtual SwFmt* GetFmt(size_t idx) const SAL_OVERRIDE { return (SwFmt*)operator[](idx); }
     sal_uInt16 GetPos(const SwFrmFmt* pFmt) const;
     bool Contains(const SwFrmFmt* pFmt) const;
-    void dumpAsXml(xmlTextWriterPtr w, const char* pName);
+    void dumpAsXml(xmlTextWriterPtr w, const char* pName) const;
     /// free's any remaining child objects
     virtual ~SwFrmFmts();
 };
@@ -93,7 +93,7 @@ public:
     virtual SwFmt* GetFmt(size_t idx) const SAL_OVERRIDE { return (SwFmt*)operator[](idx); }
     sal_uInt16 GetPos(const SwCharFmt* pFmt) const;
     bool Contains(const SwCharFmt* pFmt) const;
-    void dumpAsXml(xmlTextWriterPtr w);
+    void dumpAsXml(xmlTextWriterPtr w) const;
     /// free's any remaining child objects
     virtual ~SwCharFmts();
 };
@@ -104,7 +104,7 @@ public:
     virtual size_t GetFmtCount() const SAL_OVERRIDE { return size(); }
     virtual SwFmt* GetFmt(size_t idx) const SAL_OVERRIDE { return (SwFmt*)operator[](idx); }
     sal_uInt16 GetPos(const SwTxtFmtColl* pFmt) const;
-    void dumpAsXml(xmlTextWriterPtr w);
+    void dumpAsXml(xmlTextWriterPtr w) const;
     virtual ~SwTxtFmtColls() {}
 };
 
@@ -116,7 +116,7 @@ public:
     virtual SwFmt* GetFmt(size_t idx) const SAL_OVERRIDE { return (SwFmt*)operator[](idx); }
     sal_uInt16 GetPos(const SwSectionFmt* pFmt) const;
     bool Contains(const SwSectionFmt* pFmt) const;
-    void dumpAsXml(xmlTextWriterPtr w);
+    void dumpAsXml(xmlTextWriterPtr w) const;
     /// free's any remaining child objects
     virtual ~SwSectionFmts();
 };
@@ -141,7 +141,7 @@ public:
     /// the destructor will free all objects still in the vector
     ~SwNumRuleTbl();
     sal_uInt16 GetPos(const SwNumRule* pRule) const;
-    void dumpAsXml(xmlTextWriterPtr w);
+    void dumpAsXml(xmlTextWriterPtr w) const;
 };
 
 struct CompareSwRedlineTbl
@@ -171,7 +171,7 @@ public:
     void DeleteAndDestroy( sal_uInt16 nPos, sal_uInt16 nLen = 1 );
     void DeleteAndDestroyAll();
 
-    void dumpAsXml(xmlTextWriterPtr w);
+    void dumpAsXml(xmlTextWriterPtr w) const;
 
     /** Search next or previous Redline with the same Seq. No.
        Search can be restricted via Lookahaed.
@@ -214,7 +214,7 @@ public:
     void DeleteAndDestroy( sal_uInt16 nPos, sal_uInt16 nLen = 1 );
     void DeleteAndDestroyAll();
 
-    void dumpAsXml(xmlTextWriterPtr w);
+    void dumpAsXml(xmlTextWriterPtr w) const;
 
     sal_uInt16 GetSize() const                              {     return m_aExtraRedlines.size();                }
     SwExtraRedline* GetRedline( sal_uInt16 uIndex ) const   {     return m_aExtraRedlines.operator[]( uIndex );  }
diff --git a/sw/inc/ndarr.hxx b/sw/inc/ndarr.hxx
index 02292de..5ed0970 100644
--- a/sw/inc/ndarr.hxx
+++ b/sw/inc/ndarr.hxx
@@ -333,7 +333,7 @@ public:
      * Dumps the entire nodes structure to the given destination (file nodes.xml in the current directory by default)
      * @since 3.5
      */
-    void dumpAsXml( xmlTextWriterPtr writer = NULL );
+    void dumpAsXml( xmlTextWriterPtr writer = NULL ) const;
 };
 
 #endif
diff --git a/sw/inc/ndhints.hxx b/sw/inc/ndhints.hxx
index 291ee34..4bfbd1f 100644
--- a/sw/inc/ndhints.hxx
+++ b/sw/inc/ndhints.hxx
@@ -117,7 +117,9 @@ public:
     inline size_t GetStartOf( const SwTxtAttr *pHt ) const;
     bool Contains( const SwTxtAttr *pHt ) const;
 
-    inline SwTxtAttr * GetTextHint( const size_t nIdx )
+    inline const SwTxtAttr * GetTextHint( const size_t nIdx ) const
+        { return GetStart(nIdx); }
+    inline       SwTxtAttr * GetTextHint( const size_t nIdx )
         { return GetStart(nIdx); }
     inline const SwTxtAttr * operator[]( const size_t nIdx ) const
         { return m_HintStarts[nIdx]; }
diff --git a/sw/inc/ndtxt.hxx b/sw/inc/ndtxt.hxx
index 8c7a049..66594ee 100644
--- a/sw/inc/ndtxt.hxx
+++ b/sw/inc/ndtxt.hxx
@@ -792,7 +792,7 @@ public:
 
     bool IsCollapse() const;
 
-    virtual void dumpAsXml( xmlTextWriterPtr writer = NULL ) SAL_OVERRIDE;
+    virtual void dumpAsXml( xmlTextWriterPtr writer = NULL ) const SAL_OVERRIDE;
 
     sal_uInt32 GetRsid( sal_Int32 nStt, sal_Int32 nEnd ) const;
     sal_uInt32 GetParRsid() const;
diff --git a/sw/inc/node.hxx b/sw/inc/node.hxx
index f83b806..8f16f46 100644
--- a/sw/inc/node.hxx
+++ b/sw/inc/node.hxx
@@ -285,7 +285,7 @@ public:
      * Dumps the node structure to the given destination (file nodes.xml in the current directory by default)
      * @since 3.5
      */
-    virtual void dumpAsXml( xmlTextWriterPtr writer = NULL );
+    virtual void dumpAsXml( xmlTextWriterPtr writer = NULL ) const;
 
 private:
     /// Private constructor because copying is never allowed!!
@@ -318,7 +318,7 @@ public:
     /// Call ChkCondcoll to all ContentNodes of section.
     void CheckSectionCondColl() const;
 
-    virtual void dumpAsXml( xmlTextWriterPtr writer = NULL ) SAL_OVERRIDE;
+    virtual void dumpAsXml( xmlTextWriterPtr writer = NULL ) const SAL_OVERRIDE;
 
 private:
     /// Private constructor because copying is never allowed!!
diff --git a/sw/inc/numrule.hxx b/sw/inc/numrule.hxx
index 10d9eef..ff2322c 100644
--- a/sw/inc/numrule.hxx
+++ b/sw/inc/numrule.hxx
@@ -272,7 +272,7 @@ public:
     void SetIndentOfFirstListLevelAndChangeOthers( const short nNewIndent );
 
     void Validate();
-    void dumpAsXml(xmlTextWriterPtr w);
+    void dumpAsXml(xmlTextWriterPtr w) const;
     void GetGrabBagItem(com::sun::star::uno::Any& rVal) const;
     void SetGrabBagItem(const com::sun::star::uno::Any& rVal);
 };
diff --git a/sw/source/core/docnode/nodedump.cxx b/sw/source/core/docnode/nodedump.cxx
index 40bbecb..4dcfb40 100644
--- a/sw/source/core/docnode/nodedump.cxx
+++ b/sw/source/core/docnode/nodedump.cxx
@@ -180,7 +180,7 @@ void lcl_dumpSdrModel(WriterHelper& writer, const SdrModel* pModel)
     writer.endElement();
 }
 
-void SwDoc::dumpAsXml( xmlTextWriterPtr w )
+void SwDoc::dumpAsXml( xmlTextWriterPtr w ) const
 {
     WriterHelper writer( w );
     writer.startElement( "doc" );
@@ -208,7 +208,7 @@ void SwDoc::dumpAsXml( xmlTextWriterPtr w )
 
 namespace sw {
 namespace mark {
-void MarkManager::dumpAsXml( xmlTextWriterPtr w )
+void MarkManager::dumpAsXml( xmlTextWriterPtr w ) const
 {
     WriterHelper writer(w);
     writer.startElement("markManager");
@@ -287,7 +287,7 @@ void SwFldTypes::dumpAsXml( xmlTextWriterPtr w ) const
     writer.endElement();
 }
 
-void SwNodes::dumpAsXml( xmlTextWriterPtr w )
+void SwNodes::dumpAsXml( xmlTextWriterPtr w ) const
 {
     WriterHelper writer( w );
     writer.startElement( "swnodes" );
@@ -299,7 +299,7 @@ void SwNodes::dumpAsXml( xmlTextWriterPtr w )
     writer.endElement();
 }
 
-void SwNode::dumpAsXml( xmlTextWriterPtr w )
+void SwNode::dumpAsXml( xmlTextWriterPtr w ) const
 {
     WriterHelper writer( w );
     const char* name = "???";
@@ -330,7 +330,7 @@ void SwNode::dumpAsXml( xmlTextWriterPtr w )
         writer.endElement(); // end start node
 }
 
-void SwStartNode::dumpAsXml( xmlTextWriterPtr w )
+void SwStartNode::dumpAsXml( xmlTextWriterPtr w ) const
 {
     WriterHelper writer( w );
     const char* name = "???";
@@ -603,7 +603,7 @@ void lcl_dumpSfxItemSet(WriterHelper& writer, const SfxItemSet* pSet)
     }
 }
 
-void SwFrmFmts::dumpAsXml(xmlTextWriterPtr w, const char* pName)
+void SwFrmFmts::dumpAsXml(xmlTextWriterPtr w, const char* pName) const
 {
     WriterHelper writer(w);
     if (size())
@@ -638,7 +638,7 @@ void SwFrmFmts::dumpAsXml(xmlTextWriterPtr w, const char* pName)
     }
 }
 
-void SwCharFmts::dumpAsXml(xmlTextWriterPtr w)
+void SwCharFmts::dumpAsXml(xmlTextWriterPtr w) const
 {
     WriterHelper writer(w);
     if (size())
@@ -658,7 +658,7 @@ void SwCharFmts::dumpAsXml(xmlTextWriterPtr w)
     }
 }
 
-void SwSectionFmts::dumpAsXml(xmlTextWriterPtr w)
+void SwSectionFmts::dumpAsXml(xmlTextWriterPtr w) const
 {
     WriterHelper writer(w);
     if (size())
@@ -675,7 +675,7 @@ void SwSectionFmts::dumpAsXml(xmlTextWriterPtr w)
     }
 }
 
-void SwTxtFmtColls::dumpAsXml(xmlTextWriterPtr w)
+void SwTxtFmtColls::dumpAsXml(xmlTextWriterPtr w) const
 {
     WriterHelper writer(w);
     if (size())
@@ -695,7 +695,7 @@ void SwTxtFmtColls::dumpAsXml(xmlTextWriterPtr w)
     }
 }
 
-void SwNumRule::dumpAsXml(xmlTextWriterPtr w)
+void SwNumRule::dumpAsXml(xmlTextWriterPtr w) const
 {
      WriterHelper writer(w);
      writer.startElement("swnumrule");
@@ -707,7 +707,7 @@ void SwNumRule::dumpAsXml(xmlTextWriterPtr w)
      writer.endElement();
 }
 
-void SwNumRuleTbl::dumpAsXml(xmlTextWriterPtr w)
+void SwNumRuleTbl::dumpAsXml(xmlTextWriterPtr w) const
 {
     if (!empty())
     {
@@ -719,7 +719,7 @@ void SwNumRuleTbl::dumpAsXml(xmlTextWriterPtr w)
     }
 }
 
-void SwTxtNode::dumpAsXml( xmlTextWriterPtr w )
+void SwTxtNode::dumpAsXml( xmlTextWriterPtr w ) const
 {
     WriterHelper writer( w );
     writer.startElement( "text" );
@@ -753,16 +753,16 @@ void SwTxtNode::dumpAsXml( xmlTextWriterPtr w )
     if (HasHints())
     {
         writer.startElement("hints");
-        SwpHints& rHints = GetSwpHints();
+        const SwpHints& rHints = GetSwpHints();
         for (size_t i = 0; i < rHints.Count(); ++i)
         {
             writer.startElement("hint");
-            SwTxtAttr* pHint = rHints.GetTextHint(i);
+            const SwTxtAttr* pHint = rHints.GetTextHint(i);
 
             if (pHint->GetStart())
                 writer.writeFormatAttribute("start", TMP_FORMAT, pHint->GetStart());
-            if (pHint->GetEnd())
-                writer.writeFormatAttribute("end", TMP_FORMAT, *pHint->GetEnd());
+            if (pHint->End())
+                writer.writeFormatAttribute("end", TMP_FORMAT, *pHint->End());
             writer.writeFormatAttribute("whichId", TMP_FORMAT, pHint->Which());
 
             const char* pWhich = 0;
@@ -801,7 +801,7 @@ void SwTxtNode::dumpAsXml( xmlTextWriterPtr w )
     writer.endElement();
 }
 
-void SwRedlineTbl::dumpAsXml( xmlTextWriterPtr w )
+void SwRedlineTbl::dumpAsXml( xmlTextWriterPtr w ) const
 {
     WriterHelper writer( w );
 
@@ -938,7 +938,7 @@ void SwRedlineTbl::dumpAsXml( xmlTextWriterPtr w )
     writer.endElement( );    // swredlinetbl
 }
 
-void SwExtraRedlineTbl::dumpAsXml( xmlTextWriterPtr w )
+void SwExtraRedlineTbl::dumpAsXml( xmlTextWriterPtr w ) const
 {
     WriterHelper writer( w );
 
diff --git a/sw/source/core/inc/MarkManager.hxx b/sw/source/core/inc/MarkManager.hxx
index 2a4f5d7..ccd614e 100644
--- a/sw/source/core/inc/MarkManager.hxx
+++ b/sw/source/core/inc/MarkManager.hxx
@@ -85,7 +85,7 @@ namespace sw {
             virtual ::sw::mark::IFieldmark* getDropDownFor(const SwPosition &rPos) const SAL_OVERRIDE;
             virtual std::vector< ::sw::mark::IFieldmark* > getDropDownsFor(const SwPaM &rPaM) const SAL_OVERRIDE;
 
-            void dumpAsXml(xmlTextWriterPtr w);
+            void dumpAsXml(xmlTextWriterPtr w) const;
 
             // Annotation Marks
             virtual const_iterator_t getAnnotationMarksBegin() const SAL_OVERRIDE;
diff --git a/sw/source/core/inc/flyfrm.hxx b/sw/source/core/inc/flyfrm.hxx
index ac895fb..33f0aa7 100644
--- a/sw/source/core/inc/flyfrm.hxx
+++ b/sw/source/core/inc/flyfrm.hxx
@@ -284,7 +284,7 @@ public:
     virtual const SwFlyFrmFmt *GetFmt() const SAL_OVERRIDE;
     virtual       SwFlyFrmFmt *GetFmt() SAL_OVERRIDE;
 
-    virtual void dumpAsXml( xmlTextWriterPtr writer ) SAL_OVERRIDE { SwLayoutFrm::dumpAsXml( writer ); };
+    virtual void dumpAsXml( xmlTextWriterPtr writer ) const SAL_OVERRIDE { SwLayoutFrm::dumpAsXml( writer ); };
 
     virtual void Calc() const SAL_OVERRIDE;
 
diff --git a/sw/source/core/inc/frame.hxx b/sw/source/core/inc/frame.hxx
index 48105d9..42fa2e5 100644
--- a/sw/source/core/inc/frame.hxx
+++ b/sw/source/core/inc/frame.hxx
@@ -899,10 +899,10 @@ public:
 
 public:
     // if writer is NULL, dumps the layout structure as XML in layout.xml
-    virtual void dumpAsXml(xmlTextWriterPtr writer = NULL);
-    virtual void dumpInfosAsXml(xmlTextWriterPtr writer);
-    virtual void dumpAsXmlAttributes(xmlTextWriterPtr writer);
-    void dumpChildrenAsXml(xmlTextWriterPtr writer);
+    virtual void dumpAsXml(xmlTextWriterPtr writer = NULL) const;
+    virtual void dumpInfosAsXml(xmlTextWriterPtr writer) const;
+    virtual void dumpAsXmlAttributes(xmlTextWriterPtr writer) const;
+    void dumpChildrenAsXml(xmlTextWriterPtr writer) const;
     bool IsCollapse() const;
 };
 
diff --git a/sw/source/core/inc/sectfrm.hxx b/sw/source/core/inc/sectfrm.hxx
index aa6f224..d5ffa32 100644
--- a/sw/source/core/inc/sectfrm.hxx
+++ b/sw/source/core/inc/sectfrm.hxx
@@ -127,7 +127,7 @@ public:
 
     bool IsBalancedSection() const;
 
-    virtual void dumpAsXmlAttributes(xmlTextWriterPtr writer) SAL_OVERRIDE;
+    virtual void dumpAsXmlAttributes(xmlTextWriterPtr writer) const SAL_OVERRIDE;
 
     bool IsFtnAtEnd() const { return bFtnAtEnd; }
     bool IsEndnAtEnd() const { return bEndnAtEnd;   }
diff --git a/sw/source/core/inc/tabfrm.hxx b/sw/source/core/inc/tabfrm.hxx
index b983d10..d447198 100644
--- a/sw/source/core/inc/tabfrm.hxx
+++ b/sw/source/core/inc/tabfrm.hxx
@@ -215,7 +215,7 @@ public:
 
     sal_uInt16 GetBottomLineSize() const;
 
-    virtual void dumpAsXmlAttributes(xmlTextWriterPtr writer) SAL_OVERRIDE;
+    virtual void dumpAsXmlAttributes(xmlTextWriterPtr writer) const SAL_OVERRIDE;
 
     DECL_FIXEDMEMPOOL_NEWDEL(SwTabFrm)
 };
diff --git a/sw/source/core/inc/txtfrm.hxx b/sw/source/core/inc/txtfrm.hxx
index ce7df21..3cdc441 100644
--- a/sw/source/core/inc/txtfrm.hxx
+++ b/sw/source/core/inc/txtfrm.hxx
@@ -581,7 +581,7 @@ public:
 
     static void repaintTextFrames( const SwTxtNode& rNode );
 
-    virtual void dumpAsXmlAttributes(xmlTextWriterPtr writer) SAL_OVERRIDE;
+    virtual void dumpAsXmlAttributes(xmlTextWriterPtr writer) const SAL_OVERRIDE;
 };
 
 class SwTxtFrmLocker
diff --git a/sw/source/core/text/xmldump.cxx b/sw/source/core/text/xmldump.cxx
index 75e9706..4365487 100644
--- a/sw/source/core/text/xmldump.cxx
+++ b/sw/source/core/text/xmldump.cxx
@@ -223,7 +223,7 @@ namespace
     }
 }
 
-void SwFrm::dumpAsXml( xmlTextWriterPtr writer )
+void SwFrm::dumpAsXml( xmlTextWriterPtr writer ) const
 {
     bool bCreateWriter = ( NULL == writer );
     if ( bCreateWriter )
@@ -292,7 +292,7 @@ void SwFrm::dumpAsXml( xmlTextWriterPtr writer )
         if (IsRootFrm())
         {
             // Root frame has access to the edit shell, so dump the current selection ranges here.
-            SwRootFrm* const pRootFrm = static_cast<SwRootFrm* const>(this);
+            const SwRootFrm* const pRootFrm = static_cast<const SwRootFrm* const>(this);
             SwEditShell* pEditShell = pRootFrm->GetCurrShell()->GetDoc()->GetEditShell();
             xmlTextWriterStartElement(writer, BAD_CAST("shellCrsr"));
             SwPaM* pPaM = pEditShell->getShellCrsr(false);
@@ -316,7 +316,7 @@ void SwFrm::dumpAsXml( xmlTextWriterPtr writer )
         xmlTextWriterEndElement( writer );
 
         // Dump Anchored objects if any
-        SwSortedObjs* pAnchored = GetDrawObjs();
+        const SwSortedObjs* pAnchored = GetDrawObjs();
         if ( pAnchored && pAnchored->size() > 0 )
         {
             xmlTextWriterStartElement( writer, BAD_CAST( "anchored" ) );
@@ -358,7 +358,7 @@ void SwFrm::dumpAsXml( xmlTextWriterPtr writer )
         lcl_freeWriter( writer );
 }
 
-void SwFrm::dumpInfosAsXml( xmlTextWriterPtr writer )
+void SwFrm::dumpInfosAsXml( xmlTextWriterPtr writer ) const
 {
     // output the Frm
     xmlTextWriterStartElement( writer, BAD_CAST( "bounds" ) );
@@ -373,7 +373,7 @@ void SwFrm::dumpInfosAsXml( xmlTextWriterPtr writer )
 // bomb on two string litterals in the format.
 static const char* TMP_FORMAT = "%" SAL_PRIuUINTPTR;
 
-void SwFrm::dumpAsXmlAttributes( xmlTextWriterPtr writer )
+void SwFrm::dumpAsXmlAttributes( xmlTextWriterPtr writer ) const
 {
     xmlTextWriterWriteFormatAttribute( writer, BAD_CAST( "ptr" ), "%p", this );
     xmlTextWriterWriteFormatAttribute( writer, BAD_CAST( "id" ), "%" SAL_PRIuUINT32, GetFrmId() );
@@ -401,16 +401,16 @@ void SwFrm::dumpAsXmlAttributes( xmlTextWriterPtr writer )
     }
 }
 
-void SwFrm::dumpChildrenAsXml( xmlTextWriterPtr writer )
+void SwFrm::dumpChildrenAsXml( xmlTextWriterPtr writer ) const
 {
-    SwFrm *pFrm = GetLower(  );
+    const SwFrm *pFrm = GetLower(  );
     for ( ; pFrm != NULL; pFrm = pFrm->GetNext(  ) )
     {
         pFrm->dumpAsXml( writer );
     }
 }
 
-void SwAnchoredObject::dumpAsXml( xmlTextWriterPtr writer )
+void SwAnchoredObject::dumpAsXml( xmlTextWriterPtr writer ) const
 {
     bool bCreateWriter = ( NULL == writer );
     if ( bCreateWriter )
@@ -432,7 +432,7 @@ void SwAnchoredObject::dumpAsXml( xmlTextWriterPtr writer )
         lcl_freeWriter( writer );
 }
 
-void SwTxtFrm::dumpAsXmlAttributes( xmlTextWriterPtr writer )
+void SwTxtFrm::dumpAsXmlAttributes( xmlTextWriterPtr writer ) const
 {
     SwFrm::dumpAsXmlAttributes( writer );
     if ( HasFollow() )
@@ -442,7 +442,7 @@ void SwTxtFrm::dumpAsXmlAttributes( xmlTextWriterPtr writer )
         xmlTextWriterWriteFormatAttribute( writer, BAD_CAST( "precede" ), "%" SAL_PRIuUINT32, static_cast<SwTxtFrm*>(m_pPrecede)->GetFrmId() );
 }
 
-void SwSectionFrm::dumpAsXmlAttributes( xmlTextWriterPtr writer )
+void SwSectionFrm::dumpAsXmlAttributes( xmlTextWriterPtr writer ) const
 {
     SwFrm::dumpAsXmlAttributes( writer );
     if ( HasFollow() )
@@ -452,7 +452,7 @@ void SwSectionFrm::dumpAsXmlAttributes( xmlTextWriterPtr writer )
         xmlTextWriterWriteFormatAttribute( writer, BAD_CAST( "precede" ), "%" SAL_PRIuUINT32, static_cast<SwSectionFrm*>( m_pPrecede )->GetFrmId() );
 }
 
-void SwTabFrm::dumpAsXmlAttributes( xmlTextWriterPtr writer )
+void SwTabFrm::dumpAsXmlAttributes( xmlTextWriterPtr writer ) const
 {
     SwFrm::dumpAsXmlAttributes( writer );
     if ( HasFollow() )
commit d10f6d49b77dcf955629901937d8d5e3a2976a6c
Author: Jan-Marek Glogowski <glogow at fbihome.de>
Date:   Tue Sep 23 10:00:13 2014 +0200

    MM: first unit test and infrastructure
    
    Extendes SwModelTestBase with mail merge functions and a declaration
    of the DECLARE_MAILMERGE_TEST macro and uses it in a first test.
    As most tests it's registered as a slow test run by 'make check'.
    
    The broken MM used to drop the leading empty pages, which resulted
    in a document with 4 pages and the two page bound draws merged
    per single page.
    
    Tests the MM result for page count (eight) and each draw anchor to
    be on a different page.
    
    Change-Id: Iab17f5844e68221d48cb89863323bcfe4c8ae0d2

diff --git a/sw/CppunitTest_sw_mailmerge.mk b/sw/CppunitTest_sw_mailmerge.mk
new file mode 100644
index 0000000..f1020ff
--- /dev/null
+++ b/sw/CppunitTest_sw_mailmerge.mk
@@ -0,0 +1,93 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_CppunitTest_CppunitTest,sw_mailmerge))
+
+$(eval $(call gb_CppunitTest_add_exception_objects,sw_mailmerge, \
+    sw/qa/extras/mailmerge/mailmerge \
+))
+
+$(eval $(call gb_CppunitTest_use_libraries,sw_mailmerge, \
+    comphelper \
+    cppu \
+    sal \
+    sw \
+    test \
+    unotest \
+    utl \
+))
+
+$(eval $(call gb_CppunitTest_use_externals,sw_mailmerge, \
+    boost_headers \
+    libxml2 \
+))
+
+$(eval $(call gb_CppunitTest_use_api,sw_mailmerge,\
+    offapi \
+    udkapi \
+))
+
+$(eval $(call gb_CppunitTest_use_components,sw_mailmerge, \
+    basic/util/sb \
+    comphelper/util/comphelp \
+    configmgr/source/configmgr \
+    connectivity/source/cpool/dbpool2 \
+    connectivity/source/drivers/calc/calc \
+    connectivity/source/manager/sdbc2 \
+    dbaccess/source/filter/xml/dbaxml \
+    dbaccess/util/dba \
+    embeddedobj/util/embobj \
+    filter/source/config/cache/filterconfig1 \
+    filter/source/storagefilterdetect/storagefd \
+    forms/util/frm \
+    framework/util/fwk \
+    i18npool/util/i18npool \
+    lingucomponent/source/languageguessing/guesslang \
+    linguistic/source/lng \
+    oox/util/oox \
+    package/source/xstor/xstor \
+    package/util/package2 \
+    sax/source/expatwrap/expwrap \
+    sc/util/sc \
+    sfx2/util/sfx \
+    sot/util/sot \
+    svl/source/fsstor/fsstorage \
+    svl/util/svl \
+    svtools/util/svt \
+    sw/util/sw \
+    sw/util/swd \
+    toolkit/util/tk \
+    ucb/source/core/ucb1 \
+    ucb/source/ucp/file/ucpfile1 \
+    ucb/source/ucp/tdoc/ucptdoc1 \
+    unotools/util/utl \
+    unoxml/source/rdf/unordf \
+    unoxml/source/service/unoxml \
+    uui/util/uui \
+    $(if $(filter-out MACOSX WNT,$(OS)), \
+        $(if $(ENABLE_HEADLESS),, \
+            vcl/vcl.unx \
+        ) \
+    ) \
+    xmloff/util/xo \
+))
+
+$(eval $(call gb_CppunitTest_use_configuration,sw_mailmerge))
+$(eval $(call gb_CppunitTest_use_ure,sw_mailmerge))
+$(eval $(call gb_CppunitTest_use_vcl,sw_mailmerge))
+
+$(eval $(call gb_CppunitTest_set_include,sw_mailmerge,\
+    -I$(SRCDIR)/sw/inc \
+    -I$(SRCDIR)/sw/source/core/inc \
+    -I$(SRCDIR)/sw/qa/extras/inc \
+    -I$(SRCDIR)/sw/source/uibase/inc \
+    $$(INCLUDE) \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/sw/Module_sw.mk b/sw/Module_sw.mk
index 3a3d75b..ba58d73 100644
--- a/sw/Module_sw.mk
+++ b/sw/Module_sw.mk
@@ -71,6 +71,7 @@ $(eval $(call gb_Module_add_slowcheck_targets,sw,\
     CppunitTest_sw_odfexport \
     CppunitTest_sw_odfimport \
     CppunitTest_sw_uiwriter \
+    CppunitTest_sw_mailmerge \
 ))
 
 ifneq ($(DISABLE_CVE_TESTS),TRUE)
diff --git a/sw/qa/extras/inc/swmodeltestbase.hxx b/sw/qa/extras/inc/swmodeltestbase.hxx
index 154d18c..cb2b2b9 100644
--- a/sw/qa/extras/inc/swmodeltestbase.hxx
+++ b/sw/qa/extras/inc/swmodeltestbase.hxx
@@ -23,6 +23,11 @@
 #include <com/sun/star/text/XTextViewCursorSupplier.hpp>
 #include <com/sun/star/table/XCell.hpp>
 #include <com/sun/star/table/BorderLine2.hpp>
+#include <com/sun/star/task/XJob.hpp>
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/sdb/DatabaseContext.hpp>
+#include <com/sun/star/sdb/XDocumentDataSource.hpp>
+#include <com/sun/star/text/MailMergeType.hpp>
 
 #include <test/bootstrapfixture.hxx>
 #include <test/xmltesttools.hxx>
@@ -34,6 +39,8 @@
 #include <comphelper/processfactory.hxx>
 #include <unotools/tempfile.hxx>
 #include <unotools/mediadescriptor.hxx>
+#include <dbmgr.hxx>
+#include <unoprnms.hxx>
 
 #include <unotxdoc.hxx>
 #include <docsh.hxx>
@@ -135,6 +142,29 @@ using namespace css;
     CPPUNIT_TEST_SUITE_REGISTRATION(TestName); \
     void TestName::verify()
 
+#define DECLARE_MAILMERGE_TEST(TestName, filename, datasource, tablename, BaseClass) \
+    class TestName : public BaseClass { \
+    protected: \
+        virtual OUString getTestName() SAL_OVERRIDE { return OUString::createFromAscii(#TestName); } \
+    public: \
+        CPPUNIT_TEST_SUITE(TestName); \
+        CPPUNIT_TEST(MailMerge); \
+        CPPUNIT_TEST_SUITE_END(); \
+    \
+        void MailMerge() { \
+            executeMailMergeTest(filename, datasource, tablename); \
+        } \
+        void verify() SAL_OVERRIDE; \
+    }; \
+    CPPUNIT_TEST_SUITE_REGISTRATION(TestName); \
+    void TestName::verify()
+
+/**
+ * Maps database URIs to the registered database names for quick lookups
+ */
+typedef std::map<OUString, OUString> DBuriMap;
+DBuriMap aDBuriMap;
+
 /// Base class for filter tests loading or roundtriping a document, then asserting the document model.
 class SwModelTestBase : public test::BootstrapFixture, public unotest::MacrosTest, public XmlTestTools
 {
@@ -142,7 +172,11 @@ private:
     OUString maFilterOptions;
 
 protected:
-    uno::Reference<lang::XComponent> mxComponent;
+    uno::Reference< lang::XComponent > mxComponent;
+    uno::Reference< lang::XComponent > mxMMComponent;
+    uno::Reference< com::sun::star::task::XJob > mxJob;
+    uno::Sequence< beans::NamedValue > mSeqMailMergeArgs;
+
     xmlBufferPtr mpXmlBuffer;
     const char* mpTestDocumentPath;
     const char* mpFilter;
@@ -156,7 +190,9 @@ protected:
 
     sal_uInt32 mnStartTime;
     utl::TempFile maTempFile;
+    utl::TempFile maTempDir;
     bool mbExported; ///< Does maTempFile already contain something useful?
+    sal_Int16 nCurOutputType;
 
 protected:
     virtual OUString getTestName() { return OUString(); }
@@ -176,7 +212,9 @@ public:
         , mpTestDocumentPath(pTestDocumentPath)
         , mpFilter(pFilter)
         , mnStartTime(0)
+        , maTempDir(NULL, true)
         , mbExported(false)
+        , nCurOutputType(0)
     {
         maTempFile.EnableKillingFile();
     }
@@ -195,6 +233,16 @@ public:
     {
         if (mxComponent.is())
             mxComponent->dispose();
+        if (mxMMComponent.is())
+        {
+            if (nCurOutputType == text::MailMergeType::SHELL)
+            {
+                SwXTextDocument* pTxtDoc = dynamic_cast<SwXTextDocument *>(mxMMComponent.get());
+                pTxtDoc->GetDocShell()->DoClose();
+            }
+            else
+                mxMMComponent->dispose();
+        }
 
         test::BootstrapFixture::tearDown();
     }
@@ -259,6 +307,32 @@ protected:
     }
 
     /**
+     * Helper func used by each unit test to test the 'mail merge' code.
+     *
+     * Registers the data source, loads the original file as reference,
+     * initializes the mail merge job and its default argument sequence.
+     *
+     * The 'verify' method actually has to execute the mail merge by
+     * calling executeMailMerge() after modifying the job arguments.
+     */
+    void executeMailMergeTest(const char* filename, const char* datasource, const char* tablename = 0)
+    {
+        header();
+        preTest(filename);
+        load(mpTestDocumentPath, filename);
+
+        const OUString aPrefix( "LOMM_" );
+        const OUString aWorkDir = maTempDir.GetURL();
+        const OUString aURI( getURLFromSrc(mpTestDocumentPath) + OUString::createFromAscii(datasource) );
+        OUString aDBName = registerDBsource( aURI, aPrefix, aWorkDir );
+        initMailMergeJobAndArgs( filename, tablename, aDBName, aPrefix, aWorkDir );
+
+        postTest(filename);
+        verify();
+        finish();
+    }
+
+    /**
      * Function overloaded by unit test. See DECLARE_SW_*_TEST macros
      */
     virtual void verify()
@@ -288,7 +362,7 @@ protected:
     }
 
     /**
-     * Override this function if not calcing layout is needed
+     * Override this function if calcing layout is not needed
      */
     virtual bool mustCalcLayoutOf(const char* /*filename*/)
     {
@@ -688,6 +762,89 @@ protected:
         xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("a14"), BAD_CAST("http://schemas.microsoft.com/office/drawing/2010/main"));
         xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("o"), BAD_CAST("urn:schemas-microsoft-com:office:office"));
     }
+
+    virtual OUString registerDBsource( const OUString &aURI, const OUString &aPrefix, const OUString &aWorkDir )
+    {
+        OUString aDBName;
+        DBuriMap::const_iterator pos = aDBuriMap.find( aURI );
+        if (pos == aDBuriMap.end())
+        {
+            aDBName = SwDBManager::LoadAndRegisterDataSource( aURI, &aPrefix, &aWorkDir );
+            aDBuriMap.insert( std::pair< OUString, OUString >( aURI, aDBName ) );
+            std::cout << "New datasource name: '" << aDBName << "'" << std::endl;
+        }
+        else
+        {
+            aDBName = pos->second;
+            std::cout << "Old datasource name: '" << aDBName << "'" << std::endl;
+        }
+        CPPUNIT_ASSERT(!aDBName.isEmpty());
+        return aDBName;
+    }
+
+    virtual void initMailMergeJobAndArgs( const char* filename, const char* tablename, const OUString &aDBName,
+                                          const OUString &aPrefix, const OUString &aWorkDir )
+    {
+        uno::Reference< task::XJob > xJob( getMultiServiceFactory()->createInstance( "com.sun.star.text.MailMerge" ), uno::UNO_QUERY_THROW );
+        mxJob.set( xJob );
+
+        int seq_id = 5;
+        if (tablename) seq_id += 2;
+        mSeqMailMergeArgs.realloc( seq_id );
+
+        seq_id = 0;
+        mSeqMailMergeArgs[ seq_id++ ] = beans::NamedValue( OUString( UNO_NAME_OUTPUT_TYPE ), uno::Any( text::MailMergeType::SHELL ) );
+        mSeqMailMergeArgs[ seq_id++ ] = beans::NamedValue( OUString( UNO_NAME_DOCUMENT_URL ), uno::Any(
+                                        ( OUString(getURLFromSrc(mpTestDocumentPath) + OUString::createFromAscii(filename)) ) ) );
+        mSeqMailMergeArgs[ seq_id++ ] = beans::NamedValue( OUString( UNO_NAME_DATA_SOURCE_NAME ), uno::Any( aDBName ) );
+        mSeqMailMergeArgs[ seq_id++ ] = beans::NamedValue( OUString( UNO_NAME_OUTPUT_URL ), uno::Any( aWorkDir ) );
+        mSeqMailMergeArgs[ seq_id++ ] = beans::NamedValue( OUString( UNO_NAME_FILE_NAME_PREFIX ), uno::Any( aPrefix ));
+        if (tablename)
+        {
+            mSeqMailMergeArgs[ seq_id++ ] = beans::NamedValue( OUString( UNO_NAME_DAD_COMMAND_TYPE ), uno::Any( sdb::CommandType::TABLE ) );
+            mSeqMailMergeArgs[ seq_id++ ] = beans::NamedValue( OUString( UNO_NAME_DAD_COMMAND ), uno::Any( OUString::createFromAscii(tablename) ) );
+        }
+    }
+
+    virtual void executeMailMerge()
+    {
+        uno::Any res = mxJob->execute( mSeqMailMergeArgs );
+
+        OUString aCurOutputURL;
+        OUString aCurFileNamePrefix;
+        const beans::NamedValue *pArguments = mSeqMailMergeArgs.getConstArray();
+        bool bOk = true;
+        sal_Int32 nArgs = mSeqMailMergeArgs.getLength();
+
+        for (sal_Int32 i = 0; i < nArgs; ++i) {
+            const OUString &rName  = pArguments[i].Name;
+            const uno::Any &rValue = pArguments[i].Value;
+
+            // all error checking was already done by the MM job execution
+            if (rName == UNO_NAME_OUTPUT_URL)
+                bOk &= rValue >>= aCurOutputURL;
+            else if (rName == UNO_NAME_FILE_NAME_PREFIX)
+                bOk &= rValue >>= aCurFileNamePrefix;
+            else if (rName == UNO_NAME_OUTPUT_TYPE)
+                bOk &= rValue >>= nCurOutputType;
+        }
+
+        CPPUNIT_ASSERT(bOk);
+
+        if (nCurOutputType == text::MailMergeType::SHELL)
+        {
+            CPPUNIT_ASSERT(res >>= mxMMComponent);
+            CPPUNIT_ASSERT(mxMMComponent.is());
+        }
+        else
+        {
+            CPPUNIT_ASSERT(res == true);
+            mxMMComponent = loadFromDesktop( aCurOutputURL + "/" + aCurFileNamePrefix + "0.odt",
+                                             "com.sun.star.text.TextDocument");
+            CPPUNIT_ASSERT(mxMMComponent.is());
+            calcLayout();
+        }
+    }
 };
 
 /**
diff --git a/sw/qa/extras/mailmerge/data/4_v01.ods b/sw/qa/extras/mailmerge/data/4_v01.ods
new file mode 100644
index 0000000..ffbf33b
Binary files /dev/null and b/sw/qa/extras/mailmerge/data/4_v01.ods differ
diff --git a/sw/qa/extras/mailmerge/data/multiple-page-anchored-draws.odt b/sw/qa/extras/mailmerge/data/multiple-page-anchored-draws.odt
new file mode 100644
index 0000000..55a0436
Binary files /dev/null and b/sw/qa/extras/mailmerge/data/multiple-page-anchored-draws.odt differ
diff --git a/sw/qa/extras/mailmerge/mailmerge.cxx b/sw/qa/extras/mailmerge/mailmerge.cxx
new file mode 100644
index 0000000..7c51b3f
--- /dev/null
+++ b/sw/qa/extras/mailmerge/mailmerge.cxx
@@ -0,0 +1,76 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <swmodeltestbase.hxx>
+
+#if !defined(MACOSX) && !defined(WNT)
+
+#include <com/sun/star/awt/FontWeight.hpp>
+#include <com/sun/star/style/PageStyleLayout.hpp>
+#include <com/sun/star/table/XCell.hpp>
+#include <com/sun/star/table/BorderLine.hpp>
+#include <com/sun/star/text/XTextTable.hpp>
+#include <com/sun/star/text/MailMergeType.hpp>
+#include <com/sun/star/sdb/XDocumentDataSource.hpp>
+#include <com/sun/star/text/TextContentAnchorType.hpp>
+
+#include <wrtsh.hxx>
+#include <ndtxt.hxx>
+#include <swdtflvr.hxx>
+#include <view.hxx>
+#include <edtwin.hxx>
+#include <olmenu.hxx>
+#include <cmdid.h>
+
+class MMTest : public SwModelTestBase
+{
+    public:
+        MMTest() : SwModelTestBase("/sw/qa/extras/mailmerge/data/", "writer8") {}
+};
+
+#define DECLARE_DFLT_MAILMERGE_TEST(TestName, filename, datasource, tablename) \
+    DECLARE_MAILMERGE_TEST(TestName, filename, datasource, tablename, MMTest)
+
+DECLARE_DFLT_MAILMERGE_TEST(testMultiPageAnchoredDraws, "multiple-page-anchored-draws.odt", "4_v01.ods", "Tabelle1")
+{
+    executeMailMerge();
+
+    SwXTextDocument* pTxtDoc = dynamic_cast<SwXTextDocument *>(mxMMComponent.get());
+    CPPUNIT_ASSERT(pTxtDoc);
+    sal_uInt16 nPhysPages = pTxtDoc->GetDocShell()->GetWrtShell()->GetPhyPageNum();
+    CPPUNIT_ASSERT_EQUAL(sal_uInt16(8), nPhysPages);
+
+    uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(mxMMComponent, uno::UNO_QUERY);
+    uno::Reference<container::XIndexAccess> xDraws(xDrawPageSupplier->getDrawPage(), uno::UNO_QUERY);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(8), xDraws->getCount());
+
+    // bitset of all page numbers
+    char nPageSum = 0xFF;
+    uno::Reference<beans::XPropertySet> xPropertySet;
+
+    for (sal_Int32 i = 0; i < xDraws->getCount(); i++)
+    {
+        text::TextContentAnchorType nAnchorType;
+        sal_uInt16 nAnchorPageNo;
+        xPropertySet.set(xDraws->getByIndex(i), uno::UNO_QUERY);
+
+        xPropertySet->getPropertyValue( UNO_NAME_ANCHOR_TYPE ) >>= nAnchorType;
+        CPPUNIT_ASSERT_EQUAL( text::TextContentAnchorType_AT_PAGE, nAnchorType );
+
+        xPropertySet->getPropertyValue( UNO_NAME_ANCHOR_PAGE_NO ) >>= nAnchorPageNo;
+        nPageSum &= !nAnchorPageNo;
+    }
+
+    // are all shapes are on different page numbers?
+    CPPUNIT_ASSERT_EQUAL(char(0), nPageSum);
+}
+
+#endif
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit 5187ce45b93e5e841e541eac98da3fa2110fe632
Author: Jan-Marek Glogowski <glogow at fbihome.de>
Date:   Mon Sep 15 00:48:59 2014 +0200

    MM: add non-UI LoadAndRegisterDataSource function
    
    For the mail merge unit test we need a function to register new
    database sources without any UI interaction. This refactors and
    introduces new versions of LoadAndRegisterDataSource, which gets
    all previously interactive values as arguments.
    
    Change-Id: I1601b4112ddc800a0935950133d386ce349b9087

diff --git a/sw/inc/dbmgr.hxx b/sw/inc/dbmgr.hxx
index 797e64c..b79cda0 100644
--- a/sw/inc/dbmgr.hxx
+++ b/sw/inc/dbmgr.hxx
@@ -73,6 +73,7 @@ class SwDbtoolsClient;
 class SwXMailMerge;
 class SwMailMergeConfigItem;
 class SwCalc;
+class INetURLObject;
 
 enum DBManagerOptions
 {
@@ -217,6 +218,16 @@ public:
     SwDBManager();
     ~SwDBManager();
 
+    enum DBConnURITypes {
+        DBCONN_UNKNOWN = 0,
+        DBCONN_ODB,
+        DBCONN_CALC,
+        DBCONN_DBASE,
+        DBCONN_FLAT,
+        DBCONN_MSJET,
+        DBCONN_MSACE
+    };
+
     /// MailMergeEvent source
     const SwXMailMerge *    GetMailMergeEvtSrc() const  { return pMergeEvtSrc; }
     void SetMailMergeEvtSrc( const SwXMailMerge *pSrc ) { pMergeEvtSrc = pSrc; }
@@ -328,11 +339,35 @@ public:
 
     static ::com::sun::star::uno::Sequence<OUString> GetExistingDatabaseNames();
 
+    static DBConnURITypes GetDBunoURI(const OUString &rURI, ::com::sun::star::uno::Any &aURLAny);
+
     /**
-     Loads a data source from file and registers it. Returns the registered name.
+     Loads a data source from file and registers it.
+
+     This function requires GUI interaction, as it loads the data source from
+     the filename returned by a file picker and additional settings dialog.
+     In case of success it returns the registered name, otherwise an empty string.
      */
     static OUString            LoadAndRegisterDataSource();
 
+    /**
+     Loads a data source from file and registers it.
+
+     In case of success it returns the registered name, otherwise an empty string.
+     Optionally add a prefix to the registered DB name.
+     */
+    static OUString            LoadAndRegisterDataSource(const DBConnURITypes type, const ::com::sun::star::uno::Any &rUnoURI,
+                                                         const ::com::sun::star::uno::Reference < ::com::sun::star::beans::XPropertySet > *pSettings,
+                                                         const OUString &rURI, const OUString *pPrefix = 0, const OUString *pDestDir = 0);
+    /**
+     Loads a data source from file and registers it.
+
+     Convenience function, which calls GetDBunoURI and has just one mandatory parameter.
+     In case of success it returns the registered name, otherwise an empty string.
+     */
+    static OUString            LoadAndRegisterDataSource(const OUString& rURI, const OUString *pPrefix = 0, const OUString *pDestDir = 0,
+                                                         const ::com::sun::star::uno::Reference < ::com::sun::star::beans::XPropertySet > *pSettings = 0);
+
     static SwDbtoolsClient&    GetDbtoolsClient();
     /// has to be called from _FinitUI()
     static void                RemoveDbtoolsClient();
diff --git a/sw/source/uibase/dbui/dbmgr.cxx b/sw/source/uibase/dbui/dbmgr.cxx
index 9103a1a..49a714f 100644
--- a/sw/source/uibase/dbui/dbmgr.cxx
+++ b/sw/source/uibase/dbui/dbmgr.cxx
@@ -2391,74 +2391,113 @@ OUString SwDBManager::LoadAndRegisterDataSource()
 
     xFltMgr->setCurrentFilter( sFilterAll ) ;
     OUString sFind;
-    bool bTextConnection = false;
     if( ERRCODE_NONE == aDlgHelper.Execute() )
     {
-        OUString sURL = xFP->getFiles().getConstArray()[0];
-        //data sources have to be registered depending on their extensions
-        INetURLObject aURL( sURL );
-        OUString sExt( aURL.GetExtension() );
         Any aURLAny;
+        uno::Reference< beans::XPropertySet > aSettings;
+        const OUString aURI( xFP->getFiles().getConstArray()[0] );
+        const DBConnURITypes type = GetDBunoURI( aURI, aURLAny );
+
+        if( DBCONN_FLAT == type )
+        {
+            Reference<XComponentContext> xContext( ::comphelper::getProcessComponentContext() );
+            uno::Reference < sdb::XTextConnectionSettings > xSettingsDlg = sdb::TextConnectionSettings::create(xContext);
+            if( xSettingsDlg->execute() )
+                aSettings.set( uno::Reference < beans::XPropertySet >( xSettingsDlg, uno::UNO_QUERY_THROW ) );
+        }
+        sFind = LoadAndRegisterDataSource( type, aURLAny, DBCONN_FLAT == type ? &aSettings : 0, aURI );
+    }
+    return sFind;
+}
+
+SwDBManager::DBConnURITypes SwDBManager::GetDBunoURI(const OUString &rURI, Any &aURLAny)
+{
+    INetURLObject aURL( rURI );
+    OUString sExt( aURL.GetExtension() );
+    DBConnURITypes type = DBCONN_UNKNOWN;
+
+    if(sExt == "odb")
+    {
+        type = DBCONN_ODB;
+    }
+    else if(sExt.equalsIgnoreAsciiCase("sxc")
+        || sExt.equalsIgnoreAsciiCase("ods")
+            || sExt.equalsIgnoreAsciiCase("xls"))
+    {
+        OUString sDBURL("sdbc:calc:");
+        sDBURL += aURL.GetMainURL(INetURLObject::NO_DECODE);
+        aURLAny <<= sDBURL;
+        type = DBCONN_CALC;
+    }
+    else if(sExt.equalsIgnoreAsciiCase("dbf"))
+    {
+        aURL.removeSegment();
+        aURL.removeFinalSlash();
+        OUString sDBURL("sdbc:dbase:");
+        sDBURL += aURL.GetMainURL(INetURLObject::NO_DECODE);
+        aURLAny <<= sDBURL;
+        type = DBCONN_DBASE;
+    }
+    else if(sExt.equalsIgnoreAsciiCase("csv") || sExt.equalsIgnoreAsciiCase("txt"))
+    {
+        aURL.removeSegment();
+        aURL.removeFinalSlash();
+        OUString sDBURL("sdbc:flat:");
+        //only the 'path' has to be added
+        sDBURL += aURL.GetMainURL(INetURLObject::NO_DECODE);
+        aURLAny <<= sDBURL;
+        type = DBCONN_FLAT;
+    }
+#ifdef WNT
+    else if(sExt.equalsIgnoreAsciiCase("mdb"))
+    {
+        OUString sDBURL("sdbc:ado:access:PROVIDER=Microsoft.Jet.OLEDB.4.0;DATA SOURCE=");
+        sDBURL += aURL.PathToFileName();
+        aURLAny <<= sDBURL;
+        type = DBCONN_MSJET;
+    }
+    else if(sExt.equalsIgnoreAsciiCase("accdb"))
+    {
+        OUString sDBURL("sdbc:ado:PROVIDER=Microsoft.ACE.OLEDB.12.0;DATA SOURCE=");
+        sDBURL += aURL.PathToFileName();
+        aURLAny <<= sDBURL;
+        type = DBCONN_MSACE;
+    }
+#endif
+    return type;
+}
+
+OUString SwDBManager::LoadAndRegisterDataSource(const DBConnURITypes type, const Any &aURLAny, const uno::Reference< beans::XPropertySet > *pSettings,
+                                                const OUString &rURI, const OUString *pPrefix, const OUString *pDestDir)
+{
+        INetURLObject aURL( rURI );
+        OUString sExt( aURL.GetExtension() );
         Any aTableFilterAny;
         Any aSuppressVersionsAny;
         Any aInfoAny;
-        INetURLObject aTempURL(aURL);
         bool bStore = true;
-        if(sExt == "odb")
-        {
+        OUString sFind;
+        Sequence<OUString> aFilters(1);
+
+        switch (type) {
+        case DBCONN_UNKNOWN:
+        case DBCONN_CALC:
+            break;
+        case DBCONN_ODB:
             bStore = false;
-        }
-        else if(sExt.equalsIgnoreAsciiCase("sxc")
-            || sExt.equalsIgnoreAsciiCase("ods")
-                || sExt.equalsIgnoreAsciiCase("xls"))
-        {
-            OUString sDBURL("sdbc:calc:");
-            sDBURL += aTempURL.GetMainURL(INetURLObject::NO_DECODE);
-            aURLAny <<= sDBURL;
-        }
-        else if(sExt.equalsIgnoreAsciiCase("dbf"))
-        {
-            aTempURL.removeSegment();
-            aTempURL.removeFinalSlash();
-            OUString sDBURL("sdbc:dbase:");
-            sDBURL += aTempURL.GetMainURL(INetURLObject::NO_DECODE);
-            aURLAny <<= sDBURL;
-            //set the filter to the file name without extension
-            Sequence<OUString> aFilters(1);
-            aFilters[0] = aURL.getBase();
-            aTableFilterAny <<= aFilters;
-        }
-        else if(sExt.equalsIgnoreAsciiCase("csv") || sExt.equalsIgnoreAsciiCase("txt"))
-        {
-            aTempURL.removeSegment();
-            aTempURL.removeFinalSlash();
-            OUString sDBURL("sdbc:flat:");
-            //only the 'path' has to be added
-            sDBURL += aTempURL.GetMainURL(INetURLObject::NO_DECODE);
-            aURLAny <<= sDBURL;
-
-            bTextConnection = true;
+            break;
+        case DBCONN_FLAT:
+        case DBCONN_DBASE:
             //set the filter to the file name without extension
-            Sequence<OUString> aFilters(1);
             aFilters[0] = aURL.getBase();
             aTableFilterAny <<= aFilters;
-        }
-#ifdef WNT
-        else if(sExt.equalsIgnoreAsciiCase("mdb"))
-        {
-            OUString sDBURL("sdbc:ado:access:PROVIDER=Microsoft.Jet.OLEDB.4.0;DATA SOURCE=");
-            sDBURL += aTempURL.PathToFileName();
-            aURLAny <<= sDBURL;
-            aSuppressVersionsAny <<= makeAny(true);
-        }
-        else if(sExt.equalsIgnoreAsciiCase("accdb"))
-        {
-            OUString sDBURL("sdbc:ado:PROVIDER=Microsoft.ACE.OLEDB.12.0;DATA SOURCE=");
-            sDBURL += aTempURL.PathToFileName();
-            aURLAny <<= sDBURL;
+            break;
+        case DBCONN_MSJET:
+        case DBCONN_MSACE:
             aSuppressVersionsAny <<= makeAny(true);
+            break;
         }
-#endif
+
         try
         {
             Reference<XComponentContext> xContext( ::comphelper::getProcessComponentContext() );
@@ -2470,6 +2509,8 @@ OUString SwDBManager::LoadAndRegisterDataSource()
                                                      RTL_TEXTENCODING_UTF8 );
             sal_Int32 nExtLen = aURL.GetExtension().getLength();
             sNewName = sNewName.replaceAt( sNewName.getLength() - nExtLen - 1, nExtLen + 1, "" );
+            if (pPrefix)
+                sNewName = *pPrefix + sNewName;
 
             //find a unique name if sNewName already exists
             sFind = sNewName;
@@ -2484,7 +2525,7 @@ OUString SwDBManager::LoadAndRegisterDataSource()
             if(!bStore)
             {
                 //odb-file
-                Any aDataSource = xDBContext->getByName(aTempURL.GetMainURL(INetURLObject::NO_DECODE));
+                Any aDataSource = xDBContext->getByName(aURL.GetMainURL(INetURLObject::NO_DECODE));
                 aDataSource >>= xNewInstance;
             }
             else
@@ -2501,19 +2542,13 @@ OUString SwDBManager::LoadAndRegisterDataSource()
                 if(aInfoAny.hasValue())
                     xDataProperties->setPropertyValue("Info", aInfoAny);
 
-                if( bTextConnection )
+                if( DBCONN_FLAT == type && pSettings )
                 {
-                    uno::Reference < sdb::XTextConnectionSettings > xSettingsDlg = sdb::TextConnectionSettings::create(xContext);
-                    if( xSettingsDlg->execute() )
-                    {
                         uno::Any aSettings = xDataProperties->getPropertyValue( "Settings" );
                         uno::Reference < beans::XPropertySet > xDSSettings;
                         aSettings >>= xDSSettings;
-                        ::comphelper::copyProperties(
-                            uno::Reference < beans::XPropertySet >( xSettingsDlg, uno::UNO_QUERY_THROW ),
-                            xDSSettings );
+                        ::comphelper::copyProperties( *pSettings, xDSSettings );
                         xDSSettings->setPropertyValue( "Extension", uno::makeAny( sExt ));
-                    }
                 }
 
                 Reference<XDocumentDataSource> xDS(xNewInstance, UNO_QUERY_THROW);
@@ -2521,21 +2556,28 @@ OUString SwDBManager::LoadAndRegisterDataSource()
                 OUString sOutputExt = ".odb";
                 OUString sTmpName;
                 {
-                    utl::TempFile aTempFile(sNewName, true, &sOutputExt, &sHomePath);
+                    OUString sHomePath(SvtPathOptions().GetWorkPath());
+                    utl::TempFile aTempFile(sNewName, true, &sOutputExt, pDestDir ? pDestDir : &sHomePath);
                     aTempFile.EnableKillingFile(true);
                     sTmpName = aTempFile.GetURL();
                 }
                 xStore->storeAsURL(sTmpName, Sequence< PropertyValue >());
             }
             xDBContext->registerObject( sFind, xNewInstance );
-
         }
         catch(const Exception&)
         {
+            sFind = "";
         }
-    }
     return sFind;
+}
 
+OUString SwDBManager::LoadAndRegisterDataSource(const OUString &rURI, const OUString *pPrefix, const OUString *pDestDir,
+                                                const uno::Reference< beans::XPropertySet > *pSettings)
+{
+    Any aURLAny;
+    DBConnURITypes type = GetDBunoURI( rURI, aURLAny );
+    return LoadAndRegisterDataSource( type, aURLAny, pSettings, rURI, pPrefix, pDestDir );
 }
 
 void SwDBManager::ExecuteFormLetter( SwWrtShell& rSh,
commit 9835bb562cfe3a5d386c24d86176ba7bb5ab26d2
Author: Jan-Marek Glogowski <glogow at fbihome.de>
Date:   Mon Sep 15 00:13:06 2014 +0200

    MM: export the SwDocShell mail merge via UNO
    
    This saves the loading time for large document. Use it if you
    want to present the generated document to the user or write a
    mail merge unit tests.
    
    This includes:
      * renaming "only" to "shell" at multiple occurences
      * dropping the DBMGR_MERGE_SINGLE_FILE special type for the mail
        merge wizard in favour of an additional SwMergeDescriptor
        boolean
      * cleanup and renaming of the internal merge type enums, so these
        actually  match the diffferent merge targets: printer, email,
        file and shell
    
    Change-Id: I33c6773972195193687ba9c3e12b562310d330c1

diff --git a/offapi/com/sun/star/text/MailMergeType.idl b/offapi/com/sun/star/text/MailMergeType.idl
index 4c73532..7099a8d 100644
--- a/offapi/com/sun/star/text/MailMergeType.idl
+++ b/offapi/com/sun/star/text/MailMergeType.idl
@@ -45,6 +45,15 @@ published constants MailMergeType
      */
     const short MAIL = 3;
 
+
+    /** The output is a document shell.
+
+        The successful mail marge returns a XTextDocument based component.
+
+        @since LibreOffice 4.4
+     */
+    const short SHELL = 4;
+
 };
 
 
diff --git a/offapi/type_reference/offapi.idl b/offapi/type_reference/offapi.idl
index fc5b795..fb4b93b 100644
--- a/offapi/type_reference/offapi.idl
+++ b/offapi/type_reference/offapi.idl
@@ -14535,6 +14535,7 @@ module com {
      const short FILE = 2;
      const short MAIL = 3;
      const short PRINTER = 1;
+     const short SHELL = 4;
     };
     published service NumberingLevel {
      [property] short Adjust;
diff --git a/sw/inc/dbmgr.hxx b/sw/inc/dbmgr.hxx
index 61eb740..797e64c 100644
--- a/sw/inc/dbmgr.hxx
+++ b/sw/inc/dbmgr.hxx
@@ -77,11 +77,10 @@ class SwCalc;
 enum DBManagerOptions
 {
     DBMGR_MERGE,             ///< Data records in fields.
-    DBMGR_MERGE_MAILMERGE,   ///< Print mail merge.
-    DBMGR_MERGE_MAILING,     ///< Send mail merge as email.
-    DBMGR_MERGE_MAILFILES,   ///< Save mail merge as files.
-    DBMGR_MERGE_SINGLE_FILE, ///< Save merge as single file.
-    DBMGR_MERGE_ONLY         ///< Create merge doc w/o save/print.
+    DBMGR_MERGE_PRINTER,     ///< Print mail merge.
+    DBMGR_MERGE_EMAIL,       ///< Send mail merge as email.
+    DBMGR_MERGE_FILE,        ///< Save mail merge as files.
+    DBMGR_MERGE_SHELL        ///< Create merge doc and keep the doc shell.
 };
 
 // Administration of (new) logical databases.
@@ -154,6 +153,7 @@ struct SwMergeDescriptor
 
     bool                                            bPrintAsync;
     bool                                            bCreateSingleFile;
+    bool                                            bSubjectIsFilename;
 
     SwMailMergeConfigItem*                              pMailMergeConfigItem;
 
@@ -167,6 +167,7 @@ struct SwMergeDescriptor
         bSendAsAttachment( false ),
         bPrintAsync( false ),
         bCreateSingleFile( false ),
+        bSubjectIsFilename( false ),
         pMailMergeConfigItem(0)
         {}
 
@@ -277,7 +278,7 @@ public:
 
     /// check if a data source is open
     bool            IsDataSourceOpen(const OUString& rDataSource,
-                                    const OUString& rTableOrQuery, bool bMergeOnly);
+                                    const OUString& rTableOrQuery, bool bMergeShell);
 
     /// open the source while fields are updated - for the calculator only!
     bool            OpenDataSource(const OUString& rDataSource, const OUString& rTableOrQuery,
diff --git a/sw/inc/swabstdlg.hxx b/sw/inc/swabstdlg.hxx
index daf8ad6..f554275 100644
--- a/sw/inc/swabstdlg.hxx
+++ b/sw/inc/swabstdlg.hxx
@@ -145,7 +145,7 @@ public:
     virtual const OUString& GetSaveFilter() const = 0;
     virtual const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any > GetSelection() const = 0;
     virtual ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XResultSet> GetResultSet() const = 0;
-    virtual bool IsSaveIndividualDocs() const = 0;
+    virtual bool IsSaveSingleDoc() const = 0;
     virtual bool IsGenerateFromDataBase() const = 0;
     virtual OUString GetColumnName() const = 0;
     virtual OUString GetPath() const = 0;
diff --git a/sw/source/ui/dbui/mailmergewizard.cxx b/sw/source/ui/dbui/mailmergewizard.cxx
index d2ac379..ced4c6e 100644
--- a/sw/source/ui/dbui/mailmergewizard.cxx
+++ b/sw/source/ui/dbui/mailmergewizard.cxx
@@ -277,7 +277,7 @@ void SwMailMergeWizard::CreateTargetDocument()
     aDescriptor[ svx::daCommand ]     <<= m_rConfigItem.GetCurrentDBData().sCommand;
     aDescriptor[ svx::daCommandType ] <<= m_rConfigItem.GetCurrentDBData().nCommandType;
 
-    SwMergeDescriptor aMergeDesc( DBMGR_MERGE_ONLY, GetSwView()->GetWrtShell(),
+    SwMergeDescriptor aMergeDesc( DBMGR_MERGE_SHELL, GetSwView()->GetWrtShell(),
         aDescriptor);
     aMergeDesc.pMailMergeConfigItem = &m_rConfigItem;
     aMergeDesc.bCreateSingleFile = true;
diff --git a/sw/source/ui/dialog/swdlgfact.cxx b/sw/source/ui/dialog/swdlgfact.cxx
index b62e422..3b79a38 100644
--- a/sw/source/ui/dialog/swdlgfact.cxx
+++ b/sw/source/ui/dialog/swdlgfact.cxx
@@ -497,9 +497,9 @@ uno::Reference< sdbc::XResultSet> AbstractMailMergeDlg_Impl::GetResultSet() cons
     return pDlg->GetResultSet();
 }
 
-bool AbstractMailMergeDlg_Impl::IsSaveIndividualDocs() const
+bool AbstractMailMergeDlg_Impl::IsSaveSingleDoc() const
 {
-    return pDlg->IsSaveIndividualDocs();
+    return pDlg->IsSaveSingleDoc();
 }
 
 bool AbstractMailMergeDlg_Impl::IsGenerateFromDataBase() const
diff --git a/sw/source/ui/dialog/swdlgfact.hxx b/sw/source/ui/dialog/swdlgfact.hxx
index 1a037f7..0a402199 100644
--- a/sw/source/ui/dialog/swdlgfact.hxx
+++ b/sw/source/ui/dialog/swdlgfact.hxx
@@ -286,7 +286,7 @@ class AbstractMailMergeDlg_Impl : public AbstractMailMergeDlg
     virtual const OUString& GetSaveFilter() const SAL_OVERRIDE;
     virtual const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any > GetSelection() const SAL_OVERRIDE ;
     virtual ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XResultSet> GetResultSet() const SAL_OVERRIDE;
-    virtual bool IsSaveIndividualDocs() const SAL_OVERRIDE;
+    virtual bool IsSaveSingleDoc() const SAL_OVERRIDE;
     virtual bool IsGenerateFromDataBase() const SAL_OVERRIDE;
     virtual OUString GetColumnName() const SAL_OVERRIDE;
     virtual OUString GetPath() const SAL_OVERRIDE;
diff --git a/sw/source/ui/envelp/mailmrge.cxx b/sw/source/ui/envelp/mailmrge.cxx
index b452f4e3..693beba 100644
--- a/sw/source/ui/envelp/mailmrge.cxx
+++ b/sw/source/ui/envelp/mailmrge.cxx
@@ -139,7 +139,7 @@ SwMailMergeDlg::SwMailMergeDlg(vcl::Window* pParent, SwWrtShell& rShell,
     pImpl           (new SwMailMergeDlg_Impl),
 
     rSh             (rShell),
-    nMergeType      (DBMGR_MERGE_MAILING),
+    nMergeType      (DBMGR_MERGE_EMAIL),
     m_aDialogSize( GetSizePixel() )
 {
     get(m_pBeamerWin, "beamer");
@@ -495,11 +495,10 @@ bool SwMailMergeDlg::ExecQryShell()
     SwDBManager* pMgr = rSh.GetDBManager();
 
     if (m_pPrinterRB->IsChecked())
-        nMergeType = DBMGR_MERGE_MAILMERGE;
+        nMergeType = DBMGR_MERGE_PRINTER;
     else
     {
-        nMergeType = m_pSaveSingleDocRB->IsChecked() ?
-            DBMGR_MERGE_SINGLE_FILE : DBMGR_MERGE_MAILFILES;
+        nMergeType = DBMGR_MERGE_FILE;
         SfxMedium* pMedium = rSh.GetView().GetDocShell()->GetMedium();
         INetURLObject aAbs;
         if( pMedium )
diff --git a/sw/source/uibase/dbui/dbmgr.cxx b/sw/source/uibase/dbui/dbmgr.cxx
index 13bcbcd..9103a1a 100644
--- a/sw/source/uibase/dbui/dbmgr.cxx
+++ b/sw/source/uibase/dbui/dbmgr.cxx
@@ -430,11 +430,10 @@ bool SwDBManager::MergeNew( const SwMergeDescriptor& rMergeDesc )
             bRet = Merge(&rMergeDesc.rSh);
             break;
 
-        case DBMGR_MERGE_MAILMERGE: // printing merge from 'old' merge dialog or from UNO-component
-        case DBMGR_MERGE_MAILING:
-        case DBMGR_MERGE_MAILFILES:
-        case DBMGR_MERGE_SINGLE_FILE:
-        case DBMGR_MERGE_ONLY:
+        case DBMGR_MERGE_PRINTER:
+        case DBMGR_MERGE_EMAIL:
+        case DBMGR_MERGE_FILE:
+        case DBMGR_MERGE_SHELL:
             // save files and send them as e-Mail if required
             bRet = MergeMailFiles(&rMergeDesc.rSh,
                     rMergeDesc);
@@ -875,9 +874,8 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
     //check if the doc is synchronized and contains at least one linked section
     bool bSynchronizedDoc = pSourceShell->IsLabelDoc() && pSourceShell->GetSectionFmtCount() > 1;
     bool bNoError = true;
-    const bool bEMail = rMergeDescriptor.nMergeType == DBMGR_MERGE_MAILING;
-    const bool bAsSingleFile = rMergeDescriptor.nMergeType == DBMGR_MERGE_SINGLE_FILE;
-    const bool bMergeOnly = rMergeDescriptor.nMergeType == DBMGR_MERGE_ONLY;
+    const bool bEMail = rMergeDescriptor.nMergeType == DBMGR_MERGE_EMAIL;
+    const bool bMergeShell = rMergeDescriptor.nMergeType == DBMGR_MERGE_SHELL;
 
     ::rtl::Reference< MailDispatcher >          xMailDispatcher;
     OUString sBodyMimeType;
@@ -936,9 +934,9 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
             OSL_ENSURE(xSourceDocProps.is(), "DocumentProperties is null");
         }
 
-        if( !bMergeOnly && pSourceDocSh->IsModified() )
+        if( !bMergeShell && pSourceDocSh->IsModified() )
             pSfxDispatcher->Execute( pSourceDocSh->HasName() ? SID_SAVEDOC : SID_SAVEASDOC, SFX_CALLMODE_SYNCHRON|SFX_CALLMODE_RECORD);
-        if( bMergeOnly || !pSourceDocSh->IsModified() )
+        if( bMergeShell || !pSourceDocSh->IsModified() )
         {
             const SfxFilter* pStoreToFilter = SwIoSystem::GetFileFilter(
                 pSourceDocSh->GetMedium()->GetURLObject().GetMainURL( INetURLObject::NO_DECODE ), ::aEmptyOUStr );
@@ -982,7 +980,7 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
 
             if (!IsMergeSilent()) {
                 pSourceWindow = &pSourceShell->GetView().GetEditWin();
-                if( bMergeOnly )
+                if( bMergeShell )
                     pProgressDlg = new CreateMonitor( pSourceWindow );
                 else {
                     pProgressDlg = new PrintMonitor( pSourceWindow, PrintMonitor::MONITOR_TYPE_PRINT );
@@ -995,7 +993,7 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
                     Application::Reschedule();
             }
 
-            if(bAsSingleFile || rMergeDescriptor.bCreateSingleFile)
+            if(rMergeDescriptor.bCreateSingleFile)
             {
                 // create a target docshell to put the merged document into
                 xTargetDocShell = new SwDocShell( SFX_CREATE_MODE_STANDARD );
@@ -1003,7 +1001,7 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
                 if (nMaxDumpDocs)
                     lcl_SaveDoc( xTargetDocShell, "MergeDoc" );
                 SfxViewFrame* pTargetFrame = SfxViewFrame::LoadHiddenDocument( *xTargetDocShell, 0 );
-                if (bMergeOnly) {
+                if (bMergeShell && pSourceWindow) {
                     //the created window has to be located at the same position as the source window
                     vcl::Window& rTargetWindow = pTargetFrame->GetFrame().GetWindow();
                     rTargetWindow.SetPosPixel(pSourceWindow->GetPosPixel());
@@ -1052,7 +1050,7 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
 
             sal_Int32 nDocNo = 1;
             sal_Int32 nDocCount = 0;
-            if( !IsMergeSilent() && bMergeOnly &&
+            if( !IsMergeSilent() && bMergeShell &&
                     lcl_getCountFromResultSet( nDocCount, pImpl->pMergeData->xResultSet ) )
                 static_cast<CreateMonitor*>( pProgressDlg )->SetTotalCount( nDocCount );
 
@@ -1079,7 +1077,7 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
                     }
 
                     // create a new temporary file name - only done once in case of bCreateSingleFile
-                    if( 1 == nDocNo || (!rMergeDescriptor.bCreateSingleFile && !bAsSingleFile) )
+                    if( 1 == nDocNo || !rMergeDescriptor.bCreateSingleFile )
                     {
                         INetURLObject aEntry(sPath);
                         OUString sLeading;
@@ -1093,7 +1091,7 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
                         OUString sExt(comphelper::string::stripStart(pStoreToFilter->GetDefaultExtension(), '*'));
                         aTempFile.reset(
                             new utl::TempFile(sLeading, true, &sExt, &sPath));
-                        if( bAsSingleFile )
+                        if( rMergeDescriptor.bSubjectIsFilename )
                             aTempFile->EnableKillingFile();
                     }
 
@@ -1107,7 +1105,7 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
                     {
                         INetURLObject aTempFileURL(aTempFile->GetURL());
                         if (!IsMergeSilent()) {
-                            if( bMergeOnly )
+                            if( bMergeShell )
                                 static_cast<CreateMonitor*>( pProgressDlg )->SetCurrentPosition( nDocNo );
                             else {
                                 PrintMonitor *pPrintMonDlg = static_cast<PrintMonitor*>( pProgressDlg );
@@ -1162,7 +1160,7 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
                             pEvtSrc->LaunchMailMergeEvent( aEvt );
                         }
 
-                        if(rMergeDescriptor.bCreateSingleFile || bAsSingleFile )
+                        if(rMergeDescriptor.bCreateSingleFile)
                         {
                             OSL_ENSURE( pTargetShell, "no target shell available!" );
                             // copy created file into the target document
@@ -1206,7 +1204,7 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
                             pTargetShell->CalcLayout();
                             if ( (nMaxDumpDocs < 0) || (nDocNo <= nMaxDumpDocs) )
                                 lcl_SaveDoc( xTargetDocShell, "MergeDoc" );
-                            if (bMergeOnly)
+                            if (bMergeShell)
                             {
                                 SwDocMergeInfo aMergeInfo;
                                 aMergeInfo.nStartPageInTarget = nStartPage;
@@ -1332,7 +1330,7 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
 
                 // Freeze the layouts of the target document after the first inserted
                 // sub-document, to get the correct PageDesc.
-                if(!bFreezedLayouts && (rMergeDescriptor.bCreateSingleFile || bAsSingleFile))
+                if(!bFreezedLayouts && (rMergeDescriptor.bCreateSingleFile))
                 {
                     std::set<SwRootFrm*> aAllLayouts = pTargetShell->GetDoc()->GetAllLayouts();
                     std::for_each( aAllLayouts.begin(), aAllLayouts.end(),
@@ -1346,7 +1344,7 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
                 Application::Reschedule();
 
             // Unfreeze target document layouts and correct all PageDescs.
-            if(rMergeDescriptor.bCreateSingleFile || bAsSingleFile)
+            if(rMergeDescriptor.bCreateSingleFile)
             {
                 std::set<SwRootFrm*> aAllLayouts = pTargetShell->GetDoc()->GetAllLayouts();
                 std::for_each( aAllLayouts.begin(), aAllLayouts.end(),
@@ -1357,17 +1355,16 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
             DELETEZ( pProgressDlg );
 
             // save the single output document
-            if (bMergeOnly)
+            if (bMergeShell)
             {
                 rMergeDescriptor.pMailMergeConfigItem->SetTargetView( pTargetView );
             }
-            else if(rMergeDescriptor.bCreateSingleFile || bAsSingleFile)
+            else if(rMergeDescriptor.bCreateSingleFile)
             {
-                if( rMergeDescriptor.nMergeType != DBMGR_MERGE_MAILMERGE )
+                if( rMergeDescriptor.nMergeType != DBMGR_MERGE_PRINTER )
                 {
                     OSL_ENSURE( aTempFile.get(), "Temporary file not available" );
-                    OUString sSub(sSubject);
-                    INetURLObject aTempFileURL(bAsSingleFile ? sSub : aTempFile->GetURL());
+                    INetURLObject aTempFileURL( rMergeDescriptor.bSubjectIsFilename ? sSubject : aTempFile->GetURL());
                     SfxMedium* pDstMed = new SfxMedium(
                         aTempFileURL.GetMainURL( INetURLObject::NO_DECODE ),
                         STREAM_STD_READWRITE );
@@ -1432,7 +1429,7 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
                 }
 
                 // Leave docshell available for caller (e.g. MM wizard)
-                if (!bMergeOnly)
+                if (!bMergeShell)
                     xTargetDocShell->DoClose();
             }
 
@@ -1829,7 +1826,7 @@ OUString SwDBManager::GetDBField(uno::Reference<XPropertySet> xColumnProps,
 
 // checks if a desired data source table or query is open
 bool    SwDBManager::IsDataSourceOpen(const OUString& rDataSource,
-                                  const OUString& rTableOrQuery, bool bMergeOnly)
+                                  const OUString& rTableOrQuery, bool bMergeShell)
 {
     if(pImpl->pMergeData)
     {
@@ -1840,7 +1837,7 @@ bool    SwDBManager::IsDataSourceOpen(const OUString& rDataSource,
                     &&
                     pImpl->pMergeData->xResultSet.is();
     }
-    else if(!bMergeOnly)
+    else if(!bMergeShell)
     {
         SwDBData aData;
         aData.sDataSource = rDataSource;
@@ -2642,7 +2639,8 @@ void SwDBManager::ExecuteFormLetter( SwWrtShell& rSh,
 
                     SwMergeDescriptor aMergeDesc( pImpl->pMergeDialog->GetMergeType(), pView->GetWrtShell(), aDescriptor );
                     aMergeDesc.sSaveToFilter = pImpl->pMergeDialog->GetSaveFilter();
-                    aMergeDesc.bCreateSingleFile = !pImpl->pMergeDialog->IsSaveIndividualDocs();
+                    aMergeDesc.bCreateSingleFile = pImpl->pMergeDialog->IsSaveSingleDoc();
+                    aMergeDesc.bSubjectIsFilename = aMergeDesc.bCreateSingleFile;
                     if( !aMergeDesc.bCreateSingleFile && pImpl->pMergeDialog->IsGenerateFromDataBase() )
                     {
                         aMergeDesc.sAddressFromColumn = pImpl->pMergeDialog->GetColumnName();
diff --git a/sw/source/uibase/inc/mailmrge.hxx b/sw/source/uibase/inc/mailmrge.hxx
index 143e06b..f3d67ee 100644
--- a/sw/source/uibase/inc/mailmrge.hxx
+++ b/sw/source/uibase/inc/mailmrge.hxx
@@ -115,8 +115,8 @@ class SwMailMergeDlg : public SvxStandardDialog
     bool            ExecQryShell();
 
 public:
-     SwMailMergeDlg(vcl::Window* pParent, SwWrtShell& rSh,
-         const OUString& rSourceName,
+    SwMailMergeDlg(vcl::Window* pParent, SwWrtShell& rSh,
+        const OUString& rSourceName,
         const OUString& rTblName,
         sal_Int32 nCommandType,
         const ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XConnection>& xConnection,
@@ -125,7 +125,7 @@ public:
 
     inline DBManagerOptions GetMergeType() { return nMergeType; }
 
-    bool IsSaveIndividualDocs() const { return m_pSaveIndividualRB->IsChecked(); }
+    bool IsSaveSingleDoc() const { return m_pSaveSingleDocRB->IsChecked(); }
     bool IsGenerateFromDataBase() const { return m_pGenerateFromDataBaseCB->IsChecked(); }
     OUString GetColumnName() const { return m_pColumnLB->GetSelectEntry();}
     OUString GetPath() const { return m_pPathED->GetText();}
diff --git a/sw/source/uibase/uno/unomailmerge.cxx b/sw/source/uibase/uno/unomailmerge.cxx
index 9787a01..f54a9df 100644
--- a/sw/source/uibase/uno/unomailmerge.cxx
+++ b/sw/source/uibase/uno/unomailmerge.cxx
@@ -661,9 +661,10 @@ uno::Any SAL_CALL SwXMailMerge::execute(
     DBManagerOptions nMergeType;
     switch (nCurOutputType)
     {
-        case MailMergeType::PRINTER : nMergeType = DBMGR_MERGE_MAILMERGE; break;
-        case MailMergeType::FILE    : nMergeType = DBMGR_MERGE_MAILFILES; break;
-        case MailMergeType::MAIL    : nMergeType = DBMGR_MERGE_MAILING; break;
+        case MailMergeType::PRINTER : nMergeType = DBMGR_MERGE_PRINTER; break;
+        case MailMergeType::FILE    : nMergeType = DBMGR_MERGE_FILE; break;
+        case MailMergeType::MAIL    : nMergeType = DBMGR_MERGE_EMAIL; break;
+        case MailMergeType::SHELL   : nMergeType = DBMGR_MERGE_SHELL; break;
         default:
             throw IllegalArgumentException("Invalid value of property: OutputType", static_cast < cppu::OWeakObject * > ( this ), 0 );
     }
@@ -678,87 +679,98 @@ uno::Any SAL_CALL SwXMailMerge::execute(
 
     boost::scoped_ptr< SwMailMergeConfigItem > pMMConfigItem;
     uno::Reference< mail::XMailService > xInService;
-    if (MailMergeType::PRINTER == nCurOutputType)
+    switch (nCurOutputType)
     {
-        IDocumentDeviceAccess* pIDDA = rSh.getIDocumentDeviceAccess();
-        SwPrintData aPrtData( pIDDA->getPrintData() );
-        aPrtData.SetPrintSingleJobs( bCurSinglePrintJobs );
-        pIDDA->setPrintData( aPrtData );
-        // #i25686# printing should not be done asynchronously to prevent dangling offices
-        // when mail merge is called as command line macro
-        aMergeDesc.bPrintAsync = false;
-        aMergeDesc.aPrintOptions = aPrintSettings;
+    case MailMergeType::PRINTER:
+        {
+            IDocumentDeviceAccess* pIDDA = rSh.getIDocumentDeviceAccess();
+            SwPrintData aPrtData( pIDDA->getPrintData() );
+            aPrtData.SetPrintSingleJobs( bCurSinglePrintJobs );
+            pIDDA->setPrintData( aPrtData );
+            // #i25686# printing should not be done asynchronously to prevent dangling offices
+            // when mail merge is called as command line macro
+            aMergeDesc.bPrintAsync = false;
+            aMergeDesc.aPrintOptions = aPrintSettings;
+            aMergeDesc.bCreateSingleFile = true;
+        }
+        break;
+    case MailMergeType::SHELL:
         aMergeDesc.bCreateSingleFile = true;
-    }
-    else /* FILE and MAIL*/
-    {
-        INetURLObject aURLObj;
-        aURLObj.SetSmartProtocol( INET_PROT_FILE );
-
-        if (!aCurDocumentURL.isEmpty())
+        pMMConfigItem.reset(new SwMailMergeConfigItem);
+        aMergeDesc.pMailMergeConfigItem = pMMConfigItem.get();
+        break;
+    case MailMergeType::FILE:
+    case MailMergeType::MAIL:
         {
-            // if OutputURL or FileNamePrefix are missing get
-            // them from DocumentURL
-            aURLObj.SetSmartURL( aCurDocumentURL );
-            if (aCurFileNamePrefix.isEmpty())
-                aCurFileNamePrefix = aURLObj.GetBase(); // filename without extension
-            if (aCurOutputURL.isEmpty())
+            INetURLObject aURLObj;
+            aURLObj.SetSmartProtocol( INET_PROT_FILE );
+
+            if (!aCurDocumentURL.isEmpty())
+            {
+                // if OutputURL or FileNamePrefix are missing get
+                // them from DocumentURL
+                aURLObj.SetSmartURL( aCurDocumentURL );
+                if (aCurFileNamePrefix.isEmpty())
+                    aCurFileNamePrefix = aURLObj.GetBase(); // filename without extension
+                if (aCurOutputURL.isEmpty())
+                {
+                    aURLObj.removeSegment();
+                    aCurOutputURL = aURLObj.GetMainURL( INetURLObject::DECODE_TO_IURI );
+                }
+            }
+            else    // default empty document without URL
             {
-                aURLObj.removeSegment();
-                aCurOutputURL = aURLObj.GetMainURL( INetURLObject::DECODE_TO_IURI );
+                if (aCurOutputURL.isEmpty())
+                    throw RuntimeException("OutputURL is not set and can not be obtained.", static_cast < cppu::OWeakObject * > ( this ) );
             }
-        }
-        else    // default empty document without URL
-        {
-            if (aCurOutputURL.isEmpty())
-                throw RuntimeException("OutputURL is not set and can not be obtained.", static_cast < cppu::OWeakObject * > ( this ) );
-        }
 
-        aURLObj.SetSmartURL( aCurOutputURL );
-        OUString aPath = aURLObj.GetMainURL( INetURLObject::DECODE_TO_IURI );
+            aURLObj.SetSmartURL( aCurOutputURL );
+            OUString aPath = aURLObj.GetMainURL( INetURLObject::DECODE_TO_IURI );
 
-        const OUString aDelim( "/" );
-        if (!aPath.isEmpty() && !aPath.endsWith(aDelim))
-            aPath += aDelim;
-        if (bCurFileNameFromColumn)
-            pMgr->SetEMailColumn( aCurFileNamePrefix );
-        else
-        {
-            aPath += aCurFileNamePrefix;
-            pMgr->SetEMailColumn( OUString() );
-        }
-        pMgr->SetSubject( aPath );
-        if(MailMergeType::FILE == nCurOutputType)
-        {
-            aMergeDesc.sSaveToFilter = sSaveFilter;
-            aMergeDesc.sSaveToFilterOptions = sSaveFilterOptions;
-            aMergeDesc.aSaveToFilterData = aSaveFilterData;
-            aMergeDesc.bCreateSingleFile = bSaveAsSingleFile;
-        }
-        else
-        {
-            pMgr->SetEMailColumn( sAddressFromColumn );
-            if(sAddressFromColumn.isEmpty())
-                throw RuntimeException("Mail address column not set.", static_cast < cppu::OWeakObject * > ( this ) );
-            aMergeDesc.sSaveToFilter     = sAttachmentFilter;
-            aMergeDesc.sSubject          = sSubject;
-            aMergeDesc.sMailBody         = sMailBody;
-            aMergeDesc.sAttachmentName   = sAttachmentName;
-            aMergeDesc.aCopiesTo         = aCopiesTo;
-            aMergeDesc.aBlindCopiesTo    = aBlindCopiesTo;
-            aMergeDesc.bSendAsHTML       = bSendAsHTML;
-            aMergeDesc.bSendAsAttachment = bSendAsAttachment;
-
-            aMergeDesc.bCreateSingleFile = false;
-            pMMConfigItem.reset(new SwMailMergeConfigItem);
-            aMergeDesc.pMailMergeConfigItem = pMMConfigItem.get();
-            aMergeDesc.xSmtpServer = SwMailMergeHelper::ConnectToSmtpServer(
-                    *pMMConfigItem,
-                    xInService,
-                    sInServerPassword, sOutServerPassword );
-            if( !aMergeDesc.xSmtpServer.is() || !aMergeDesc.xSmtpServer->isConnected())
-                throw RuntimeException("Failed to connect to mail server.", static_cast < cppu::OWeakObject * > ( this ) );
+            const OUString aDelim( "/" );
+            if (!aPath.isEmpty() && !aPath.endsWith(aDelim))
+                aPath += aDelim;
+            if (bCurFileNameFromColumn)
+                pMgr->SetEMailColumn( aCurFileNamePrefix );
+            else
+            {
+                aPath += aCurFileNamePrefix;
+                pMgr->SetEMailColumn( OUString() );
+            }
+            pMgr->SetSubject( aPath );
+            if(MailMergeType::FILE == nCurOutputType)
+            {
+                aMergeDesc.sSaveToFilter = sSaveFilter;
+                aMergeDesc.sSaveToFilterOptions = sSaveFilterOptions;
+                aMergeDesc.aSaveToFilterData = aSaveFilterData;
+                aMergeDesc.bCreateSingleFile = bSaveAsSingleFile;
+            }
+            else
+            {
+                pMgr->SetEMailColumn( sAddressFromColumn );
+                if(sAddressFromColumn.isEmpty())
+                    throw RuntimeException("Mail address column not set.", static_cast < cppu::OWeakObject * > ( this ) );
+                aMergeDesc.sSaveToFilter     = sAttachmentFilter;
+                aMergeDesc.sSubject          = sSubject;
+                aMergeDesc.sMailBody         = sMailBody;
+                aMergeDesc.sAttachmentName   = sAttachmentName;
+                aMergeDesc.aCopiesTo         = aCopiesTo;
+                aMergeDesc.aBlindCopiesTo    = aBlindCopiesTo;
+                aMergeDesc.bSendAsHTML       = bSendAsHTML;
+                aMergeDesc.bSendAsAttachment = bSendAsAttachment;
+
+                aMergeDesc.bCreateSingleFile = false;
+                pMMConfigItem.reset(new SwMailMergeConfigItem);
+                aMergeDesc.pMailMergeConfigItem = pMMConfigItem.get();
+                aMergeDesc.xSmtpServer = SwMailMergeHelper::ConnectToSmtpServer(
+                        *pMMConfigItem,
+                        xInService,
+                        sInServerPassword, sOutServerPassword );
+                if( !aMergeDesc.xSmtpServer.is() || !aMergeDesc.xSmtpServer->isConnected())
+                    throw RuntimeException("Failed to connect to mail server.", static_cast < cppu::OWeakObject * > ( this ) );
+            }
         }
+        break;
     }
 
     // save document with temporary filename
@@ -812,7 +824,13 @@ uno::Any SAL_CALL SwXMailMerge::execute(
     if(aMergeDesc.xSmtpServer.is() && aMergeDesc.xSmtpServer->isConnected())
         aMergeDesc.xSmtpServer->disconnect();
 
-    return makeAny( sal_True );
+    if (DBMGR_MERGE_SHELL == nMergeType)
+    {
+        SwXTextDocument *xTextDoc = new SwXTextDocument( aMergeDesc.pMailMergeConfigItem->GetTargetView()->GetDocShell() );
+        return makeAny( Reference< XComponent >( xTextDoc->queryInterface( XComponent::static_type() ), css::uno::UNO_QUERY) );
+    }
+    else
+        return makeAny( sal_True );
 }
 
 void SAL_CALL SwXMailMerge::cancel() throw (com::sun::star::uno::RuntimeException, std::exception)
commit 0a5cd87e591d7f87bfab92716079af719259f143
Author: Jan-Marek Glogowski <glogow at fbihome.de>
Date:   Mon Sep 15 00:00:03 2014 +0200

    MM: dump debug documents based on environment var
    
    Introduce SW_DEBUG_MAILMERGE_DOCS=<n> to dump n mail merge debug
    documents (partly merged and working copies).
    
    This will speed up mail merge unit tests and allows dumping of
    an arbitrary amount of intermediate mail merge documents.
    
    Change-Id: Idb9fc19f99ccafe5574897bd1e687d439c52ebe5

diff --git a/sw/source/uibase/dbui/dbmgr.cxx b/sw/source/uibase/dbui/dbmgr.cxx
index d25743c..13bcbcd 100644
--- a/sw/source/uibase/dbui/dbmgr.cxx
+++ b/sw/source/uibase/dbui/dbmgr.cxx
@@ -848,17 +848,13 @@ static void lcl_CopyDocumentPorperties(
     pTargetDoc->ReplaceUserDefinedDocumentProperties( xSourceDocProps );
 }
 
-#ifdef DBG_UTIL
-
-#define MAX_DOC_DUMP 3
-
 static void lcl_SaveDoc( SfxObjectShell *xTargetDocShell,
                          const char *name, int no = 0 )
 {
     boost::scoped_ptr< utl::TempFile > aTempFile;
     OUString sExt( ".odt" );
     OUString basename = OUString::createFromAscii( name );
-    if (no > 0 )
+    if (no > 0)
         basename += OUString::number(no) + "-";
     aTempFile.reset( new utl::TempFile( basename, true, &sExt ) );
     OSL_ENSURE( aTempFile.get(), "Temporary file not available" );
@@ -872,7 +868,6 @@ static void lcl_SaveDoc( SfxObjectShell *xTargetDocShell,
         SAL_INFO( "sw.mailmerge", "Saved doc as: " << aTempFile->GetURL() );
     delete pDstMed;
 }
-#endif
 
 bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
                                  const SwMergeDescriptor& rMergeDescriptor)
@@ -888,6 +883,17 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
     OUString sBodyMimeType;
     rtl_TextEncoding eEncoding = ::osl_getThreadTextEncoding();
 
+    static const char *sMaxDumpDocs = 0;
+    static sal_Int32 nMaxDumpDocs = 0;
+    if (!sMaxDumpDocs)
+    {
+        sMaxDumpDocs = getenv("SW_DEBUG_MAILMERGE_DOCS");
+        if (!sMaxDumpDocs)
+            sMaxDumpDocs = "";
+        else
+            nMaxDumpDocs = rtl_ustr_toInt32(reinterpret_cast<const sal_Unicode*>( sMaxDumpDocs ), 10);
+    }
+
     if(bEMail)
     {
         xMailDispatcher.set( new MailDispatcher(rMergeDescriptor.xSmtpServer));
@@ -994,9 +1000,8 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
                 // create a target docshell to put the merged document into
                 xTargetDocShell = new SwDocShell( SFX_CREATE_MODE_STANDARD );
                 xTargetDocShell->DoInitNew( 0 );
-#ifdef DBG_UTIL
-                lcl_SaveDoc( xTargetDocShell, "MergeDoc" );
-#endif
+                if (nMaxDumpDocs)
+                    lcl_SaveDoc( xTargetDocShell, "MergeDoc" );
                 SfxViewFrame* pTargetFrame = SfxViewFrame::LoadHiddenDocument( *xTargetDocShell, 0 );
                 if (bMergeOnly) {
                     //the created window has to be located at the same position as the source window
@@ -1045,7 +1050,7 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
                 pViewFrm = SfxViewFrame::GetNext(*pViewFrm, pSourceDocSh);
             }
 
-            sal_uLong nDocNo = 1;
+            sal_Int32 nDocNo = 1;
             sal_Int32 nDocCount = 0;
             if( !IsMergeSilent() && bMergeOnly &&
                     lcl_getCountFromResultSet( nDocCount, pImpl->pMergeData->xResultSet ) )
@@ -1131,10 +1136,8 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
 
                         SwDoc* pWorkDoc = rWorkShell.GetDoc();
                         lcl_CopyDocumentPorperties( xSourceDocProps, xWorkDocSh, pWorkDoc );
-#ifdef DBG_UTIL
-                        if ( nDocNo <= MAX_DOC_DUMP )
+                        if ( (nMaxDumpDocs < 0) || (nDocNo <= nMaxDumpDocs) )
                             lcl_SaveDoc( xWorkDocSh, "WorkDoc", nDocNo );
-#endif
                         SwDBManager* pOldDBManager = pWorkDoc->GetDBManager();
                         pWorkDoc->SetDBManager( this );
                         pWorkDoc->getIDocumentLinksAdministration().EmbedAllLinks();
@@ -1194,19 +1197,15 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
                                 pTargetPageDesc = pTargetShell->FindPageDescByName( sModifiedStartingPageDesc );
 
                             sal_uInt16 nStartPage = pTargetShell->GetPageCnt();
-#ifdef DBG_UTIL
-                            if ( nDocNo <= MAX_DOC_DUMP )
+                            if ( (nMaxDumpDocs < 0) || (nDocNo <= nMaxDumpDocs) )
                                 lcl_SaveDoc( xWorkDocSh, "WorkDoc", nDocNo );
-#endif
                             pTargetDoc->AppendDoc(*rWorkShell.GetDoc(),
                                 nStartingPageNo, pTargetPageDesc, nDocNo == 1);
 
                             // #i72820# calculate layout to be able to find the correct page index
                             pTargetShell->CalcLayout();
-#ifdef DBG_UTIL
-                            if ( nDocNo <= MAX_DOC_DUMP )
+                            if ( (nMaxDumpDocs < 0) || (nDocNo <= nMaxDumpDocs) )
                                 lcl_SaveDoc( xTargetDocShell, "MergeDoc" );
-#endif
                             if (bMergeOnly)
                             {
                                 SwDocMergeInfo aMergeInfo;


More information about the Libreoffice-commits mailing list