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 <glo...@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 <glo...@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 <glo...@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 <glo...@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 <glo...@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; _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits