[Libreoffice-commits] core.git: 6 commits - config_host/config_cups.h.in configure.ac include/sfx2 include/vcl sfx2/source sw/source vcl/inc vcl/source vcl/unx

Miklos Vajna vmiklos at collabora.co.uk
Wed Mar 11 08:22:50 PDT 2015


 config_host/config_cups.h.in                   |    6 
 configure.ac                                   |    3 
 include/sfx2/viewsh.hxx                        |    5 
 include/vcl/jobdata.hxx                        |    6 
 include/vcl/print.hxx                          |    9 +
 include/vcl/printerinfomanager.hxx             |   10 +
 sfx2/source/view/viewprn.cxx                   |   15 ++
 sw/source/uibase/dbui/dbmgr.cxx                |  160 ++++++++++++++++++++-----
 sw/source/uibase/inc/view.hxx                  |   11 -
 sw/source/uibase/uno/unomailmerge.cxx          |    2 
 vcl/inc/cupsmgr.hxx                            |   24 +++
 vcl/source/gdi/print3.cxx                      |   73 ++++++-----
 vcl/unx/generic/printer/cupsmgr.cxx            |  101 +++++++++++++--
 vcl/unx/generic/printer/jobdata.cxx            |   18 ++
 vcl/unx/generic/printer/printerinfomanager.cxx |   15 ++
 15 files changed, 373 insertions(+), 85 deletions(-)

New commits:
commit d5c93cccaebf92b7f99e174552a7c84a5c652690
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Wed Mar 11 16:03:25 2015 +0100

    SwDBManager::MergeMailFiles: merge two bCreateSingleFile blocks
    
    Change-Id: Ia4290a8bfafc88c8e8e7601d62781c0da250824e

diff --git a/sw/source/uibase/dbui/dbmgr.cxx b/sw/source/uibase/dbui/dbmgr.cxx
index b01e2b2..85f7fa8 100644
--- a/sw/source/uibase/dbui/dbmgr.cxx
+++ b/sw/source/uibase/dbui/dbmgr.cxx
@@ -1141,9 +1141,6 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
                         rWorkShell.SwViewShell::UpdateFlds();
                         SfxGetpApp()->NotifyEvent(SfxEventHint(SW_EVENT_FIELD_MERGE_FINISHED, SwDocShell::GetEventName(STR_SW_EVENT_FIELD_MERGE_FINISHED), xWorkDocSh));
 
-                        if( bCreateSingleFile )
-                            pWorkDoc->RemoveInvisibleContent();
-
                         // launch MailMergeEvent if required
                         const SwXMailMerge *pEvtSrc = GetMailMergeEvtSrc();
                         if(pEvtSrc)
@@ -1155,6 +1152,8 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
 
                         if(bCreateSingleFile)
                         {
+                            pWorkDoc->RemoveInvisibleContent();
+
                             OSL_ENSURE( pTargetShell, "no target shell available!" );
                             // copy created file into the target document
                             rWorkShell.ConvertFieldsToText();
commit 138d29aa09417eba4d15ade4c9f4dab2620b6326
Author: Luboš Luňák <l.lunak at collabora.com>
Date:   Thu Feb 26 15:56:24 2015 +0100

    support fast MM printing in non-single-file mode only for CUPS
    
    As said in the comment, the non-single-file mode could create way too many print
    jobs, so enable this only for the CUPS backend, which has been modified
    to send them as a single batch.
    
    Conflicts:
    	configure.ac
    	include/vcl/printerinfomanager.hxx
    	sw/source/uibase/dbui/dbmgr.cxx
    	vcl/inc/cupsmgr.hxx
    	vcl/unx/generic/printer/cupsmgr.cxx
    	vcl/unx/generic/printer/printerinfomanager.cxx
    
    Change-Id: I4c02ca0e8b91323b1d02f004c7b4813433064a11

diff --git a/config_host/config_cups.h.in b/config_host/config_cups.h.in
new file mode 100644
index 0000000..6794703
--- /dev/null
+++ b/config_host/config_cups.h.in
@@ -0,0 +1,6 @@
+#ifndef CONFIG_CUPS_H
+#define CONFIG_CUPS_H
+
+#define ENABLE_CUPS 0
+
+#endif
diff --git a/configure.ac b/configure.ac
index 9131d9b..e8d4fe8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -4633,7 +4633,7 @@ if test "$test_cups" = "yes"; then
     if test "$ac_cv_lib_cups_cupsPrintFiles" != "yes" -o "$ac_cv_header_cups_cups_h" != "yes"; then
         AC_MSG_ERROR([Could not find CUPS. Install libcups2-dev or cups-devel.])
     fi
-
+    AC_DEFINE(ENABLE_CUPS)
 else
     AC_MSG_RESULT([no])
 fi
@@ -12900,6 +12900,7 @@ AC_CONFIG_FILES([config_host.mk
 AC_CONFIG_HEADERS([config_host/config_buildid.h])
 AC_CONFIG_HEADERS([config_host/config_clang.h])
 AC_CONFIG_HEADERS([config_host/config_eot.h])
+AC_CONFIG_HEADERS([config_host/config_cups.h])
 AC_CONFIG_HEADERS([config_host/config_features.h])
 AC_CONFIG_HEADERS([config_host/config_folders.h])
 AC_CONFIG_HEADERS([config_host/config_gcc.h])
diff --git a/include/vcl/jobdata.hxx b/include/vcl/jobdata.hxx
index 8cffdd1..c173863 100644
--- a/include/vcl/jobdata.hxx
+++ b/include/vcl/jobdata.hxx
@@ -79,6 +79,12 @@ struct VCL_DLLPUBLIC JobData
     static bool constructFromStreamBuffer( void* pData, int bytes, JobData& rJobData );
 };
 
+bool operator==(const psp::JobData& rLeft, const psp::JobData& rRight);
+inline bool operator!=(const psp::JobData& rLeft, const psp::JobData& rRight)
+{
+    return !( rLeft == rRight );
+}
+
 } // namespace
 
 
diff --git a/include/vcl/printerinfomanager.hxx b/include/vcl/printerinfomanager.hxx
index 97e68d1..ec5c587 100644
--- a/include/vcl/printerinfomanager.hxx
+++ b/include/vcl/printerinfomanager.hxx
@@ -196,6 +196,16 @@ public:
     // check whether a printer's feature string contains a subfeature
     bool checkFeatureToken( const OUString& rPrinterName, const char* pToken ) const;
 
+    // Starts printing in a batch mode, in which all printing will be done together instead of separate jobs.
+    // If the implementation supports it, calls to endSpool() will only delay the printing until flushBatchPrint()
+    // is called to print all delayed jobs.
+    // Returns false if failed or not supported (in which case endSpool() will print normally).
+    virtual bool startBatchPrint();
+    // Actually spools all delayed print jobs, if enabled, and disables batch mode.
+    virtual bool flushBatchPrint();
+    // Returns true batch printing is supported at all.
+    virtual bool supportsBatchPrint() const;
+
     virtual ~PrinterInfoManager();
 };
 
diff --git a/sw/source/uibase/dbui/dbmgr.cxx b/sw/source/uibase/dbui/dbmgr.cxx
index af65b33..b01e2b2 100644
--- a/sw/source/uibase/dbui/dbmgr.cxx
+++ b/sw/source/uibase/dbui/dbmgr.cxx
@@ -135,6 +135,9 @@
 #include <dbfld.hxx>
 
 #include <boost/scoped_ptr.hpp>
+#include <config_cups.h>
+#include <vcl/printerinfomanager.hxx>
+
 
 using namespace ::osl;
 using namespace ::svx;
@@ -820,6 +823,27 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
     bool bNoError = true;
     const bool bEMail = rMergeDescriptor.nMergeType == DBMGR_MERGE_EMAIL;
     const bool bMergeShell = rMergeDescriptor.nMergeType == DBMGR_MERGE_SHELL;
+    bool bCreateSingleFile = rMergeDescriptor.bCreateSingleFile;
+
+    if( rMergeDescriptor.nMergeType == DBMGR_MERGE_PRINTER )
+    {
+        // It is possible to do MM printing in both modes for the same result, but the singlefile mode
+        // is slower because of all the temporary document copies and merging them together
+        // into the single file, while the other mode simply updates fields and prints for every record.
+        // However, this would cause one print job for every record, and e.g. CUPS refuses new jobs
+        // if it has many jobs enqueued (500 by default), and with the current printing framework
+        // (which uses a pull model) it's rather complicated to create a single print job
+        // in steps.
+        // To handle this, CUPS backend has been changed to cache all the documents to print
+        // and send them to CUPS only as one job at the very end. Therefore, with CUPS, it's ok
+        // to use the faster mode. As I have no idea about other platforms, keep them using
+        // the slower singlefile mode (or feel free to check them, or rewrite the printing code).
+#if ENABLE_CUPS
+        bCreateSingleFile = !psp::PrinterInfoManager::get().supportsBatchPrint();
+#else
+        bCreateSingleFile = true;
+#endif
+    }
 
     ::rtl::Reference< MailDispatcher >          xMailDispatcher;
     OUString sBodyMimeType;
@@ -937,7 +961,7 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
                     Application::Reschedule();
             }
 
-            if(rMergeDescriptor.bCreateSingleFile)
+            if(bCreateSingleFile)
             {
                 // create a target docshell to put the merged document into
                 xTargetDocShell = new SwDocShell( SFX_CREATE_MODE_STANDARD );
@@ -1036,7 +1060,7 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
                     }
 
                     // create a new temporary file name - only done once in case of bCreateSingleFile
-                    if( createTempFile && ( 1 == nDocNo || !rMergeDescriptor.bCreateSingleFile ))
+                    if( createTempFile && ( 1 == nDocNo || !bCreateSingleFile ))
                     {
                         INetURLObject aEntry(sPath);
                         OUString sLeading;
@@ -1086,7 +1110,7 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
                         // Create a copy of the source document and work with that one instead of the source.
                         // If we're not in the single file mode (which requires modifying the document for the merging),
                         // it is enough to do this just once.
-                        if( 1 == nDocNo || rMergeDescriptor.bCreateSingleFile )
+                        if( 1 == nDocNo || bCreateSingleFile )
                         {
                             assert( !xWorkDocSh.Is());
                             // copy the source document
@@ -1117,7 +1141,7 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
                         rWorkShell.SwViewShell::UpdateFlds();
                         SfxGetpApp()->NotifyEvent(SfxEventHint(SW_EVENT_FIELD_MERGE_FINISHED, SwDocShell::GetEventName(STR_SW_EVENT_FIELD_MERGE_FINISHED), xWorkDocSh));
 
-                        if( rMergeDescriptor.bCreateSingleFile )
+                        if( bCreateSingleFile )
                             pWorkDoc->RemoveInvisibleContent();
 
                         // launch MailMergeEvent if required
@@ -1129,7 +1153,7 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
                             pEvtSrc->LaunchMailMergeEvent( aEvt );
                         }
 
-                        if(rMergeDescriptor.bCreateSingleFile)
+                        if(bCreateSingleFile)
                         {
                             OSL_ENSURE( pTargetShell, "no target shell available!" );
                             // copy created file into the target document
@@ -1162,6 +1186,7 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
                             }
                         else if( rMergeDescriptor.nMergeType == DBMGR_MERGE_PRINTER )
                         {
+                            assert(!bCreateSingleFile);
                             if( 1 == nDocNo ) // set up printing only once at the beginning
                             {
                                 // printing should be done synchronously otherwise the document
@@ -1191,6 +1216,9 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
                                 SfxPrinter* pDocPrt = pWorkView->GetPrinter(false);
                                 JobSetup aJobSetup = pDocPrt ? pDocPrt->GetJobSetup() : pWorkView->GetJobSetup();
                                 Printer::PreparePrintJob( pWorkView->GetPrinterController(), aJobSetup );
+#if ENABLE_CUPS
+                                psp::PrinterInfoManager::get().startBatchPrint();
+#endif
                             }
                             if( !Printer::ExecutePrintJob( pWorkView->GetPrinterController()))
                                 bCancel = true;
@@ -1324,7 +1352,7 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
                                 }
                             }
                         }
-                        if( rMergeDescriptor.bCreateSingleFile )
+                        if( bCreateSingleFile )
                         {
                             pWorkDoc->SetDBManager( pOldDBManager );
                             xWorkDocSh->DoClose();
@@ -1337,7 +1365,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))
+                if(!bFreezedLayouts && bCreateSingleFile)
                 {
                     std::set<SwRootFrm*> aAllLayouts = pTargetShell->GetDoc()->GetAllLayouts();
                     std::for_each( aAllLayouts.begin(), aAllLayouts.end(),
@@ -1347,15 +1375,20 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
             } while( !bCancel &&
                 (bSynchronizedDoc && (nStartRow != nEndRow)? ExistsNextRecord() : ToNextMergeRecord()));
 
-            if( !rMergeDescriptor.bCreateSingleFile )
+            if( !bCreateSingleFile )
             {
                 if( rMergeDescriptor.nMergeType == DBMGR_MERGE_PRINTER )
+                {
                     Printer::FinishPrintJob( pWorkView->GetPrinterController());
+#if ENABLE_CUPS
+                    psp::PrinterInfoManager::get().flushBatchPrint();
+#endif
+                }
                 pWorkDoc->SetDBManager( pOldDBManager );
                 xWorkDocSh->DoClose();
             }
 
-            if (rMergeDescriptor.bCreateSingleFile)
+            if (bCreateSingleFile)
             {
                 // sw::DocumentLayoutManager::CopyLayoutFmt() did not generate
                 // unique fly names, do it here once.
@@ -1367,7 +1400,7 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
                 Application::Reschedule();
 
             // Unfreeze target document layouts and correct all PageDescs.
-            if(rMergeDescriptor.bCreateSingleFile)
+            if(bCreateSingleFile)
             {
                 pTargetShell->CalcLayout();
                 std::set<SwRootFrm*> aAllLayouts = pTargetShell->GetDoc()->GetAllLayouts();
@@ -1383,7 +1416,7 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
             {
                 rMergeDescriptor.pMailMergeConfigItem->SetTargetView( pTargetView );
             }
-            else if(rMergeDescriptor.bCreateSingleFile)
+            else if(bCreateSingleFile)
             {
                 if( rMergeDescriptor.nMergeType != DBMGR_MERGE_PRINTER )
                 {
diff --git a/vcl/inc/cupsmgr.hxx b/vcl/inc/cupsmgr.hxx
index c7b9487..4db4c1d 100644
--- a/vcl/inc/cupsmgr.hxx
+++ b/vcl/inc/cupsmgr.hxx
@@ -58,6 +58,23 @@ class CUPSManager : public PrinterInfoManager
     osl::Mutex                                                  m_aGetPPDMutex;
     bool                                                        m_bPPDThreadRunning;
 
+    struct PendingJob
+    {
+        OUString printerName;
+        OUString jobTitle;
+        JobData jobData;
+        bool banner;
+        OUString faxNumber;
+        OString file;
+        PendingJob( const OUString& printerName_, const OUString& jobTitle_, const JobData& jobData_,
+            bool banner_, const OUString& faxNumber_, const OString& file_ )
+            : printerName( printerName_ ), jobTitle( jobTitle_ ), jobData( jobData_ ), banner( banner_ ), faxNumber( faxNumber_ ), file( file_ )
+            {}
+        PendingJob() : banner( false ) {}
+    };
+    std::list< PendingJob > pendingJobs;
+    bool batchMode;
+
     CUPSManager();
     virtual ~CUPSManager();
 
@@ -66,6 +83,9 @@ class CUPSManager : public PrinterInfoManager
     void getOptionsFromDocumentSetup( const JobData& rJob, bool bBanner, int& rNumOptions, void** rOptions ) const;
     void runDests();
     OString threadedCupsGetPPD(const char* pPrinter);
+
+    bool processPendingJobs();
+    bool printJobs( const PendingJob& job, const std::vector< OString >& files );
 public:
     static void runDestThread(void* pMgr);
 
@@ -80,6 +100,10 @@ public:
     virtual bool endSpool( const OUString& rPrinterName, const OUString& rJobTitle, FILE* pFile, const JobData& rDocumentJobData, bool bBanner, const OUString& rFaxNumber ) SAL_OVERRIDE;
     virtual void setupJobContextData( JobData& rData ) SAL_OVERRIDE;
 
+    virtual bool startBatchPrint() SAL_OVERRIDE;
+    virtual bool flushBatchPrint() SAL_OVERRIDE;
+    virtual bool supportsBatchPrint() const SAL_OVERRIDE;
+
     /// changes the info about a named printer
     virtual void changePrinterInfo( const OUString& rPrinter, const PrinterInfo& rNewInfo ) SAL_OVERRIDE;
 
diff --git a/vcl/unx/generic/printer/cupsmgr.cxx b/vcl/unx/generic/printer/cupsmgr.cxx
index 2dc978a..3ea62b0 100644
--- a/vcl/unx/generic/printer/cupsmgr.cxx
+++ b/vcl/unx/generic/printer/cupsmgr.cxx
@@ -626,8 +626,6 @@ bool CUPSManager::endSpool( const OUString& rPrintername, const OUString& rJobTi
                rDocumentJobData.m_nCopies
                );
 
-    int nJobID = 0;
-
     osl::MutexGuard aGuard( m_aCUPSMutex );
 
     std::unordered_map< OUString, int, OUStringHash >::iterator dest_it =
@@ -639,32 +637,105 @@ bool CUPSManager::endSpool( const OUString& rPrintername, const OUString& rJobTi
     }
 
     std::unordered_map< FILE*, OString, FPtrHash >::const_iterator it = m_aSpoolFiles.find( pFile );
-    if( it != m_aSpoolFiles.end() )
+    if( it == m_aSpoolFiles.end() )
+        return false;
+    fclose( pFile );
+    PendingJob job( rPrintername, rJobTitle, rDocumentJobData, bBanner, rFaxNumber, it->second );
+    m_aSpoolFiles.erase( pFile );
+    pendingJobs.push_back( job );
+    if( !batchMode ) // process immediately, otherwise will be handled by flushBatchPrint()
+        return processPendingJobs();
+    return true;
+}
+
+bool CUPSManager::startBatchPrint()
+{
+    batchMode = true;
+    return true;
+}
+
+bool CUPSManager::supportsBatchPrint() const
+{
+    return true;
+}
+
+bool CUPSManager::flushBatchPrint()
+{
+    osl::MutexGuard aGuard( m_aCUPSMutex );
+    return processPendingJobs();
+}
+
+bool CUPSManager::processPendingJobs()
+{
+    // Print all jobs that have the same data using one CUPS call (i.e. merge all jobs that differ only in files to print).
+    PendingJob currentJobData;
+    bool first = true;
+    std::vector< OString > files;
+    bool ok = true;
+    while( !pendingJobs.empty())
+    {
+        if( first )
+        {
+            currentJobData = pendingJobs.front();
+            first = false;
+        }
+        else if( currentJobData.printerName != pendingJobs.front().printerName
+                || currentJobData.jobTitle != pendingJobs.front().jobTitle
+                || currentJobData.jobData != pendingJobs.front().jobData
+                || currentJobData.banner != pendingJobs.front().banner )
+        {
+            if( !printJobs( currentJobData, files ))
+                ok = false;
+            files.clear();
+            currentJobData = pendingJobs.front();
+        }
+        files.push_back( pendingJobs.front().file );
+        pendingJobs.pop_front();
+    }
+    if( !first )
     {
-        fclose( pFile );
+        if( !printJobs( currentJobData, files )) // print the last batch
+            ok = false;
+    }
+    return ok;
+}
+
+bool CUPSManager::printJobs( const PendingJob& job, const std::vector< OString >& files )
+{
+    std::unordered_map< OUString, int, OUStringHash >::iterator dest_it =
+        m_aCUPSDestMap.find( job.printerName );
+
         rtl_TextEncoding aEnc = osl_getThreadTextEncoding();
 
         // setup cups options
         int nNumOptions = 0;
         cups_option_t* pOptions = NULL;
-        getOptionsFromDocumentSetup( rDocumentJobData, bBanner, nNumOptions, reinterpret_cast<void**>(&pOptions) );
+        getOptionsFromDocumentSetup( job.jobData, job.banner, nNumOptions, reinterpret_cast<void**>(&pOptions) );
 
-        OString sJobName(OUStringToOString(rJobTitle, aEnc));
+        OString sJobName(OUStringToOString(job.jobTitle, aEnc));
 
         //fax4CUPS, "the job name will be dialled for you"
         //so override the jobname with the desired number
-        if (!rFaxNumber.isEmpty())
+        if (!job.faxNumber.isEmpty())
         {
-            sJobName = OUStringToOString(rFaxNumber, aEnc);
+            sJobName = OUStringToOString(job.faxNumber, aEnc);
         }
 
         cups_dest_t* pDest = ((cups_dest_t*)m_pDests) + dest_it->second;
-        nJobID = cupsPrintFile(pDest->name,
-            it->second.getStr(),
+
+        std::vector< const char* > fnames;
+        for( std::vector< OString >::const_iterator it = files.begin();
+             it != files.end();
+             ++it )
+            fnames.push_back( it->getStr());
+
+        int nJobID = cupsPrintFiles(pDest->name,
+            fnames.size(),
+            fnames.data(),
             sJobName.getStr(),
             nNumOptions, pOptions);
         SAL_INFO("vcl.unx.print", "cupsPrintFile( " << pDest->name << ", "
-                << it->second << ", " << rJobTitle << ", " << nNumOptions
+                << ( fnames.size() == 1 ? files.front() : OString::number( fnames.size()) ).getStr() << ", " << sJobName << ", " << nNumOptions
                 << ", " << pOptions << " ) returns " << nJobID);
         for( int n = 0; n < nNumOptions; n++ )
             SAL_INFO("vcl.unx.print",
@@ -676,11 +747,13 @@ bool CUPSManager::endSpool( const OUString& rPrintername, const OUString& rJobTi
         system( aCmd.getStr() );
 #endif
 
-        unlink( it->second.getStr() );
-        m_aSpoolFiles.erase( pFile );
+        for( std::vector< OString >::const_iterator it = files.begin();
+             it != files.end();
+             ++it )
+            unlink( it->getStr());
+
         if( pOptions )
             cupsFreeOptions( nNumOptions, pOptions );
-    }
 
     return nJobID != 0;
 }
diff --git a/vcl/unx/generic/printer/jobdata.cxx b/vcl/unx/generic/printer/jobdata.cxx
index ae76040..dacf2e2 100644
--- a/vcl/unx/generic/printer/jobdata.cxx
+++ b/vcl/unx/generic/printer/jobdata.cxx
@@ -53,6 +53,24 @@ JobData& JobData::operator=(const JobData& rRight)
     return *this;
 }
 
+bool psp::operator==(const psp::JobData& rLeft, const psp::JobData& rRight)
+{
+    return rLeft.m_nCopies == rRight.m_nCopies
+//        && rLeft.m_bCollate == rRight.m_bCollate
+        && rLeft.m_nLeftMarginAdjust == rRight.m_nLeftMarginAdjust
+        && rLeft.m_nRightMarginAdjust == rRight.m_nRightMarginAdjust
+        && rLeft.m_nTopMarginAdjust == rRight.m_nTopMarginAdjust
+        && rLeft.m_nBottomMarginAdjust == rRight.m_nBottomMarginAdjust
+        && rLeft.m_nColorDepth == rRight.m_nColorDepth
+        && rLeft.m_eOrientation == rRight.m_eOrientation
+        && rLeft.m_aPrinterName == rRight.m_aPrinterName
+        && rLeft.m_pParser == rRight.m_pParser
+//        && rLeft.m_aContext == rRight.m_aContext
+        && rLeft.m_nPSLevel == rRight.m_nPSLevel
+        && rLeft.m_nPDFDevice == rRight.m_nPDFDevice
+        && rLeft.m_nColorDevice == rRight.m_nColorDevice;
+}
+
 void JobData::setCollate( bool bCollate )
 {
     if (m_nPDFDevice > 0)
diff --git a/vcl/unx/generic/printer/printerinfomanager.cxx b/vcl/unx/generic/printer/printerinfomanager.cxx
index 2690c88..0c9ed63 100644
--- a/vcl/unx/generic/printer/printerinfomanager.cxx
+++ b/vcl/unx/generic/printer/printerinfomanager.cxx
@@ -933,6 +933,21 @@ void PrinterInfoManager::setDefaultPaper( PPDContext& rContext ) const
     }
 }
 
+bool PrinterInfoManager::startBatchPrint()
+{
+    return false; // not implemented
+}
+
+bool PrinterInfoManager::supportsBatchPrint() const
+{
+    return false;
+}
+
+bool PrinterInfoManager::flushBatchPrint()
+{
+    return false;
+}
+
 SystemQueueInfo::SystemQueueInfo() :
     m_bChanged( false )
 {
commit e0ad036eed6b151ea81311fcf9ba46f1726b103c
Author: Luboš Luňák <l.lunak at collabora.com>
Date:   Thu Feb 19 16:39:06 2015 +0100

    mailmerge doesn't need to use the singlefile technique for printing
    
    It should be sufficient for every record to just update the fields and print
    the document. The printing code apparently rather expects to do the printing
    in one go, so split the functions up there.
    
    Conflicts:
    	include/sfx2/viewsh.hxx
    	include/vcl/print.hxx
    	sfx2/source/view/viewprn.cxx
    	sw/source/uibase/dbui/dbmgr.cxx
    	sw/source/uibase/uno/unomailmerge.cxx
    	vcl/source/gdi/print3.cxx
    
    Change-Id: I4d17c703b3220f47609fc4b054ce048b299a0c92

diff --git a/include/sfx2/viewsh.hxx b/include/sfx2/viewsh.hxx
index 31e2d68..42cea72 100644
--- a/include/sfx2/viewsh.hxx
+++ b/include/sfx2/viewsh.hxx
@@ -35,6 +35,7 @@
 #include <tools/gen.hxx>
 #include <tools/errcode.hxx>
 #include <vcl/jobset.hxx>
+#include <boost/shared_ptr.hpp>
 
 class SfxBaseController;
 class Size;
@@ -59,6 +60,7 @@ class Dialog;
 class Menu;
 class NotifyEvent;
 class SfxInPlaceClient;
+namespace vcl { class PrinterController; }
 
 #define SFX_PRINTER_PRINTER               1  // without JOB SETUP => Temporary
 #define SFX_PRINTER_JOBSETUP         2
@@ -266,6 +268,9 @@ public:
     bool                        TryContextMenuInterception( Menu& rIn, const OUString& rMenuIdentifier, Menu*& rpOut, ::com::sun::star::ui::ContextMenuExecuteEvent aEvent );
 
     void                        ExecPrint( const com::sun::star::uno::Sequence < com::sun::star::beans::PropertyValue >&, bool, bool );
+    // Like ExecPrint(), but only sets up for printing. Use Printer::ExecutePrintJob() and Printer::FinishPrintJob() afterwards.
+    void                        StartPrint( const com::sun::star::uno::Sequence < com::sun::star::beans::PropertyValue >&, bool, bool );
+    std::shared_ptr< vcl::PrinterController > GetPrinterController() const;
 
     void                        AddRemoveClipboardListener( const com::sun::star::uno::Reference < com::sun::star::datatransfer::clipboard::XClipboardListener>&, bool );
     ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboardNotifier > GetClipboardNotifier();
diff --git a/include/vcl/print.hxx b/include/vcl/print.hxx
index b0dd3f0..d749769 100644
--- a/include/vcl/print.hxx
+++ b/include/vcl/print.hxx
@@ -405,9 +405,16 @@ public:
                                            const Image&, sal_uInt16 ) SAL_OVERRIDE;
 
 
+    // These 3 together are more modular PrintJob(), allowing printing more documents as one print job
+    // by repeated calls to ExecutePrintJob(). Used by mailmerge.
+    static void                 PreparePrintJob( std::shared_ptr<vcl::PrinterController> i_pController,
+                                        const JobSetup& i_rInitSetup );
+    static bool                 ExecutePrintJob( std::shared_ptr<vcl::PrinterController> i_pController );
+    static void                 FinishPrintJob( std::shared_ptr<vcl::PrinterController> i_pController );
+
     // implementation detail of PrintJob being asynchronous
     // not exported, not usable outside vcl
-    static void SAL_DLLPRIVATE  ImplPrintJob( const std::shared_ptr<vcl::PrinterController>& i_pController,
+    static void SAL_DLLPRIVATE  ImplPrintJob( std::shared_ptr<vcl::PrinterController> i_pController,
                                               const JobSetup& i_rInitSetup );
 };
 
diff --git a/sfx2/source/view/viewprn.cxx b/sfx2/source/view/viewprn.cxx
index 0ed526d..2104532 100644
--- a/sfx2/source/view/viewprn.cxx
+++ b/sfx2/source/view/viewprn.cxx
@@ -567,8 +567,10 @@ SfxPrinter* SfxViewShell::SetPrinter_Impl( SfxPrinter *pNewPrinter )
     return pDocPrinter;
 }
 
-void SfxViewShell::ExecPrint( const uno::Sequence < beans::PropertyValue >& rProps, bool bIsAPI, bool bIsDirect )
+void SfxViewShell::StartPrint( const uno::Sequence < beans::PropertyValue >& rProps, bool bIsAPI, bool bIsDirect )
 {
+    assert( pImp->m_xPrinterController.get() == NULL );
+
     // get the current selection; our controller should know it
     Reference< frame::XController > xController( GetController() );
     Reference< view::XSelectionSupplier > xSupplier( xController, UNO_QUERY );
@@ -610,11 +612,20 @@ void SfxViewShell::ExecPrint( const uno::Sequence < beans::PropertyValue >& rPro
     SfxObjectShell *pObjShell = GetObjectShell();
     xNewController->setValue( OUString( "JobName"  ),
                         makeAny( OUString( pObjShell->GetTitle(0) ) ) );
+}
 
+void SfxViewShell::ExecPrint( const uno::Sequence < beans::PropertyValue >& rProps, bool bIsAPI, bool bIsDirect )
+{
+    StartPrint( rProps, bIsAPI, bIsDirect );
     // FIXME: job setup
     SfxPrinter* pDocPrt = GetPrinter(false);
     JobSetup aJobSetup = pDocPrt ? pDocPrt->GetJobSetup() : GetJobSetup();
-    Printer::PrintJob( xNewController, aJobSetup );
+    Printer::PrintJob( GetPrinterController(), aJobSetup );
+}
+
+std::shared_ptr< vcl::PrinterController > SfxViewShell::GetPrinterController() const
+{
+    return pImp->m_xPrinterController;
 }
 
 Printer* SfxViewShell::GetActivePrinter() const
diff --git a/sw/source/uibase/dbui/dbmgr.cxx b/sw/source/uibase/dbui/dbmgr.cxx
index d93e85c..af65b33 100644
--- a/sw/source/uibase/dbui/dbmgr.cxx
+++ b/sw/source/uibase/dbui/dbmgr.cxx
@@ -23,6 +23,7 @@
 #include <unotxdoc.hxx>
 #include <com/sun/star/text/NotePrintMode.hpp>
 #include <sfx2/app.hxx>
+#include <sfx2/printer.hxx>
 #include <com/sun/star/sdb/CommandType.hpp>
 #include <com/sun/star/sdb/XDocumentDataSource.hpp>
 #include <com/sun/star/frame/XComponentLoader.hpp>
@@ -1159,6 +1160,41 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
                                     lcl_CopyFollowPageDesc( *pTargetShell, *pWorkPageDesc, *pTargetPageDesc, nDocNo );
                                 }
                             }
+                        else if( rMergeDescriptor.nMergeType == DBMGR_MERGE_PRINTER )
+                        {
+                            if( 1 == nDocNo ) // set up printing only once at the beginning
+                            {
+                                // printing should be done synchronously otherwise the document
+                                // might already become invalid during the process
+                                uno::Sequence< beans::PropertyValue > aOptions( rMergeDescriptor.aPrintOptions );
+
+                                aOptions.realloc( 2 );
+                                aOptions[ 0 ].Name = "Wait";
+                                aOptions[ 0 ].Value <<= sal_True;
+                                aOptions[ 1 ].Name = "MonitorVisible";
+                                aOptions[ 1 ].Value <<= sal_False;
+                                // move print options
+                                const beans::PropertyValue* pPrintOptions = rMergeDescriptor.aPrintOptions.getConstArray();
+                                for( sal_Int32 nOption = 0, nIndex = 1 ; nOption < rMergeDescriptor.aPrintOptions.getLength(); ++nOption)
+                                {
+                                    if( pPrintOptions[nOption].Name == "CopyCount" || pPrintOptions[nOption].Name == "FileName"
+                                        || pPrintOptions[nOption].Name == "Collate" || pPrintOptions[nOption].Name == "Pages"
+                                        || pPrintOptions[nOption].Name == "Wait" || pPrintOptions[nOption].Name == "PrinterName" )
+                                    {
+                                        // add an option
+                                        aOptions.realloc( nIndex + 1 );
+                                        aOptions[ nIndex ].Name = pPrintOptions[nOption].Name;
+                                        aOptions[ nIndex++ ].Value = pPrintOptions[nOption].Value ;
+                                    }
+                                }
+                                pWorkView->StartPrint( aOptions, IsMergeSilent(), rMergeDescriptor.bPrintAsync );
+                                SfxPrinter* pDocPrt = pWorkView->GetPrinter(false);
+                                JobSetup aJobSetup = pDocPrt ? pDocPrt->GetJobSetup() : pWorkView->GetJobSetup();
+                                Printer::PreparePrintJob( pWorkView->GetPrinterController(), aJobSetup );
+                            }
+                            if( !Printer::ExecutePrintJob( pWorkView->GetPrinterController()))
+                                bCancel = true;
+                        }
                             else
                                 pTargetPageDesc = pTargetShell->FindPageDescByName( sModifiedStartingPageDesc );
 
@@ -1313,6 +1349,8 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
 
             if( !rMergeDescriptor.bCreateSingleFile )
             {
+                if( rMergeDescriptor.nMergeType == DBMGR_MERGE_PRINTER )
+                    Printer::FinishPrintJob( pWorkView->GetPrinterController());
                 pWorkDoc->SetDBManager( pOldDBManager );
                 xWorkDocSh->DoClose();
             }
@@ -2665,7 +2703,7 @@ void SwDBManager::ExecuteFormLetter( SwWrtShell& rSh,
 
                     SwMergeDescriptor aMergeDesc( pImpl->pMergeDialog->GetMergeType(), pView->GetWrtShell(), aDescriptor );
                     aMergeDesc.sSaveToFilter = pImpl->pMergeDialog->GetSaveFilter();
-                    aMergeDesc.bCreateSingleFile = pImpl->pMergeDialog->IsSaveSingleDoc();
+                    aMergeDesc.bCreateSingleFile = pImpl->pMergeDialog->IsSaveSingleDoc() && pImpl->pMergeDialog->GetMergeType() != DBMGR_MERGE_PRINTER;
                     aMergeDesc.bSubjectIsFilename = aMergeDesc.bCreateSingleFile;
                     if( !aMergeDesc.bCreateSingleFile && pImpl->pMergeDialog->IsGenerateFromDataBase() )
                     {
diff --git a/sw/source/uibase/uno/unomailmerge.cxx b/sw/source/uibase/uno/unomailmerge.cxx
index 30adba6..216a6c6 100644
--- a/sw/source/uibase/uno/unomailmerge.cxx
+++ b/sw/source/uibase/uno/unomailmerge.cxx
@@ -691,7 +691,7 @@ uno::Any SAL_CALL SwXMailMerge::execute(
             // when mail merge is called as command line macro
             aMergeDesc.bPrintAsync = false;
             aMergeDesc.aPrintOptions = aPrintSettings;
-            aMergeDesc.bCreateSingleFile = true;
+            aMergeDesc.bCreateSingleFile = false;
         }
         break;
     case MailMergeType::SHELL:
diff --git a/vcl/source/gdi/print3.cxx b/vcl/source/gdi/print3.cxx
index bfabad1..3bd9f05 100644
--- a/vcl/source/gdi/print3.cxx
+++ b/vcl/source/gdi/print3.cxx
@@ -297,11 +297,9 @@ void Printer::PrintJob(const std::shared_ptr<PrinterController>& i_xController,
     }
 }
 
-void Printer::ImplPrintJob(const std::shared_ptr<PrinterController>& i_xController,
+void Printer::PreparePrintJob(std::shared_ptr<PrinterController> xController,
                            const JobSetup& i_rInitSetup)
 {
-    std::shared_ptr<PrinterController> xController(i_xController);
-
     // check if there is a default printer; if not, show an error box (if appropriate)
     if( GetDefaultPrinterName().isEmpty() )
     {
@@ -328,7 +326,7 @@ void Printer::ImplPrintJob(const std::shared_ptr<PrinterController>& i_xControll
     }
 
     // reset last page property
-    i_xController->setLastPage(false);
+    xController->setLastPage(false);
 
     // update "PageRange" property inferring from other properties:
     // case 1: "Pages" set from UNO API ->
@@ -340,12 +338,12 @@ void Printer::ImplPrintJob(const std::shared_ptr<PrinterController>& i_xControll
     // "Pages" attribute from API is now equivalent to "PageRange"
     // AND "PrintContent" = 1 except calc where it is "PrintRange" = 1
     // Argh ! That sure needs cleaning up
-    PropertyValue* pContentVal = i_xController->getValue(OUString("PrintRange"));
+    PropertyValue* pContentVal = xController->getValue(OUString("PrintRange"));
     if( ! pContentVal )
-        pContentVal = i_xController->getValue(OUString("PrintContent"));
+        pContentVal = xController->getValue(OUString("PrintContent"));
 
     // case 1: UNO API has set "Pages"
-    PropertyValue* pPagesVal = i_xController->getValue(OUString("Pages"));
+    PropertyValue* pPagesVal = xController->getValue(OUString("Pages"));
     if( pPagesVal )
     {
         OUString aPagesVal;
@@ -358,7 +356,7 @@ void Printer::ImplPrintJob(const std::shared_ptr<PrinterController>& i_xControll
             if( pContentVal )
             {
                 pContentVal->Value = makeAny( sal_Int32( 1 ) );
-                i_xController->setValue(OUString("PageRange"), pPagesVal->Value);
+                xController->setValue(OUString("PageRange"), pPagesVal->Value);
             }
         }
     }
@@ -371,13 +369,13 @@ void Printer::ImplPrintJob(const std::shared_ptr<PrinterController>& i_xControll
             if( nContent == 0 )
             {
                 // do not overwrite PageRange if it is already set
-                PropertyValue* pRangeVal = i_xController->getValue(OUString("PageRange"));
+                PropertyValue* pRangeVal = xController->getValue(OUString("PageRange"));
                 OUString aRange;
                 if( pRangeVal )
                     pRangeVal->Value >>= aRange;
                 if( aRange.isEmpty() )
                 {
-                    sal_Int32 nPages = i_xController->getPageCount();
+                    sal_Int32 nPages = xController->getPageCount();
                     if( nPages > 0 )
                     {
                         OUStringBuffer aBuf( 32 );
@@ -387,14 +385,14 @@ void Printer::ImplPrintJob(const std::shared_ptr<PrinterController>& i_xControll
                             aBuf.appendAscii( "-" );
                             aBuf.append( nPages );
                         }
-                        i_xController->setValue(OUString("PageRange"), makeAny(aBuf.makeStringAndClear()));
+                        xController->setValue(OUString("PageRange"), makeAny(aBuf.makeStringAndClear()));
                     }
                 }
             }
         }
     }
 
-    PropertyValue* pReverseVal = i_xController->getValue(OUString("PrintReverse"));
+    PropertyValue* pReverseVal = xController->getValue(OUString("PrintReverse"));
     if( pReverseVal )
     {
         bool bReverse = false;
@@ -402,7 +400,7 @@ void Printer::ImplPrintJob(const std::shared_ptr<PrinterController>& i_xControll
         xController->setReversePrint( bReverse );
     }
 
-    PropertyValue* pPapersizeFromSetupVal = i_xController->getValue(OUString("PapersizeFromSetup"));
+    PropertyValue* pPapersizeFromSetupVal = xController->getValue(OUString("PapersizeFromSetup"));
     if( pPapersizeFromSetupVal )
     {
         bool bPapersizeFromSetup = false;
@@ -411,35 +409,35 @@ void Printer::ImplPrintJob(const std::shared_ptr<PrinterController>& i_xControll
     }
 
     // setup NUp printing from properties
-    sal_Int32 nRows = i_xController->getIntProperty(OUString("NUpRows"), 1);
-    sal_Int32 nCols = i_xController->getIntProperty(OUString("NUpColumns"), 1);
+    sal_Int32 nRows = xController->getIntProperty(OUString("NUpRows"), 1);
+    sal_Int32 nCols = xController->getIntProperty(OUString("NUpColumns"), 1);
     if( nRows > 1 || nCols > 1 )
     {
         PrinterController::MultiPageSetup aMPS;
         aMPS.nRows         = nRows > 1 ? nRows : 1;
         aMPS.nColumns      = nCols > 1 ? nCols : 1;
-        sal_Int32 nValue = i_xController->getIntProperty(OUString("NUpPageMarginLeft"), aMPS.nLeftMargin);
+        sal_Int32 nValue = xController->getIntProperty(OUString("NUpPageMarginLeft"), aMPS.nLeftMargin);
         if( nValue >= 0 )
             aMPS.nLeftMargin = nValue;
-        nValue = i_xController->getIntProperty(OUString("NUpPageMarginRight"), aMPS.nRightMargin);
+        nValue = xController->getIntProperty(OUString("NUpPageMarginRight"), aMPS.nRightMargin);
         if( nValue >= 0 )
             aMPS.nRightMargin = nValue;
-        nValue = i_xController->getIntProperty( OUString( "NUpPageMarginTop" ), aMPS.nTopMargin );
+        nValue = xController->getIntProperty( OUString( "NUpPageMarginTop" ), aMPS.nTopMargin );
         if( nValue >= 0 )
             aMPS.nTopMargin = nValue;
-        nValue = i_xController->getIntProperty( OUString( "NUpPageMarginBottom" ), aMPS.nBottomMargin );
+        nValue = xController->getIntProperty( OUString( "NUpPageMarginBottom" ), aMPS.nBottomMargin );
         if( nValue >= 0 )
             aMPS.nBottomMargin = nValue;
-        nValue = i_xController->getIntProperty( OUString( "NUpHorizontalSpacing" ), aMPS.nHorizontalSpacing );
+        nValue = xController->getIntProperty( OUString( "NUpHorizontalSpacing" ), aMPS.nHorizontalSpacing );
         if( nValue >= 0 )
             aMPS.nHorizontalSpacing = nValue;
-        nValue = i_xController->getIntProperty( OUString( "NUpVerticalSpacing" ), aMPS.nVerticalSpacing );
+        nValue = xController->getIntProperty( OUString( "NUpVerticalSpacing" ), aMPS.nVerticalSpacing );
         if( nValue >= 0 )
             aMPS.nVerticalSpacing = nValue;
-        aMPS.bDrawBorder = i_xController->getBoolProperty( OUString( "NUpDrawBorder" ), aMPS.bDrawBorder );
-        aMPS.nOrder = static_cast<PrinterController::NupOrderType>(i_xController->getIntProperty( OUString( "NUpSubPageOrder" ), aMPS.nOrder ));
-        aMPS.aPaperSize = i_xController->getPrinter()->PixelToLogic( i_xController->getPrinter()->GetPaperSizePixel(), MapMode( MAP_100TH_MM ) );
-        PropertyValue* pPgSizeVal = i_xController->getValue( OUString( "NUpPaperSize" ) );
+        aMPS.bDrawBorder = xController->getBoolProperty( OUString( "NUpDrawBorder" ), aMPS.bDrawBorder );
+        aMPS.nOrder = static_cast<PrinterController::NupOrderType>(xController->getIntProperty( OUString( "NUpSubPageOrder" ), aMPS.nOrder ));
+        aMPS.aPaperSize = xController->getPrinter()->PixelToLogic( xController->getPrinter()->GetPaperSizePixel(), MapMode( MAP_100TH_MM ) );
+        PropertyValue* pPgSizeVal = xController->getValue( OUString( "NUpPaperSize" ) );
         awt::Size aSizeVal;
         if( pPgSizeVal && (pPgSizeVal->Value >>= aSizeVal) )
         {
@@ -447,7 +445,7 @@ void Printer::ImplPrintJob(const std::shared_ptr<PrinterController>& i_xControll
             aMPS.aPaperSize.Height() = aSizeVal.Height;
         }
 
-        i_xController->setMultipage( aMPS );
+        xController->setMultipage( aMPS );
     }
 
     // in direct print case check whether there is anything to print.
@@ -472,10 +470,10 @@ void Printer::ImplPrintJob(const std::shared_ptr<PrinterController>& i_xControll
     {
         try
         {
-            PrintDialog aDlg( NULL, i_xController );
+            PrintDialog aDlg( NULL, xController );
             if( ! aDlg.Execute() )
             {
-                i_xController->abortJob();
+                xController->abortJob();
                 return;
             }
             if( aDlg.isPrintToFile() )
@@ -483,7 +481,7 @@ void Printer::ImplPrintJob(const std::shared_ptr<PrinterController>& i_xControll
                 OUString aFile = queryFile( xController->getPrinter().get() );
                 if( aFile.isEmpty() )
                 {
-                    i_xController->abortJob();
+                    xController->abortJob();
                     return;
                 }
                 xController->setValue( OUString( "LocalFileName" ),
@@ -501,19 +499,32 @@ void Printer::ImplPrintJob(const std::shared_ptr<PrinterController>& i_xControll
     }
 
     xController->pushPropertiesToPrinter();
+}
 
+bool Printer::ExecutePrintJob(std::shared_ptr<PrinterController> xController)
+{
     OUString aJobName;
     PropertyValue* pJobNameVal = xController->getValue( OUString( "JobName" ) );
     if( pJobNameVal )
         pJobNameVal->Value >>= aJobName;
 
-    xController->getPrinter()->StartJob( aJobName, xController );
+    return xController->getPrinter()->StartJob( aJobName, xController );
+}
 
+void Printer::FinishPrintJob(std::shared_ptr<PrinterController> xController)
+{
     xController->resetPaperToLastConfigured();
-
     xController->jobFinished( xController->getJobState() );
 }
 
+void Printer::ImplPrintJob(std::shared_ptr<PrinterController> xController,
+                           const JobSetup& i_rInitSetup)
+{
+    PreparePrintJob( xController, i_rInitSetup );
+    ExecutePrintJob( xController );
+    FinishPrintJob( xController );
+}
+
 bool Printer::StartJob( const OUString& i_rJobName, std::shared_ptr<vcl::PrinterController>& i_xController)
 {
     mnError = PRINTER_OK;
commit 1ef9952e804da953706cc514564db92a4a4a07b5
Author: Luboš Luňák <l.lunak at collabora.com>
Date:   Tue Feb 17 21:31:21 2015 +0100

    do not needlessly make overriden functions more private
    
    These are public in the base class.
    
    Conflicts:
    	sw/source/uibase/inc/view.hxx
    
    Change-Id: I839ffe56a835f99c2812cffb60804b74aaa9c5ac

diff --git a/sw/source/uibase/inc/view.hxx b/sw/source/uibase/inc/view.hxx
index 4378449..b921216 100644
--- a/sw/source/uibase/inc/view.hxx
+++ b/sw/source/uibase/inc/view.hxx
@@ -332,11 +332,6 @@ class SW_DLLPUBLIC SwView: public SfxViewShell
     SAL_DLLPRIVATE void          SpellKontext(bool bOn = true)
                                  { m_bCenterCrsr = bOn; m_bAlwaysShowSel = bOn; }
 
-    // methods for printing
-    SAL_DLLPRIVATE virtual SfxPrinter*       GetPrinter( bool bCreate = false ) SAL_OVERRIDE;
-    SAL_DLLPRIVATE virtual bool              HasPrintOptionsPage() const SAL_OVERRIDE;
-    SAL_DLLPRIVATE virtual SfxTabPage*       CreatePrintOptionsPage( vcl::Window* pParent,
-                                                    const SfxItemSet& rSet) SAL_OVERRIDE;
     // for readonly switching
     SAL_DLLPRIVATE virtual void  Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) SAL_OVERRIDE;
     SAL_DLLPRIVATE void          _CheckReadonlyState();
@@ -664,6 +659,12 @@ public:
     void UpdateDocStats();
     /// Where is the real cursor: in the annotation or in the main document?
     void SetAnnotationMode(bool bMode);
+
+    // methods for printing
+    SAL_DLLPRIVATE virtual   SfxPrinter*     GetPrinter( bool bCreate = false ) SAL_OVERRIDE;
+    SAL_DLLPRIVATE virtual bool  HasPrintOptionsPage() const SAL_OVERRIDE;
+    SAL_DLLPRIVATE virtual SfxTabPage*       CreatePrintOptionsPage( vcl::Window* pParent,
+                                                    const SfxItemSet& rSet) SAL_OVERRIDE;
 };
 
 inline long SwView::GetXScroll() const
commit 356d93766e27337a5463e793ceeb9da757a3a37f
Author: Luboš Luňák <l.lunak at collabora.com>
Date:   Sun Feb 15 22:53:57 2015 +0100

    avoid creating temporary document copies in non-singlefile MM mode
    
    The singlefile mode needs a new copy for every record, because it modifies
    it (such as changing fields to text), but the non-singlefile mode does not
    need all that relatively expensive work, because it just updates the fields
    and nothing else.
    
    Conflicts:
    	sw/source/uibase/dbui/dbmgr.cxx
    
    Change-Id: If02cf8aca1d0f050ffb63cd85d5a9455afc5a6ea

diff --git a/sw/source/uibase/dbui/dbmgr.cxx b/sw/source/uibase/dbui/dbmgr.cxx
index 145b8dd..d93e85c 100644
--- a/sw/source/uibase/dbui/dbmgr.cxx
+++ b/sw/source/uibase/dbui/dbmgr.cxx
@@ -1008,6 +1008,14 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
             bool bFreezedLayouts = false;
             // collect temporary files
             ::std::vector< OUString> aFilesToRemove;
+
+            // The SfxObjectShell will be closed explicitly later but it is more safe to use SfxObjectShellLock here
+            SfxObjectShellLock xWorkDocSh;
+            // a view frame for the document
+            SwView* pWorkView = NULL;
+            SwDoc* pWorkDoc = NULL;
+            SwDBManager* pOldDBManager = NULL;
+
             do
             {
                 nStartRow = pImpl->pMergeData ? pImpl->pMergeData->xResultSet->getRow() : 0;
@@ -1074,21 +1082,26 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
                         for( sal_uInt16 i = 0; i < 25; i++ )
                             Application::Reschedule();
 
-                        // The SfxObjectShell will be closed explicitly later but it is more safe to use SfxObjectShellLock here
-                        // copy the source document
-                        SfxObjectShellLock xWorkDocSh = pSourceDocSh->GetDoc()->CreateCopy( true );
+                        // Create a copy of the source document and work with that one instead of the source.
+                        // If we're not in the single file mode (which requires modifying the document for the merging),
+                        // it is enough to do this just once.
+                        if( 1 == nDocNo || rMergeDescriptor.bCreateSingleFile )
+                        {
+                            assert( !xWorkDocSh.Is());
+                            // copy the source document
+                            xWorkDocSh = pSourceDocSh->GetDoc()->CreateCopy( true );
 
                         //create a view frame for the document
-                        SwView* pWorkView = static_cast< SwView* >( SfxViewFrame::LoadHiddenDocument( *xWorkDocSh, 0 )->GetViewShell() );
+                        pWorkView = static_cast< SwView* >( SfxViewFrame::LoadHiddenDocument( *xWorkDocSh, 0 )->GetViewShell() );
                         //request the layout calculation
                         SwWrtShell& rWorkShell = pWorkView->GetWrtShell();
                         pWorkView->AttrChangedNotify( &rWorkShell );// in order for SelectShell to be called
 
-                        SwDoc* pWorkDoc = rWorkShell.GetDoc();
+                        pWorkDoc = rWorkShell.GetDoc();
                         pWorkDoc->ReplaceDocumentProperties( *pSourceDocSh->GetDoc());
                         if ( (nMaxDumpDocs < 0) || (nDocNo <= nMaxDumpDocs) )
                             lcl_SaveDoc( xWorkDocSh, "WorkDoc", nDocNo );
-                        SwDBManager* pOldDBManager = pWorkDoc->GetDBManager();
+                        pOldDBManager = pWorkDoc->GetDBManager();
                         pWorkDoc->SetDBManager( this );
                         pWorkDoc->getIDocumentLinksAdministration().EmbedAllLinks();
 
@@ -1096,12 +1109,15 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
                         rWorkShell.LockExpFlds();
                         rWorkShell.CalcLayout();
                         rWorkShell.UnlockExpFlds();
+                    }
 
+                        SwWrtShell& rWorkShell = pWorkView->GetWrtShell();
                         SfxGetpApp()->NotifyEvent(SfxEventHint(SW_EVENT_FIELD_MERGE, SwDocShell::GetEventName(STR_SW_EVENT_FIELD_MERGE), xWorkDocSh));
                         rWorkShell.SwViewShell::UpdateFlds();
                         SfxGetpApp()->NotifyEvent(SfxEventHint(SW_EVENT_FIELD_MERGE_FINISHED, SwDocShell::GetEventName(STR_SW_EVENT_FIELD_MERGE_FINISHED), xWorkDocSh));
 
-                        pWorkDoc->RemoveInvisibleContent();
+                        if( rMergeDescriptor.bCreateSingleFile )
+                            pWorkDoc->RemoveInvisibleContent();
 
                         // launch MailMergeEvent if required
                         const SwXMailMerge *pEvtSrc = GetMailMergeEvtSrc();
@@ -1272,9 +1288,12 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
                                 }
                             }
                         }
-                        pWorkDoc->SetDBManager( pOldDBManager );
-
-                        xWorkDocSh->DoClose();
+                        if( rMergeDescriptor.bCreateSingleFile )
+                        {
+                            pWorkDoc->SetDBManager( pOldDBManager );
+                            xWorkDocSh->DoClose();
+                            xWorkDocSh = NULL;
+                        }
                     }
                 }
                 nDocNo++;
@@ -1291,6 +1310,13 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
                 }
             } while( !bCancel &&
                 (bSynchronizedDoc && (nStartRow != nEndRow)? ExistsNextRecord() : ToNextMergeRecord()));
+
+            if( !rMergeDescriptor.bCreateSingleFile )
+            {
+                pWorkDoc->SetDBManager( pOldDBManager );
+                xWorkDocSh->DoClose();
+            }
+
             if (rMergeDescriptor.bCreateSingleFile)
             {
                 // sw::DocumentLayoutManager::CopyLayoutFmt() did not generate
commit d753dde3a701eba0fdfadb393c6380389246f0eb
Author: Luboš Luňák <l.lunak at collabora.com>
Date:   Sun Feb 15 17:07:31 2015 +0100

    do not create temp file(s) during MM if not needed
    
    Conflicts:
    	sw/source/uibase/dbui/dbmgr.cxx
    
    Change-Id: I1360e215bff42dd866ab1d94a18a8f2f9ddc7c66

diff --git a/sw/source/uibase/dbui/dbmgr.cxx b/sw/source/uibase/dbui/dbmgr.cxx
index 94e5bca..145b8dd 100644
--- a/sw/source/uibase/dbui/dbmgr.cxx
+++ b/sw/source/uibase/dbui/dbmgr.cxx
@@ -912,6 +912,7 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
 
             SwView* pTargetView = 0;
             boost::scoped_ptr< utl::TempFile > aTempFile;
+            bool createTempFile = ( rMergeDescriptor.nMergeType == DBMGR_MERGE_EMAIL || rMergeDescriptor.nMergeType == DBMGR_MERGE_FILE );
             OUString sModifiedStartingPageDesc;
             OUString sStartingPageDesc;
             sal_uInt16 nStartingPageNo = 0;
@@ -1026,7 +1027,7 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
                     }
 
                     // create a new temporary file name - only done once in case of bCreateSingleFile
-                    if( 1 == nDocNo || !rMergeDescriptor.bCreateSingleFile )
+                    if( createTempFile && ( 1 == nDocNo || !rMergeDescriptor.bCreateSingleFile ))
                     {
                         INetURLObject aEntry(sPath);
                         OUString sLeading;
@@ -1042,23 +1043,25 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
                             new utl::TempFile(sLeading, true, &sExt, &sPath));
                         if( rMergeDescriptor.bSubjectIsFilename )
                             aTempFile->EnableKillingFile();
+                        if( !aTempFile->IsValid() )
+                        {
+                            ErrorHandler::HandleError( ERRCODE_IO_NOTSUPPORTED );
+                            bNoError = false;
+                            bCancel = true;
+                        }
                     }
 
-                    if( !aTempFile->IsValid() )
-                    {
-                        ErrorHandler::HandleError( ERRCODE_IO_NOTSUPPORTED );
-                        bNoError = false;
-                        bCancel = true;
-                    }
-                    else
+                    if( !bCancel )
                     {
-                        INetURLObject aTempFileURL(aTempFile->GetURL());
+                        boost::scoped_ptr< INetURLObject > aTempFileURL;
+                        if( createTempFile )
+                            aTempFileURL.reset( new INetURLObject(aTempFile->GetURL()));
                         if (!IsMergeSilent()) {
                             if( bMergeShell )
                                 static_cast<CreateMonitor*>( pProgressDlg )->SetCurrentPosition( nDocNo );
                             else {
                                 PrintMonitor *pPrintMonDlg = static_cast<PrintMonitor*>( pProgressDlg );
-                                pPrintMonDlg->m_pPrinter->SetText( aTempFileURL.GetBase() );
+                                pPrintMonDlg->m_pPrinter->SetText( createTempFile ? aTempFileURL->GetBase() : OUString( pSourceDocSh->GetTitle( 22 )));
                                 OUString sStat(SW_RES(STR_STATSTR_LETTER));   // Brief
                                 sStat += " ";
                                 sStat += OUString::number( nDocNo );
@@ -1164,7 +1167,8 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
                         }
                         else
                         {
-                            OUString sFileURL =  aTempFileURL.GetMainURL( INetURLObject::NO_DECODE );
+                            assert( createTempFile );
+                            OUString sFileURL =  aTempFileURL->GetMainURL( INetURLObject::NO_DECODE );
                             SfxMedium* pDstMed = new SfxMedium(
                                 sFileURL,
                                 STREAM_STD_READWRITE );
@@ -1319,7 +1323,7 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
             {
                 if( rMergeDescriptor.nMergeType != DBMGR_MERGE_PRINTER )
                 {
-                    OSL_ENSURE( aTempFile.get(), "Temporary file not available" );
+                    assert( aTempFile.get());
                     INetURLObject aTempFileURL( rMergeDescriptor.bSubjectIsFilename ? sSubject : aTempFile->GetURL());
                     SfxMedium* pDstMed = new SfxMedium(
                         aTempFileURL.GetMainURL( INetURLObject::NO_DECODE ),


More information about the Libreoffice-commits mailing list