[Libreoffice-commits] core.git: Branch 'private/jmux/libreoffice-4-1-6+backports' - 15 commits - config_host/config_cups.h.in configure.ac include/sfx2 include/vcl sc/source sfx2/source shell/Package_scripts_kde.mk shell/source sw/inc sw/source vcl/inc vcl/source vcl/unx

Christoph Lutz christoph.lutz_ml at cib.de
Thu Mar 26 07:39:08 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 
 sc/source/ui/src/optdlg.src                    |    6 
 sfx2/source/view/viewprn.cxx                   |   15 +
 shell/Package_scripts_kde.mk                   |    6 
 shell/source/unix/misc/kde4-open-url.sh        |   22 +
 sw/inc/dbmgr.hxx                               |    2 
 sw/source/core/fields/dbfld.cxx                |    4 
 sw/source/core/fields/docufld.cxx              |    3 
 sw/source/ui/dbui/dbmgr.cxx                    |  307 ++++++++++++++++---------
 sw/source/ui/inc/view.hxx                      |   11 
 sw/source/ui/uno/unomailmerge.cxx              |    2 
 vcl/inc/cupsmgr.hxx                            |   23 +
 vcl/inc/unx/salframe.h                         |    1 
 vcl/source/filter/wmf/enhwmf.cxx               |   17 +
 vcl/source/filter/wmf/winmtf.cxx               |   11 
 vcl/source/filter/wmf/winmtf.hxx               |    2 
 vcl/source/gdi/print3.cxx                      |   73 +++--
 vcl/unx/generic/printer/cupsmgr.cxx            |  113 +++++++--
 vcl/unx/generic/printer/jobdata.cxx            |   18 +
 vcl/unx/generic/printer/printerinfomanager.cxx |   15 +
 vcl/unx/generic/window/salframe.cxx            |  147 +++++++++--
 vcl/unx/kde4/KDE4FilePicker.cxx                |   76 +++---
 vcl/unx/kde4/KDE4FilePicker.hxx                |    6 
 28 files changed, 682 insertions(+), 237 deletions(-)

New commits:
commit 743966cdf34a85c01f42c303a341ef9a9ce7288d
Author: Christoph Lutz <christoph.lutz_ml at cib.de>
Date:   Mon Mar 9 15:37:45 2015 +0000

    Don't store temporary mail merge file if mail merge job was cancelled
    
    If a mail merge "to single file" is canceled, the temporary file was still saved.
    This needed a lot of time for large mail merge results (>20s) which is not needed,
    wanted and inteded. We want mail merge to return asap.
    
    Reviewed-on: https://gerrit.libreoffice.org/14811
    Reviewed-by: Michael Stahl <mstahl at redhat.com>
    Tested-by: Michael Stahl <mstahl at redhat.com>
    (cherry picked from commit 86a547e33bab2a89513385c5af535a6099526616)
    
    Conflicts:
    
    	sw/source/uibase/dbui/dbmgr.cxx
    
    Change-Id: I74e9048c7eb483766e7e677dd21167b7d844a518

diff --git a/sw/source/ui/dbui/dbmgr.cxx b/sw/source/ui/dbui/dbmgr.cxx
index ba5f075..c8c2572 100644
--- a/sw/source/ui/dbui/dbmgr.cxx
+++ b/sw/source/ui/dbui/dbmgr.cxx
@@ -1445,27 +1445,30 @@ sal_Bool SwNewDBMgr::MergeMailFiles(SwWrtShell* pSourceShell,
             {
                 if( rMergeDescriptor.nMergeType != DBMGR_MERGE_PRINTER )
                 {
-                    assert( aTempFile.get());
-                    INetURLObject aTempFileURL( rMergeDescriptor.bSubjectIsFilename ? sSubject : aTempFile->GetURL());
-                    SfxMedium* pDstMed = new SfxMedium(
-                        aTempFileURL.GetMainURL( INetURLObject::NO_DECODE ),
-                        STREAM_STD_READWRITE );
-                    pDstMed->SetFilter( pStoreToFilter );
-                    if(pDstMed->GetItemSet())
+                    if( !bCancel )
                     {
-                        if(pStoreToFilterOptions )
-                            pDstMed->GetItemSet()->Put(SfxStringItem(SID_FILE_FILTEROPTIONS, *pStoreToFilterOptions));
-                        if(rMergeDescriptor.aSaveToFilterData.getLength())
-                            pDstMed->GetItemSet()->Put(SfxUsrAnyItem(SID_FILTER_DATA, makeAny(rMergeDescriptor.aSaveToFilterData)));
-                    }
+                        assert( aTempFile.get());
+                        INetURLObject aTempFileURL( rMergeDescriptor.bSubjectIsFilename ? sSubject : aTempFile->GetURL());
+                        SfxMedium* pDstMed = new SfxMedium(
+                            aTempFileURL.GetMainURL( INetURLObject::NO_DECODE ),
+                            STREAM_STD_READWRITE );
+                        pDstMed->SetFilter( pStoreToFilter );
+                        if(pDstMed->GetItemSet())
+                        {
+                            if(pStoreToFilterOptions )
+                                pDstMed->GetItemSet()->Put(SfxStringItem(SID_FILE_FILTEROPTIONS, *pStoreToFilterOptions));
+                            if(rMergeDescriptor.aSaveToFilterData.getLength())
+                                pDstMed->GetItemSet()->Put(SfxUsrAnyItem(SID_FILTER_DATA, makeAny(rMergeDescriptor.aSaveToFilterData)));
+                        }
 
-                    xTargetDocShell->DoSaveAs(*pDstMed);
-                    xTargetDocShell->DoSaveCompleted(pDstMed);
-                    if( xTargetDocShell->GetError() )
-                    {
-                        // error message ??
-                        ErrorHandler::HandleError( xTargetDocShell->GetError() );
-                        bNoError = sal_False;
+                        xTargetDocShell->DoSaveAs(*pDstMed);
+                        xTargetDocShell->DoSaveCompleted(pDstMed);
+                        if( xTargetDocShell->GetError() )
+                        {
+                            // error message ??
+                            ErrorHandler::HandleError( xTargetDocShell->GetError() );
+                            bNoError = sal_False;
+                        }
                     }
                 }
                 else if( pTargetView ) // must be available!
commit cbdc7d82bccd79bec118632808e95ef51a6de220
Author: Jan-Marek Glogowski <glogow at fbihome.de>
Date:   Thu Mar 19 15:48:37 2015 +0100

    tdf#70346 MM: don't restore section visibility
    
    Mail merging the current document is expected to change the
    source document. So there is no need to try to restore the pre-MM
    document, even the visibility. In the end any effort is futile,
    as field changes cannot be undone.
    
    Even worse: it introduced a regression using the "data to fields"
    function from the data source manager (F4), which would never
    set the correct section visibility.
    
    We need to copy the document to prevent changes to the source
    document and skip the quite probably unexpected save in MM.
    
    (cherry picked from commit adb98d94ca1059b56d6b6726ca9aea96ecae8a96)
    
    Conflicts:
    
    	sw/source/uibase/dbui/dbmgr.cxx
    
    Change-Id: I814905f1566a63b2ee14cb5f6d08da34c05942aa

diff --git a/sw/source/ui/dbui/dbmgr.cxx b/sw/source/ui/dbui/dbmgr.cxx
index 0cb48e0..ba5f075 100644
--- a/sw/source/ui/dbui/dbmgr.cxx
+++ b/sw/source/ui/dbui/dbmgr.cxx
@@ -441,11 +441,6 @@ sal_Bool SwNewDBMgr::MergeNew( const SwMergeDescriptor& rMergeDesc )
 
     DELETEZ( pImpl->pMergeData );
 
-    // Recalculate original section visibility states, as field changes aren't
-    // tracked (not undo-able).  Has to be done, after pImpl->pMergeData is
-    //  gone, otherwise merge data is used for calculation!
-    rMergeDesc.rSh.ViewShell::UpdateFlds();
-
     bInMerge = sal_False;
 
     return bRet;
commit 7a6f4af8b8b56c8b07f689dfa5c01e92a5a71b55
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.
    
    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 4e66ef6..c3f97a3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -4348,7 +4348,7 @@ if test "$test_cups" = "yes"; then
     if test "$ac_cv_lib_cups_cupsPrintFiles" != "yes" -a "$ac_cv_header_cups_cups_h" != "yes"; then
         AC_MSG_ERROR([Could not find CUPS. Install libcupsys2-dev or cups-devel.])
     fi
-
+    AC_DEFINE(ENABLE_CUPS)
 else
     AC_MSG_RESULT([no])
 fi
@@ -12066,6 +12066,7 @@ fi
 AC_CONFIG_FILES([config_host.mk Makefile lo.xcent instsetoo_native/util/openoffice.lst])
 AC_CONFIG_HEADERS([config_host/config_buildid.h])
 AC_CONFIG_HEADERS([config_host/config_clang.h])
+AC_CONFIG_HEADERS([config_host/config_cups.h])
 AC_CONFIG_HEADERS([config_host/config_features.h])
 AC_CONFIG_HEADERS([config_host/config_gcc.h])
 AC_CONFIG_HEADERS([config_host/config_global.h])
diff --git a/include/vcl/jobdata.hxx b/include/vcl/jobdata.hxx
index f6fb94f..94c164f 100644
--- a/include/vcl/jobdata.hxx
+++ b/include/vcl/jobdata.hxx
@@ -77,6 +77,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 108b315..d93f43d 100644
--- a/include/vcl/printerinfomanager.hxx
+++ b/include/vcl/printerinfomanager.hxx
@@ -229,6 +229,16 @@ public:
     // gets m_bDisableCUPS, initialized from printer config
     bool isCUPSDisabled() 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/ui/dbui/dbmgr.cxx b/sw/source/ui/dbui/dbmgr.cxx
index 0d269dd..0cb48e0 100644
--- a/sw/source/ui/dbui/dbmgr.cxx
+++ b/sw/source/ui/dbui/dbmgr.cxx
@@ -132,6 +132,9 @@
 #include <calc.hxx>
 #include <dbfld.hxx>
 
+#include <config_cups.h>
+#include <vcl/printerinfomanager.hxx>
+
 using namespace ::osl;
 using namespace ::svx;
 using namespace ::com::sun::star;
@@ -848,6 +851,27 @@ sal_Bool SwNewDBMgr::MergeMailFiles(SwWrtShell* pSourceShell,
     sal_Bool bNoError = sal_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;
@@ -966,7 +990,7 @@ sal_Bool SwNewDBMgr::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 );
@@ -1065,7 +1089,7 @@ sal_Bool SwNewDBMgr::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);
                         String sLeading;
@@ -1115,7 +1139,7 @@ sal_Bool SwNewDBMgr::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
@@ -1155,7 +1179,7 @@ sal_Bool SwNewDBMgr::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
@@ -1214,6 +1238,7 @@ sal_Bool SwNewDBMgr::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
@@ -1243,6 +1268,9 @@ sal_Bool SwNewDBMgr::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;
@@ -1354,7 +1382,7 @@ sal_Bool SwNewDBMgr::MergeMailFiles(SwWrtShell* pSourceShell,
                                     }
                                 }
                             }
-                        if( rMergeDescriptor.bCreateSingleFile )
+                        if( bCreateSingleFile )
                         {
                             pWorkDoc->SetNewDBMgr( pOldDBManager );
                             xWorkDocSh->DoClose();
@@ -1367,7 +1395,7 @@ sal_Bool SwNewDBMgr::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(),
@@ -1377,15 +1405,20 @@ sal_Bool SwNewDBMgr::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->SetNewDBMgr( pOldDBManager );
                 xWorkDocSh->DoClose();
             }
 
-            if (rMergeDescriptor.bCreateSingleFile)
+            if (bCreateSingleFile)
             {
                 // sw::DocumentLayoutManager::CopyLayoutFmt() did not generate
                 // unique fly names, do it here once.
@@ -1397,7 +1430,7 @@ sal_Bool SwNewDBMgr::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();
@@ -1413,7 +1446,7 @@ sal_Bool SwNewDBMgr::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 9a84b77..79c1ae7 100644
--- a/vcl/inc/cupsmgr.hxx
+++ b/vcl/inc/cupsmgr.hxx
@@ -58,6 +58,22 @@ class CUPSManager : public PrinterInfoManager
     osl::Mutex                                                  m_aGetPPDMutex;
     bool                                                        m_bPPDThreadRunning;
 
+    struct PendingJob
+    {
+        OUString printerName;
+        OUString jobTitle;
+        JobData jobData;
+        bool banner;
+        OString file;
+        PendingJob( const OUString& printerName_, const OUString& jobTitle_, const JobData& jobData_,
+            bool banner_, const OString& file_ )
+            : printerName( printerName_ ), jobTitle( jobTitle_ ), jobData( jobData_ ), banner( banner_ ), file( file_ )
+            {}
+        PendingJob() : banner( false ) {}
+    };
+    std::list< PendingJob > pendingJobs;
+    bool batchMode;
+
     CUPSManager();
     virtual ~CUPSManager();
 
@@ -66,6 +82,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:
     // public for stub
     static void runDestThread(void* pMgr);
@@ -81,6 +100,10 @@ public:
     virtual int endSpool( const OUString& rPrinterName, const OUString& rJobTitle, FILE* pFile, const JobData& rDocumentJobData, bool bBanner );
     virtual void setupJobContextData( JobData& rData );
 
+    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 );
 
diff --git a/vcl/unx/generic/printer/cupsmgr.cxx b/vcl/unx/generic/printer/cupsmgr.cxx
index 6b06596..5169d29 100644
--- a/vcl/unx/generic/printer/cupsmgr.cxx
+++ b/vcl/unx/generic/printer/cupsmgr.cxx
@@ -646,8 +646,6 @@ int CUPSManager::endSpool( const OUString& rPrintername, const OUString& rJobTit
                rDocumentJobData.m_nCopies
                );
 
-    int nJobID = 0;
-
     osl::MutexGuard aGuard( m_aCUPSMutex );
 
     boost::unordered_map< OUString, int, OUStringHash >::iterator dest_it =
@@ -659,25 +657,98 @@ int CUPSManager::endSpool( const OUString& rPrintername, const OUString& rJobTit
     }
 
     boost::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, 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 );
-        rtl_TextEncoding aEnc = osl_getThreadTextEncoding();
+        if( !printJobs( currentJobData, files )) // print the last batch
+            ok = false;
+    }
+    return ok;
+}
 
-        // setup cups options
-        int nNumOptions = 0;
-        cups_option_t* pOptions = NULL;
-        getOptionsFromDocumentSetup( rDocumentJobData, bBanner, nNumOptions, (void**)&pOptions );
+bool CUPSManager::printJobs( const PendingJob& job, const std::vector< OString >& files )
+{
+    boost::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( job.jobData, job.banner, nNumOptions, reinterpret_cast<void**>(&pOptions) );
+
+    cups_dest_t* pDest = ((cups_dest_t*)m_pDests) + dest_it->second;
 
-        cups_dest_t* pDest = ((cups_dest_t*)m_pDests) + dest_it->second;
-        nJobID = cupsPrintFile( pDest->name,
-        it->second.getStr(),
-        OUStringToOString( rJobTitle, aEnc ).getStr(),
-        nNumOptions, pOptions );
+    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(),
+            OUStringToOString( job.jobTitle, aEnc ).getStr(),
+            nNumOptions, pOptions);
 #if OSL_DEBUG_LEVEL > 1
         fprintf( stderr, "cupsPrintFile( %s, %s, %s, %d, %p ) returns %d\n",
                     pDest->name,
-                    it->second.getStr(),
+                    ( fnames.size() == 1 ? files.front() : OString::number( fnames.size()) ).getStr(),
                     OUStringToOString( rJobTitle, aEnc ).getStr(),
                     nNumOptions,
                     pOptions,
@@ -691,11 +762,13 @@ int CUPSManager::endSpool( const OUString& rPrintername, const OUString& rJobTit
         system( aCmd.getStr() );
 #endif
 
-        unlink( it->second.getStr() );
-        m_aSpoolFiles.erase( pFile );
-        if( pOptions )
-            cupsFreeOptions( nNumOptions, pOptions );
-    }
+    for( std::vector< OString >::const_iterator it = files.begin();
+         it != files.end();
+         ++it )
+        unlink( it->getStr());
+
+    if( pOptions )
+        cupsFreeOptions( nNumOptions, pOptions );
 
     return nJobID;
 }
diff --git a/vcl/unx/generic/printer/jobdata.cxx b/vcl/unx/generic/printer/jobdata.cxx
index d40fffd..16adb96 100644
--- a/vcl/unx/generic/printer/jobdata.cxx
+++ b/vcl/unx/generic/printer/jobdata.cxx
@@ -52,6 +52,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 )
 {
     const PPDParser* pParser = m_aContext.getParser();
diff --git a/vcl/unx/generic/printer/printerinfomanager.cxx b/vcl/unx/generic/printer/printerinfomanager.cxx
index 7def80f..b895f82 100644
--- a/vcl/unx/generic/printer/printerinfomanager.cxx
+++ b/vcl/unx/generic/printer/printerinfomanager.cxx
@@ -1180,6 +1180,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 b27863c5f0e490685552a76735cc136c31b30336
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.
    
    Change-Id: I4d17c703b3220f47609fc4b054ce048b299a0c92

diff --git a/include/sfx2/viewsh.hxx b/include/sfx2/viewsh.hxx
index ad4c64c..57d067d 100644
--- a/include/sfx2/viewsh.hxx
+++ b/include/sfx2/viewsh.hxx
@@ -36,6 +36,7 @@
 #include <tools/errcode.hxx>
 #include <vcl/jobset.hxx>
 #include <vector>
+#include <boost/shared_ptr.hpp>
 
 class SfxBaseController;
 class Size;
@@ -59,6 +60,7 @@ class SfxFrameItem;
 class Dialog;
 class Menu;
 class NotifyEvent;
+namespace vcl { class PrinterController; }
 
 #define SFX_PRINTER_PRINTER               1  // without JOB SETUP => Temporary
 #define SFX_PRINTER_JOBSETUP         2
@@ -257,6 +259,9 @@ public:
     sal_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 >&, sal_Bool, sal_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 );
+    boost::shared_ptr< vcl::PrinterController > GetPrinterController() const;
 
     void                        AddRemoveClipboardListener( const com::sun::star::uno::Reference < com::sun::star::datatransfer::clipboard::XClipboardListener>&, sal_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 40997dd..9ab7344 100644
--- a/include/vcl/print.hxx
+++ b/include/vcl/print.hxx
@@ -373,9 +373,16 @@ public:
                           const JobSetup& i_rInitSetup
                           );
 
+    // 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( boost::shared_ptr<vcl::PrinterController> i_pController,
+                                        const JobSetup& i_rInitSetup );
+    static bool                 ExecutePrintJob( boost::shared_ptr<vcl::PrinterController> i_pController );
+    static void                 FinishPrintJob( boost::shared_ptr<vcl::PrinterController> i_pController );
+
     // implementation detail of PrintJob being asynchronous
     // not exported, not usable outside vcl
-    static void SAL_DLLPRIVATE ImplPrintJob( const boost::shared_ptr<vcl::PrinterController>& i_pController,
+    static void SAL_DLLPRIVATE ImplPrintJob( boost::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 251dbb0..27b720d 100644
--- a/sfx2/source/view/viewprn.cxx
+++ b/sfx2/source/view/viewprn.cxx
@@ -579,8 +579,10 @@ SfxPrinter* SfxViewShell::SetPrinter_Impl( SfxPrinter *pNewPrinter )
     return pDocPrinter;
 }
 
-void SfxViewShell::ExecPrint( const uno::Sequence < beans::PropertyValue >& rProps, sal_Bool bIsAPI, sal_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 );
@@ -622,7 +624,11 @@ void SfxViewShell::ExecPrint( const uno::Sequence < beans::PropertyValue >& rPro
     SfxObjectShell *pObjShell = GetObjectShell();
     pController->setValue( OUString( "JobName"  ),
                         makeAny( OUString( pObjShell->GetTitle(0) ) ) );
+}
 
+void SfxViewShell::ExecPrint( const uno::Sequence < beans::PropertyValue >& rProps, sal_Bool bIsAPI, sal_Bool bIsDirect )
+{
+    StartPrint( rProps, bIsAPI, bIsDirect );
     // FIXME: job setup
     SfxPrinter* pDocPrt = GetPrinter(sal_False);
     JobSetup aJobSetup = pDocPrt ? pDocPrt->GetJobSetup() : GetJobSetup();
@@ -630,7 +636,12 @@ void SfxViewShell::ExecPrint( const uno::Sequence < beans::PropertyValue >& rPro
         aJobSetup.SetValue( String( "IsQuickJob"  ),
                             String( "true"  ) );
 
-    Printer::PrintJob( pController, aJobSetup );
+    Printer::PrintJob( GetPrinterController(), aJobSetup );
+}
+
+boost::shared_ptr< vcl::PrinterController > SfxViewShell::GetPrinterController() const
+{
+    return pImp->m_pPrinterController;
 }
 
 Printer* SfxViewShell::GetActivePrinter() const
diff --git a/sw/source/ui/dbui/dbmgr.cxx b/sw/source/ui/dbui/dbmgr.cxx
index 790504e..0d269dd 100644
--- a/sw/source/ui/dbui/dbmgr.cxx
+++ b/sw/source/ui/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>
@@ -1211,6 +1212,41 @@ sal_Bool SwNewDBMgr::MergeMailFiles(SwWrtShell* pSourceShell,
                                     rMergeDescriptor.pMailMergeConfigItem->AddMergedDocument( aMergeInfo );
                                 }
                             }
+                        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
                             {
                                 assert( createTempFile );
@@ -1343,6 +1379,8 @@ sal_Bool SwNewDBMgr::MergeMailFiles(SwWrtShell* pSourceShell,
 
             if( !rMergeDescriptor.bCreateSingleFile )
             {
+                if( rMergeDescriptor.nMergeType == DBMGR_MERGE_PRINTER )
+                    Printer::FinishPrintJob( pWorkView->GetPrinterController());
                 pWorkDoc->SetNewDBMgr( pOldDBManager );
                 xWorkDocSh->DoClose();
             }
@@ -2702,7 +2740,7 @@ void SwNewDBMgr::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/ui/uno/unomailmerge.cxx b/sw/source/ui/uno/unomailmerge.cxx
index c58e1dd..bffd112 100644
--- a/sw/source/ui/uno/unomailmerge.cxx
+++ b/sw/source/ui/uno/unomailmerge.cxx
@@ -718,7 +718,7 @@ uno::Any SAL_CALL SwXMailMerge::execute(
             // when mail merge is called as command line macro
             aMergeDesc.bPrintAsync = sal_False;
             aMergeDesc.aPrintOptions = aPrintSettings;
-            aMergeDesc.bCreateSingleFile = sal_True;
+            aMergeDesc.bCreateSingleFile = sal_False;
         }
         break;
     case MailMergeType::SHELL:
diff --git a/vcl/source/gdi/print3.cxx b/vcl/source/gdi/print3.cxx
index e20c79e..9e02d2d 100644
--- a/vcl/source/gdi/print3.cxx
+++ b/vcl/source/gdi/print3.cxx
@@ -299,12 +299,10 @@ void Printer::PrintJob( const boost::shared_ptr<PrinterController>& i_pControlle
     }
 }
 
-void Printer::ImplPrintJob( const boost::shared_ptr<PrinterController>& i_pController,
+void Printer::PreparePrintJob( boost::shared_ptr<PrinterController> pController,
                             const JobSetup& i_rInitSetup
                             )
 {
-    boost::shared_ptr<PrinterController> pController( i_pController );
-
     // check if there is a default printer; if not, show an error box (if appropriate)
     if( GetDefaultPrinterName().isEmpty() )
     {
@@ -332,7 +330,7 @@ void Printer::ImplPrintJob( const boost::shared_ptr<PrinterController>& i_pContr
     }
 
     // reset last page property
-    i_pController->setLastPage( sal_False );
+    pController->setLastPage( sal_False );
 
     // update "PageRange" property inferring from other properties:
     // case 1: "Pages" set from UNO API ->
@@ -344,12 +342,12 @@ void Printer::ImplPrintJob( const boost::shared_ptr<PrinterController>& i_pContr
     // "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
-    beans::PropertyValue* pContentVal = i_pController->getValue( OUString( "PrintRange" ) );
+    beans::PropertyValue* pContentVal = pController->getValue( OUString( "PrintRange" ) );
     if( ! pContentVal )
-        pContentVal = i_pController->getValue( OUString( "PrintContent" ) );
+        pContentVal = pController->getValue( OUString( "PrintContent" ) );
 
     // case 1: UNO API has set "Pages"
-    beans::PropertyValue* pPagesVal = i_pController->getValue( OUString( "Pages" ) );
+    beans::PropertyValue* pPagesVal = pController->getValue( OUString( "Pages" ) );
     if( pPagesVal )
     {
         OUString aPagesVal;
@@ -362,7 +360,7 @@ void Printer::ImplPrintJob( const boost::shared_ptr<PrinterController>& i_pContr
             if( pContentVal )
             {
                 pContentVal->Value = makeAny( sal_Int32( 1 ) );
-                i_pController->setValue( OUString( "PageRange" ), pPagesVal->Value );
+                pController->setValue( OUString( "PageRange" ), pPagesVal->Value );
             }
         }
     }
@@ -375,13 +373,13 @@ void Printer::ImplPrintJob( const boost::shared_ptr<PrinterController>& i_pContr
             if( nContent == 0 )
             {
                 // do not overwrite PageRange if it is already set
-                beans::PropertyValue* pRangeVal = i_pController->getValue( OUString( "PageRange" ) );
+                beans::PropertyValue* pRangeVal = pController->getValue( OUString( "PageRange" ) );
                 OUString aRange;
                 if( pRangeVal )
                     pRangeVal->Value >>= aRange;
                 if( aRange.isEmpty() )
                 {
-                    sal_Int32 nPages = i_pController->getPageCount();
+                    sal_Int32 nPages = pController->getPageCount();
                     if( nPages > 0 )
                     {
                         OUStringBuffer aBuf( 32 );
@@ -391,14 +389,14 @@ void Printer::ImplPrintJob( const boost::shared_ptr<PrinterController>& i_pContr
                             aBuf.appendAscii( "-" );
                             aBuf.append( nPages );
                         }
-                        i_pController->setValue( OUString( "PageRange" ), makeAny( aBuf.makeStringAndClear() ) );
+                        pController->setValue( OUString( "PageRange" ), makeAny( aBuf.makeStringAndClear() ) );
                     }
                 }
             }
         }
     }
 
-    beans::PropertyValue* pReverseVal = i_pController->getValue( OUString( "PrintReverse" ) );
+    beans::PropertyValue* pReverseVal = pController->getValue( OUString( "PrintReverse" ) );
     if( pReverseVal )
     {
         sal_Bool bReverse = sal_False;
@@ -406,7 +404,7 @@ void Printer::ImplPrintJob( const boost::shared_ptr<PrinterController>& i_pContr
         pController->setReversePrint( bReverse );
     }
 
-    beans::PropertyValue* pPapersizeFromSetupVal = i_pController->getValue( OUString( "PapersizeFromSetup" ) );
+    beans::PropertyValue* pPapersizeFromSetupVal = pController->getValue( OUString( "PapersizeFromSetup" ) );
     if( pPapersizeFromSetupVal )
     {
         sal_Bool bPapersizeFromSetup = sal_False;
@@ -415,35 +413,35 @@ void Printer::ImplPrintJob( const boost::shared_ptr<PrinterController>& i_pContr
     }
 
     // setup NUp printing from properties
-    sal_Int32 nRows = i_pController->getIntProperty( OUString( "NUpRows" ), 1 );
-    sal_Int32 nCols = i_pController->getIntProperty( OUString( "NUpColumns" ), 1 );
+    sal_Int32 nRows = pController->getIntProperty( OUString( "NUpRows" ), 1 );
+    sal_Int32 nCols = pController->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_pController->getIntProperty( OUString( "NUpPageMarginLeft" ), aMPS.nLeftMargin );
+        sal_Int32 nValue = pController->getIntProperty( OUString( "NUpPageMarginLeft" ), aMPS.nLeftMargin );
         if( nValue >= 0 )
             aMPS.nLeftMargin = nValue;
-        nValue = i_pController->getIntProperty( OUString( "NUpPageMarginRight" ), aMPS.nRightMargin );
+        nValue = pController->getIntProperty( OUString( "NUpPageMarginRight" ), aMPS.nRightMargin );
         if( nValue >= 0 )
             aMPS.nRightMargin = nValue;
-        nValue = i_pController->getIntProperty( OUString( "NUpPageMarginTop" ), aMPS.nTopMargin );
+        nValue = pController->getIntProperty( OUString( "NUpPageMarginTop" ), aMPS.nTopMargin );
         if( nValue >= 0 )
             aMPS.nTopMargin = nValue;
-        nValue = i_pController->getIntProperty( OUString( "NUpPageMarginBottom" ), aMPS.nBottomMargin );
+        nValue = pController->getIntProperty( OUString( "NUpPageMarginBottom" ), aMPS.nBottomMargin );
         if( nValue >= 0 )
             aMPS.nBottomMargin = nValue;
-        nValue = i_pController->getIntProperty( OUString( "NUpHorizontalSpacing" ), aMPS.nHorizontalSpacing );
+        nValue = pController->getIntProperty( OUString( "NUpHorizontalSpacing" ), aMPS.nHorizontalSpacing );
         if( nValue >= 0 )
             aMPS.nHorizontalSpacing = nValue;
-        nValue = i_pController->getIntProperty( OUString( "NUpVerticalSpacing" ), aMPS.nVerticalSpacing );
+        nValue = pController->getIntProperty( OUString( "NUpVerticalSpacing" ), aMPS.nVerticalSpacing );
         if( nValue >= 0 )
             aMPS.nVerticalSpacing = nValue;
-        aMPS.bDrawBorder = i_pController->getBoolProperty( OUString( "NUpDrawBorder" ), aMPS.bDrawBorder );
-        aMPS.nOrder = static_cast<PrinterController::NupOrderType>(i_pController->getIntProperty( OUString( "NUpSubPageOrder" ), aMPS.nOrder ));
-        aMPS.aPaperSize = i_pController->getPrinter()->PixelToLogic( i_pController->getPrinter()->GetPaperSizePixel(), MapMode( MAP_100TH_MM ) );
-        beans::PropertyValue* pPgSizeVal = i_pController->getValue( OUString( "NUpPaperSize" ) );
+        aMPS.bDrawBorder = pController->getBoolProperty( OUString( "NUpDrawBorder" ), aMPS.bDrawBorder );
+        aMPS.nOrder = static_cast<PrinterController::NupOrderType>(pController->getIntProperty( OUString( "NUpSubPageOrder" ), aMPS.nOrder ));
+        aMPS.aPaperSize = pController->getPrinter()->PixelToLogic( pController->getPrinter()->GetPaperSizePixel(), MapMode( MAP_100TH_MM ) );
+        beans::PropertyValue* pPgSizeVal = pController->getValue( OUString( "NUpPaperSize" ) );
         awt::Size aSizeVal;
         if( pPgSizeVal && (pPgSizeVal->Value >>= aSizeVal) )
         {
@@ -451,7 +449,7 @@ void Printer::ImplPrintJob( const boost::shared_ptr<PrinterController>& i_pContr
             aMPS.aPaperSize.Height() = aSizeVal.Height;
         }
 
-        i_pController->setMultipage( aMPS );
+        pController->setMultipage( aMPS );
     }
 
     // in direct print case check whether there is anything to print.
@@ -475,10 +473,10 @@ void Printer::ImplPrintJob( const boost::shared_ptr<PrinterController>& i_pContr
     {
         try
         {
-            PrintDialog aDlg( NULL, i_pController );
+            PrintDialog aDlg( NULL, pController );
             if( ! aDlg.Execute() )
             {
-                i_pController->abortJob();
+                pController->abortJob();
                 return;
             }
             if( aDlg.isPrintToFile() )
@@ -486,7 +484,7 @@ void Printer::ImplPrintJob( const boost::shared_ptr<PrinterController>& i_pContr
                 OUString aFile = queryFile( pController->getPrinter().get() );
                 if( aFile.isEmpty() )
                 {
-                    i_pController->abortJob();
+                    pController->abortJob();
                     return;
                 }
                 pController->setValue( OUString( "LocalFileName" ),
@@ -504,19 +502,32 @@ void Printer::ImplPrintJob( const boost::shared_ptr<PrinterController>& i_pContr
     }
 
     pController->pushPropertiesToPrinter();
+}
 
+bool Printer::ExecutePrintJob(boost::shared_ptr<PrinterController> pController)
+{
     OUString aJobName;
     beans::PropertyValue* pJobNameVal = pController->getValue( OUString( "JobName" ) );
     if( pJobNameVal )
         pJobNameVal->Value >>= aJobName;
 
-    pController->getPrinter()->StartJob( String( aJobName ), pController );
+    return pController->getPrinter()->StartJob( aJobName, pController );
+}
 
+void Printer::FinishPrintJob(boost::shared_ptr<PrinterController> pController)
+{
     pController->resetPaperToLastConfigured();
-
     pController->jobFinished( pController->getJobState() );
 }
 
+void Printer::ImplPrintJob(boost::shared_ptr<PrinterController> xController,
+                           const JobSetup& i_rInitSetup)
+{
+    PreparePrintJob( xController, i_rInitSetup );
+    ExecutePrintJob( xController );
+    FinishPrintJob( xController );
+}
+
 bool Printer::StartJob( const OUString& i_rJobName, boost::shared_ptr<vcl::PrinterController>& i_pController )
 {
     mnError = PRINTER_OK;
commit 13c533a272ed225a599788ed7bef87a3655ac7c3
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.
    
    Change-Id: I839ffe56a835f99c2812cffb60804b74aaa9c5ac

diff --git a/sw/source/ui/inc/view.hxx b/sw/source/ui/inc/view.hxx
index 056ae0d..4a42580 100644
--- a/sw/source/ui/inc/view.hxx
+++ b/sw/source/ui/inc/view.hxx
@@ -336,11 +336,6 @@ class SW_DLLPUBLIC SwView: public SfxViewShell
     SW_DLLPRIVATE void          SpellKontext(sal_Bool bOn = sal_True)
                             { m_bCenterCrsr = bOn; m_bAlwaysShowSel = bOn; }
 
-    // methods for printing
-    SW_DLLPRIVATE virtual   SfxPrinter*     GetPrinter( sal_Bool bCreate = sal_False );
-    SW_DLLPRIVATE virtual bool  HasPrintOptionsPage() const;
-    SW_DLLPRIVATE virtual SfxTabPage*       CreatePrintOptionsPage( Window* pParent,
-                                                    const SfxItemSet& rSet);
     // for readonly switching
     SW_DLLPRIVATE virtual void  Notify( SfxBroadcaster& rBC, const SfxHint& rHint );
     SW_DLLPRIVATE void          _CheckReadonlyState();
@@ -663,6 +658,12 @@ public:
     void UpdateDocStats();
     /// Where is the real cursor: in the annotation or in the main document?
     void SetAnnotationMode(bool bMode);
+
+    // methods for printing
+    SW_DLLPRIVATE virtual   SfxPrinter*     GetPrinter( sal_Bool bCreate = sal_False );
+    SW_DLLPRIVATE virtual bool  HasPrintOptionsPage() const;
+    SW_DLLPRIVATE virtual SfxTabPage*       CreatePrintOptionsPage( Window* pParent,
+                                                    const SfxItemSet& rSet);
 };
 
 // ----------------- inline Methoden ----------------------
commit 70d71ccbcabbd089bcadf246feac4a6028ba7d57
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.
    
    Change-Id: If02cf8aca1d0f050ffb63cd85d5a9455afc5a6ea

diff --git a/sw/source/ui/dbui/dbmgr.cxx b/sw/source/ui/dbui/dbmgr.cxx
index b532c4e..790504e 100644
--- a/sw/source/ui/dbui/dbmgr.cxx
+++ b/sw/source/ui/dbui/dbmgr.cxx
@@ -1037,6 +1037,14 @@ sal_Bool SwNewDBMgr::MergeMailFiles(SwWrtShell* pSourceShell,
             bool bFreezedLayouts = false;
             // collect temporary files
             ::std::vector< String> 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;
+            SwNewDBMgr* pOldDBManager = NULL;
+
             do
             {
                 nStartRow = pImpl->pMergeData ? pImpl->pMergeData->xResultSet->getRow() : 0;
@@ -1103,21 +1111,26 @@ sal_Bool SwNewDBMgr::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();
                             lcl_CopyDocumentPorperties( xSourceDocProps, xWorkDocSh, pWorkDoc );
                             if ( (nMaxDumpDocs < 0) || (nDocNo <= nMaxDumpDocs) )
                                 lcl_SaveDoc( xWorkDocSh, "WorkDoc", nDocNo );
-                            SwNewDBMgr* pOldDBMgr = pWorkDoc->GetNewDBMgr();
+                            pOldDBManager = pWorkDoc->GetNewDBMgr();
                             pWorkDoc->SetNewDBMgr( this );
                             pWorkDoc->EmbedAllLinks();
 
@@ -1125,13 +1138,13 @@ sal_Bool SwNewDBMgr::MergeMailFiles(SwWrtShell* pSourceShell,
                             rWorkShell.LockExpFlds();
                             rWorkShell.CalcLayout();
                             rWorkShell.UnlockExpFlds();
+                        }
 
+                            SwWrtShell& rWorkShell = pWorkView->GetWrtShell();
                             SFX_APP()->NotifyEvent(SfxEventHint(SW_EVENT_FIELD_MERGE, SwDocShell::GetEventName(STR_SW_EVENT_FIELD_MERGE), xWorkDocSh));
                             rWorkShell.ViewShell::UpdateFlds();
                             SFX_APP()->NotifyEvent(SfxEventHint(SW_EVENT_FIELD_MERGE_FINISHED, SwDocShell::GetEventName(STR_SW_EVENT_FIELD_MERGE_FINISHED), xWorkDocSh));
 
-                            pWorkDoc->RemoveInvisibleContent();
-
                             // launch MailMergeEvent if required
                             const SwXMailMerge *pEvtSrc = GetMailMergeEvtSrc();
                             if(pEvtSrc)
@@ -1145,6 +1158,7 @@ sal_Bool SwNewDBMgr::MergeMailFiles(SwWrtShell* pSourceShell,
                             {
                                 OSL_ENSURE( pTargetShell, "no target shell available!" );
                                 // copy created file into the target document
+                                pWorkDoc->RemoveInvisibleContent();
                                 rWorkShell.ConvertFieldsToText();
                                 rWorkShell.SetNumberingRestart();
                                 if( bSynchronizedDoc )
@@ -1304,9 +1318,12 @@ sal_Bool SwNewDBMgr::MergeMailFiles(SwWrtShell* pSourceShell,
                                     }
                                 }
                             }
-                            pWorkDoc->SetNewDBMgr( pOldDBMgr );
-
-                        xWorkDocSh->DoClose();
+                        if( rMergeDescriptor.bCreateSingleFile )
+                        {
+                            pWorkDoc->SetNewDBMgr( pOldDBManager );
+                            xWorkDocSh->DoClose();
+                            xWorkDocSh = NULL;
+                        }
                     }
                 }
                 nDocNo++;
@@ -1323,6 +1340,13 @@ sal_Bool SwNewDBMgr::MergeMailFiles(SwWrtShell* pSourceShell,
                 }
             } while( !bCancel &&
                 (bSynchronizedDoc && (nStartRow != nEndRow)? ExistsNextRecord() : ToNextMergeRecord()));
+
+            if( !rMergeDescriptor.bCreateSingleFile )
+            {
+                pWorkDoc->SetNewDBMgr( pOldDBManager );
+                xWorkDocSh->DoClose();
+            }
+
             if (rMergeDescriptor.bCreateSingleFile)
             {
                 // sw::DocumentLayoutManager::CopyLayoutFmt() did not generate
commit b05ef2159fa07e97c15c02f53c3a705e5c340934
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
    
    Change-Id: I1360e215bff42dd866ab1d94a18a8f2f9ddc7c66

diff --git a/sw/source/ui/dbui/dbmgr.cxx b/sw/source/ui/dbui/dbmgr.cxx
index 0c4cfeb..b532c4e 100644
--- a/sw/source/ui/dbui/dbmgr.cxx
+++ b/sw/source/ui/dbui/dbmgr.cxx
@@ -941,6 +941,7 @@ sal_Bool SwNewDBMgr::MergeMailFiles(SwWrtShell* pSourceShell,
 
             SwView* pTargetView = 0;
             std::auto_ptr< utl::TempFile > aTempFile;
+            bool createTempFile = ( rMergeDescriptor.nMergeType == DBMGR_MERGE_EMAIL || rMergeDescriptor.nMergeType == DBMGR_MERGE_FILE );
             String sModifiedStartingPageDesc;
             String sStartingPageDesc;
             sal_uInt16 nStartingPageNo = 0;
@@ -1055,7 +1056,7 @@ sal_Bool SwNewDBMgr::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);
                         String sLeading;
@@ -1071,23 +1072,25 @@ sal_Bool SwNewDBMgr::MergeMailFiles(SwWrtShell* pSourceShell,
                                 new utl::TempFile(sLeading,&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 = sal_False;
-                        bCancel = sal_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 )
                                 ((CreateMonitor*) pProgressDlg)->SetCurrentPosition( nDocNo );
                             else {
                                 PrintMonitor *pPrintMonDlg = (PrintMonitor*) pProgressDlg;
-                                pPrintMonDlg->aPrinter.SetText( aTempFileURL.GetBase() );
+                                pPrintMonDlg->aPrinter.SetText( createTempFile ? aTempFileURL->GetBase() : OUString( pSourceDocSh->GetTitle( 22 )));
                                 OUString sStat(SW_RES(STR_STATSTR_LETTER));   // Brief
                                 sStat += " ";
                                 sStat += OUString::number( nDocNo );
@@ -1196,7 +1199,8 @@ sal_Bool SwNewDBMgr::MergeMailFiles(SwWrtShell* pSourceShell,
                             }
                             else
                             {
-                                String sFileURL =  aTempFileURL.GetMainURL( INetURLObject::NO_DECODE );
+                                assert( createTempFile );
+                                String sFileURL =  aTempFileURL->GetMainURL( INetURLObject::NO_DECODE );
                                 SfxMedium* pDstMed = new SfxMedium(
                                     sFileURL,
                                     STREAM_STD_READWRITE );
@@ -1351,7 +1355,7 @@ sal_Bool SwNewDBMgr::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 ),
commit 6a568ab6c711cf881867245807a0d1051d65a3a5
Author: Jan-Marek Glogowski <glogow at fbihome.de>
Date:   Mon Feb 23 12:56:25 2015 +0100

    KDE4: improve default load and save dialog titles
    
    Switches from STR_SVT_FILEPICKER_ to STR_FPICKER_ resource IDs and
    uses the default resource manager (ImplGetResMgr).
    
    The STR_FPICKER_ IDs contain default translated titles for the open
    and save dialogs, which KDE4 dialogs are currently missing.
    
    Actually I want 'Save as' instead of 'Save'... but it's better
    then the current - empty - default.
    
    (cherry picked from commit b613270a730ace29dd1b16b29be2222b34f34a5d)
    
    Conflicts:
    
    	vcl/unx/kde4/KDE4FilePicker.cxx
    
    Change-Id: Ia43774ea66a96838f53cf6614a264d9c6a94c501

diff --git a/vcl/unx/kde4/KDE4FilePicker.cxx b/vcl/unx/kde4/KDE4FilePicker.cxx
index 96c856b..f8b2fc2 100644
--- a/vcl/unx/kde4/KDE4FilePicker.cxx
+++ b/vcl/unx/kde4/KDE4FilePicker.cxx
@@ -57,6 +57,8 @@
 
 #include "generic/geninst.h"
 
+#include "svids.hrc"
+
 using namespace ::com::sun::star;
 using namespace ::com::sun::star::ui::dialogs;
 using namespace ::com::sun::star::ui::dialogs::TemplateDescription;
@@ -105,7 +107,6 @@ QString toQString(const OUString& s)
 
 KDE4FilePicker::KDE4FilePicker( const uno::Reference<uno::XComponentContext>& )
     : KDE4FilePicker_Base(_helperMutex)
-    , _resMgr( ResMgr::CreateResMgr("fps_office") )
 {
     _extraControls = new QWidget();
     _layout = new QGridLayout(_extraControls);
@@ -184,7 +185,6 @@ void KDE4FilePicker::cleanupProxy()
         SalYieldMutexReleaser aReleaser;
         return Q_EMIT cleanupProxySignal();
     }
-    delete _resMgr;
     delete _dialog;
 }
 
@@ -496,6 +496,24 @@ OUString SAL_CALL KDE4FilePicker::getLabel(sal_Int16 controlId)
     return toOUString(label);
 }
 
+QString KDE4FilePicker::getResString( sal_Int16 aRedId )
+{
+    QString aResString;
+
+    if( aRedId < 0 )
+        return aResString;
+
+    try
+    {
+        aResString = toQString(String(ResId( aRedId, *ImplGetResMgr() )));
+    }
+    catch(...)
+    {
+    }
+
+    return aResString.replace('~', '&');
+}
+
 void KDE4FilePicker::addCustomControl(sal_Int16 controlId)
 {
     QWidget* widget = 0;
@@ -504,37 +522,37 @@ void KDE4FilePicker::addCustomControl(sal_Int16 controlId)
     switch (controlId)
     {
         case CHECKBOX_AUTOEXTENSION:
-            resId = STR_SVT_FILEPICKER_AUTO_EXTENSION;
+            resId = STR_FPICKER_AUTO_EXTENSION;
             break;
         case CHECKBOX_PASSWORD:
-            resId = STR_SVT_FILEPICKER_PASSWORD;
+            resId = STR_FPICKER_PASSWORD;
             break;
         case CHECKBOX_FILTEROPTIONS:
-            resId = STR_SVT_FILEPICKER_FILTER_OPTIONS;
+            resId = STR_FPICKER_FILTER_OPTIONS;
             break;
         case CHECKBOX_READONLY:
-            resId = STR_SVT_FILEPICKER_READONLY;
+            resId = STR_FPICKER_READONLY;
             break;
         case CHECKBOX_LINK:
-            resId = STR_SVT_FILEPICKER_INSERT_AS_LINK;
+            resId = STR_FPICKER_INSERT_AS_LINK;
             break;
         case CHECKBOX_PREVIEW:
-            resId = STR_SVT_FILEPICKER_SHOW_PREVIEW;
+            resId = STR_FPICKER_SHOW_PREVIEW;
             break;
         case CHECKBOX_SELECTION:
-            resId = STR_SVT_FILEPICKER_SELECTION;
+            resId = STR_FPICKER_SELECTION;
             break;
         case PUSHBUTTON_PLAY:
-            resId = STR_SVT_FILEPICKER_PLAY;
+            resId = STR_FPICKER_PLAY;
             break;
         case LISTBOX_VERSION:
-            resId = STR_SVT_FILEPICKER_VERSION;
+            resId = STR_FPICKER_VERSION;
             break;
         case LISTBOX_TEMPLATE:
-            resId = STR_SVT_FILEPICKER_TEMPLATES;
+            resId = STR_FPICKER_TEMPLATES;
             break;
         case LISTBOX_IMAGE_TEMPLATE:
-            resId = STR_SVT_FILEPICKER_IMAGE_TEMPLATE;
+            resId = STR_FPICKER_IMAGE_TEMPLATE;
             break;
         case LISTBOX_VERSION_LABEL:
         case LISTBOX_TEMPLATE_LABEL:
@@ -553,16 +571,7 @@ void KDE4FilePicker::addCustomControl(sal_Int16 controlId)
         case CHECKBOX_PREVIEW:
         case CHECKBOX_SELECTION:
         {
-            QString label;
-
-            if (_resMgr && resId != -1)
-            {
-                OUString s = String(ResId( resId, *_resMgr ));
-                label = toQString(s);
-                label.replace("~", "&");
-            }
-
-            widget = new QCheckBox(label, _extraControls);
+            widget = new QCheckBox(getResString(resId), _extraControls);
 
             // the checkbox is created even for CHECKBOX_AUTOEXTENSION to simplify
             // code, but the checkbox is hidden and ignored
@@ -692,6 +701,21 @@ void SAL_CALL KDE4FilePicker::initialize( const uno::Sequence<uno::Any> &args )
     }
 
     _dialog->setOperationMode( operationMode );
+
+    sal_Int16 resId = -1;
+    switch (_dialog->operationMode())
+    {
+    case KFileDialog::Opening:
+        resId = STR_FPICKER_OPEN;
+        break;
+    case KFileDialog::Saving:
+        resId = STR_FPICKER_SAVE;
+        break;
+    default:
+        break;
+    }
+
+    _dialog->setCaption(getResString(resId));
 }
 
 void SAL_CALL KDE4FilePicker::cancel()
diff --git a/vcl/unx/kde4/KDE4FilePicker.hxx b/vcl/unx/kde4/KDE4FilePicker.hxx
index 8b7b53e..b746191 100644
--- a/vcl/unx/kde4/KDE4FilePicker.hxx
+++ b/vcl/unx/kde4/KDE4FilePicker.hxx
@@ -41,8 +41,6 @@ class KFileDialog;
 class QWidget;
 class QLayout;
 
-class ResMgr;
-
 typedef ::cppu::WeakComponentImplHelper5
 <   ::com::sun::star::ui::dialogs::XFilePicker2
 ,   ::com::sun::star::ui::dialogs::XFilePicker3
@@ -61,8 +59,6 @@ protected:
 
     ::com::sun::star::uno::Reference< ::com::sun::star::ui::dialogs::XFilePickerListener > m_xListener;
 
-    ResMgr *_resMgr;
-
     //the dialog to display
     KFileDialog* _dialog;
 
@@ -221,6 +217,8 @@ private:
     //add a custom control widget to the file dialog
     void addCustomControl(sal_Int16 controlId);
 
+    QString getResString( sal_Int16 aRedId );
+
 private Q_SLOTS:
     void cleanupProxy();
 
commit 4e80faebe1cf0fdd4a7c39d2bedc46db411aa650
Author: Jan-Marek Glogowski <glogow at fbihome.de>
Date:   Mon Feb 23 11:27:03 2015 +0100

    KDE4: actually apply file dialog operation mode
    
    The operationMode can just be set once after the dialog has been
    created. So this moves the call into the initialize function, which
    actually knows the dialog type, in comparison to the constructor.
    
    The "default" constructor setting, resulted in the missing
    "New folder" icon and probably other settings, as all dialogs were
    actually "Opening" dialogs.
    
    (cherry picked from commit 6fc55b9abd783b624241d56e34751ea495adbd7d)
    
    Conflicts:
    
    	vcl/unx/kde4/KDE4FilePicker.cxx
    
    Change-Id: I470052e7c7cbb8e369e226a81b80de3728068c49

diff --git a/vcl/unx/kde4/KDE4FilePicker.cxx b/vcl/unx/kde4/KDE4FilePicker.cxx
index 019760b..96c856b 100644
--- a/vcl/unx/kde4/KDE4FilePicker.cxx
+++ b/vcl/unx/kde4/KDE4FilePicker.cxx
@@ -113,8 +113,7 @@ KDE4FilePicker::KDE4FilePicker( const uno::Reference<uno::XComponentContext>& )
     _dialog = new KFileDialog(KUrl("~"), QString(""), 0, _extraControls);
     _dialog->setMode(KFile::File | KFile::LocalOnly);
 
-    //default mode
-    _dialog->setOperationMode(KFileDialog::Opening);
+    _dialog->setConfirmOverwrite( true );
 
     // XExecutableDialog functions
     connect( this, SIGNAL( setTitleSignal( const OUString & ) ),
@@ -692,8 +691,7 @@ void SAL_CALL KDE4FilePicker::initialize( const uno::Sequence<uno::Any> &args )
                     1 );
     }
 
-    _dialog->setOperationMode(operationMode);
-    _dialog->setConfirmOverwrite(true);
+    _dialog->setOperationMode( operationMode );
 }
 
 void SAL_CALL KDE4FilePicker::cancel()
commit 75055ee27ffb0dbd45b915d720ea14ab2b1a27dd
Author: Jan-Marek Glogowski <glogow at fbihome.de>
Date:   Wed Oct 29 16:04:47 2014 +0100

    MM: don't read column content twice to fill SwCalc
    
    Currently we fill the SwCalc dict twice via lcl_GetColumnCnt and
    GetMergeColumnCnt.
    
    This also drops the unused nFmt argument from GetMergeColumnCnt.
    
    (cherry picked from commit 585bcac8eaa27396ea749a7bdb66abf62fc60335)
    
    Conflicts:
    
    	sw/inc/dbmgr.hxx
    	sw/source/core/fields/docufld.cxx
    	sw/source/uibase/dbui/dbmgr.cxx
    
    Change-Id: I2f7fd1578353e919209002c0c3040adc14b08528

diff --git a/sw/inc/dbmgr.hxx b/sw/inc/dbmgr.hxx
index 0f5493c..c094021 100644
--- a/sw/inc/dbmgr.hxx
+++ b/sw/inc/dbmgr.hxx
@@ -321,7 +321,7 @@ public:
     void            CloseAll(sal_Bool bIncludingMerge = sal_True);
 
     sal_Bool            GetMergeColumnCnt(const String& rColumnName, sal_uInt16 nLanguage,
-                                OUString &rResult, double *pNumber, sal_uInt32 *pFormat);
+                                OUString &rResult, double *pNumber);
     sal_Bool            FillCalcWithMergeData(SvNumberFormatter *pDocFormatter,
                                               sal_uInt16 nLanguage, bool asString, SwCalc &aCalc);
     sal_Bool            ToNextMergeRecord();
diff --git a/sw/source/core/fields/dbfld.cxx b/sw/source/core/fields/dbfld.cxx
index b068000..be36c3a 100644
--- a/sw/source/core/fields/dbfld.cxx
+++ b/sw/source/core/fields/dbfld.cxx
@@ -357,13 +357,13 @@ void SwDBField::Evaluate()
     if(!pMgr || !pMgr->IsDataSourceOpen(aTmpData.sDataSource, aTmpData.sCommand, sal_True))
         return ;
 
-    sal_uInt32 nFmt;
+    sal_uInt32 nFmt = 0;
 
     // Passenden Spaltennamen suchen
     String aColNm( ((SwDBFieldType*)GetTyp())->GetColumnName() );
 
     SvNumberFormatter* pDocFormatter = GetDoc()->GetNumberFormatter();
-    pMgr->GetMergeColumnCnt(aColNm, GetLanguage(), aContent, &nValue, &nFmt);
+    pMgr->GetMergeColumnCnt(aColNm, GetLanguage(), aContent, &nValue);
     if( !( nSubType & nsSwExtendedSubType::SUB_OWN_FMT ) )
         SetFormat( nFmt = pMgr->GetColumnFmt( aTmpData.sDataSource, aTmpData.sCommand,
                                         aColNm, pDocFormatter, GetLanguage() ));
diff --git a/sw/source/core/fields/docufld.cxx b/sw/source/core/fields/docufld.cxx
index a7aa86a..55a8177 100644
--- a/sw/source/core/fields/docufld.cxx
+++ b/sw/source/core/fields/docufld.cxx
@@ -1440,9 +1440,8 @@ void SwHiddenTxtField::Evaluate(SwDoc* pDoc)
                                                 sDataTableOrQuery, sal_False))
                 {
                     double fNumber;
-                    sal_uInt32 nTmpFormat;
                     pMgr->GetMergeColumnCnt(GetColumnName( sTmpName ),
-                        GetLanguage(), aContent, &fNumber, &nTmpFormat );
+                        GetLanguage(), aContent, &fNumber );
                     bValid = sal_True;
                 }
                 else if( sDBName.Len() && sDataSource.Len() &&
diff --git a/sw/source/ui/dbui/dbmgr.cxx b/sw/source/ui/dbui/dbmgr.cxx
index 57ee68c..0c4cfeb 100644
--- a/sw/source/ui/dbui/dbmgr.cxx
+++ b/sw/source/ui/dbui/dbmgr.cxx
@@ -264,8 +264,27 @@ static sal_Bool lcl_MoveAbsolute(SwDSParam* pParam, long nAbsPos)
     return bRet;
 }
 
-static sal_Bool lcl_GetColumnCnt(SwDSParam* pParam,
-    const String& rColumnName, long nLanguage, OUString& rResult, double* pNumber)
+static void lcl_GetColumnCnt(SwDSParam *pParam,
+                             const uno::Reference< XPropertySet > &rColumnProps,
+                             long nLanguage, OUString &rResult, double* pNumber)
+{
+    SwDBFormatData aFormatData;
+    if(!pParam->xFormatter.is())
+    {
+        uno::Reference<XDataSource> xSource = SwNewDBMgr::getDataSourceAsParent(
+                                    pParam->xConnection,pParam->sDataSource);
+        lcl_InitNumberFormatter(*pParam, xSource );
+    }
+    aFormatData.aNullDate = pParam->aNullDate;
+    aFormatData.xFormatter = pParam->xFormatter;
+
+    aFormatData.aLocale = LanguageTag( (LanguageType)nLanguage ).getLocale();
+
+    rResult = SwNewDBMgr::GetDBField( rColumnProps, aFormatData, pNumber);
+}
+
+static sal_Bool lcl_GetColumnCnt(SwDSParam* pParam, const String& rColumnName,
+                             long nLanguage, OUString& rResult, double* pNumber)
 {
     uno::Reference< XColumnsSupplier > xColsSupp( pParam->xResultSet, UNO_QUERY );
     uno::Reference<XNameAccess> xCols;
@@ -281,20 +300,7 @@ static sal_Bool lcl_GetColumnCnt(SwDSParam* pParam,
     Any aCol = xCols->getByName(rColumnName);
     uno::Reference< XPropertySet > xColumnProps;
     aCol >>= xColumnProps;
-
-    SwDBFormatData aFormatData;
-    if(!pParam->xFormatter.is())
-    {
-        uno::Reference<XDataSource> xSource = SwNewDBMgr::getDataSourceAsParent(
-                                    pParam->xConnection,pParam->sDataSource);
-        lcl_InitNumberFormatter(*pParam, xSource );
-    }
-    aFormatData.aNullDate = pParam->aNullDate;
-    aFormatData.xFormatter = pParam->xFormatter;
-
-    aFormatData.aLocale = LanguageTag( (LanguageType)nLanguage ).getLocale();
-
-    rResult = SwNewDBMgr::GetDBField( xColumnProps, aFormatData, pNumber);
+    lcl_GetColumnCnt( pParam, xColumnProps, nLanguage, rResult, pNumber );
     return sal_True;
 };
 
@@ -1901,7 +1907,7 @@ sal_Bool SwNewDBMgr::GetColumnCnt(const String& rSourceName, const String& rTabl
 
 // reads the column data at the current position
 sal_Bool    SwNewDBMgr::GetMergeColumnCnt(const String& rColumnName, sal_uInt16 nLanguage,
-                                OUString &rResult, double *pNumber, sal_uInt32 * /*pFormat*/)
+                                OUString &rResult, double *pNumber)
 {
     if(!pImpl->pMergeData || !pImpl->pMergeData->xResultSet.is() || pImpl->pMergeData->bAfterSelection )
     {
@@ -1946,46 +1952,44 @@ sal_Bool SwNewDBMgr::FillCalcWithMergeData( SvNumberFormatter *pDocFormatter,
                 continue;
             }
 
+            // get the column type
+            sal_Int32 nColumnType = DataType::SQLNULL;
+            Any aCol = xCols->getByName( pColNames[nCol] );
+            uno::Reference<XPropertySet> xColumnProps;
+            aCol >>= xColumnProps;
+            Any aType = xColumnProps->getPropertyValue( "Type" );
+            aType >>= nColumnType;
             double aNumber = DBL_MAX;
-            if( lcl_GetColumnCnt(pImpl->pMergeData, rColName, nLanguage, aString, &aNumber) )
+
+            lcl_GetColumnCnt( pImpl->pMergeData, xColumnProps, nLanguage, aString, &aNumber );
+
+            sal_uInt32 nFmt = GetColumnFmt( pImpl->pMergeData->sDataSource,
+                                            pImpl->pMergeData->sCommand,
+                                            pColNames[nCol], pDocFormatter, nLanguage );
+            // aNumber is overwritten by SwDBField::FormatValue, so store initial status
+            bool colIsNumber = aNumber != DBL_MAX;
+            bool bValidValue = SwDBField::FormatValue( pDocFormatter, aString, nFmt,
+                                                       aNumber, nColumnType, NULL );
+            if( colIsNumber )
             {
-                // get the column type
-                sal_Int32 nColumnType;
-                Any aCol = xCols->getByName( pColNames[nCol] );
-                uno::Reference<XPropertySet> xCol;
-                aCol >>= xCol;
-                Any aType = xCol->getPropertyValue( "Type" );
-                aType >>= nColumnType;
-
-                sal_uInt32 nFmt;
-                if( !GetMergeColumnCnt(pColNames[nCol], nLanguage, aString, &aNumber, &nFmt) )
-                    continue;
-
-                // aNumber is overwritten by SwDBField::FormatValue, so store initial status
-                bool colIsNumber = aNumber != DBL_MAX;
-                bool bValidValue = SwDBField::FormatValue( pDocFormatter, aString, nFmt,
-                                                           aNumber, nColumnType, NULL );
-                if( colIsNumber )
-                {
-                    if( bValidValue )
-                    {
-                        SwSbxValue aValue;
-                        if( !asString )
-                            aValue.PutDouble( aNumber );
-                        else
-                            aValue.PutString( aString );
-                        SAL_INFO( "sw.dbmgr", "'" << pColNames[nCol] << "': " << aNumber << " / " << aString );
-                        rCalc.VarChange( pColNames[nCol], aValue );
-                    }
-                }
-                else
+                if( bValidValue )
                 {
                     SwSbxValue aValue;
-                    aValue.PutString( aString );
-                    SAL_INFO( "sw.dbmgr", "'" << pColNames[nCol] << "': " << aString );
+                    if( !asString )
+                        aValue.PutDouble( aNumber );
+                    else
+                        aValue.PutString( aString );
+                    SAL_INFO( "sw.dbmgr", "'" << pColNames[nCol] << "': " << aNumber << " / " << aString );
                     rCalc.VarChange( pColNames[nCol], aValue );
                 }
             }
+            else
+            {
+                SwSbxValue aValue;
+                aValue.PutString( aString );
+                SAL_INFO( "sw.dbmgr", "'" << pColNames[nCol] << "': " << aString );
+                rCalc.VarChange( pColNames[nCol], aValue );
+            }
         }
         return bExistsNextRecord;
     }
commit ada32b3744ad037630f9f146bbc6ae1ee9e4a90f
Author: Jan-Marek Glogowski <glogow at fbihome.de>
Date:   Wed Nov 26 13:35:42 2014 +0100

    Add kde4-open-url script
    
    Adds a KDE4 specific URL processing script.
    
    (cherry picked from commit f7db2461292be3e23f5b3af47e488eaa8105d8db)
    
    Conflicts:
    
    	shell/Package_scripts_kde.mk
    
    Change-Id: I0116fa95f076a5772e88c616e93de542fe4fe4e4

diff --git a/shell/Package_scripts_kde.mk b/shell/Package_scripts_kde.mk
index 5214df2..870b90d 100644
--- a/shell/Package_scripts_kde.mk
+++ b/shell/Package_scripts_kde.mk
@@ -11,6 +11,12 @@ $(eval $(call gb_Package_Package,shell_scripts_kde,$(SRCDIR)/shell/source/unix/m
 
 $(eval $(call gb_Package_set_outdir,shell_scripts_kde,$(INSTDIR)))
 
+ifeq ($(ENABLE_KDE),TRUE)
 $(eval $(call gb_Package_add_file,shell_scripts_kde,$(gb_PROGRAMDIRNAME)/kde-open-url,kde-open-url.sh))
+endif
+
+ifeq ($(ENABLE_KDE4),TRUE)
+$(eval $(call gb_Package_add_file,shell_scripts_kde,$(gb_PROGRAMDIRNAME)/kde4-open-url,kde4-open-url.sh))
+endif
 
 # vim: set shiftwidth=4 tabstop=4 noexpandtab:
diff --git a/shell/source/unix/misc/kde4-open-url.sh b/shell/source/unix/misc/kde4-open-url.sh
new file mode 100755
index 0000000..e5b8125
--- /dev/null
+++ b/shell/source/unix/misc/kde4-open-url.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+#
+# 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/.
+#
+# This file incorporates work covered by the following license notice:
+#
+#   Licensed to the Apache Software Foundation (ASF) under one or more
+#   contributor license agreements. See the NOTICE file distributed
+#   with this work for additional information regarding copyright
+#   ownership. The ASF licenses this file to you under the Apache
+#   License, Version 2.0 (the "License"); you may not use this file
+#   except in compliance with the License. You may obtain a copy of
+#   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+#
+
+# use kde-open or xdg-open if available, falling back to our own open-url
+kde-open "$1" 2>/dev/null || xdg-open "$1" 2>/dev/null || `dirname "$0"`/open-url "$1" 2>/dev/null
+exit 0
commit b6b36aaa3343bdb11441abf854cc89ab4e5adebe
Author: Eilidh McAdam <eilidh.mcadam at itomig.de>
Date:   Fri Dec 12 00:45:11 2014 +0000

    EMF clip regions should be ignored sometimes.
    
    Specifically, the record EMR_EXTSELECTCLIPRGN specifies the default
    clip region if the RegionMode field is set to RGN_COPY.
    See EMF specification section 2.3.2.2 available from
    http://msdn.microsoft.com/en-us/library/cc230624.aspx
    
    A unit test had to be changed for this - instead of checking for
    a specific clip region, it now checks that no clip region is
    specified. This is under the assumption that the default clip
    region for our device context is "show everything" - i.e. no clip.
    
    Note also that RGN_COPY seems to be a common mode value for this
    record type.
    
    (cherry picked from commit 0ca943155c04ee6272bba7ce957b8d87ae9442de)
    
    Conflicts:
    	vcl/qa/cppunit/wmf/wmfimporttest.cxx (deleted)
    	vcl/source/filter/wmf/enhwmf.cxx
    	vcl/source/filter/wmf/winmtf.cxx
    
    Change-Id: I7bd4fe305dda184d121465005fe09d3c113e3063

diff --git a/vcl/source/filter/wmf/enhwmf.cxx b/vcl/source/filter/wmf/enhwmf.cxx
index de8b780..b2b5079 100644
--- a/vcl/source/filter/wmf/enhwmf.cxx
+++ b/vcl/source/filter/wmf/enhwmf.cxx
@@ -947,10 +947,19 @@ sal_Bool EnhWMFReader::ReadEnhWMF()
                     *pWMF >> cbRgnData
                           >> iMode;
 
-                    PolyPolygon aPolyPoly;
-                    if ( cbRgnData )
-                        ImplReadRegion( aPolyPoly, *pWMF, nRecSize );
-                    pOut->SetClipPath( aPolyPoly, iMode, sal_True );
+                    // This record's region data should be ignored if mode
+                    // is RGN_COPY - see EMF spec section 2.3.2.2
+                    if (iMode == RGN_COPY)
+                    {
+                        pOut->SetDefaultClipPath();
+                    }
+                    else
+                    {
+                        PolyPolygon aPolyPoly;
+                        if ( cbRgnData )
+                            ImplReadRegion( aPolyPoly, *pWMF, nRecSize );
+                        pOut->SetClipPath( aPolyPoly, iMode, sal_True );
+                    }
                 }
                 break;
 
diff --git a/vcl/source/filter/wmf/winmtf.cxx b/vcl/source/filter/wmf/winmtf.cxx
index 6d44084..1065895 100644
--- a/vcl/source/filter/wmf/winmtf.cxx
+++ b/vcl/source/filter/wmf/winmtf.cxx
@@ -84,6 +84,12 @@ void WinMtfClipPath::moveClipRegion( const Size& rSize )
     maClip = basegfx::tools::B2DClipState( aCurrClip );
 }
 
+void WinMtfClipPath::setDefaultClipPath()
+{
+    // Empty clip region - everything visible
+    maClip = basegfx::tools::B2DClipState();
+}
+
 basegfx::B2DPolyPolygon WinMtfClipPath::getClipPath() const
 {
     return maClip.getClipPoly();
@@ -875,6 +881,11 @@ void WinMtfOutput::SetClipPath( const PolyPolygon& rPolyPolygon, sal_Int32 nClip
     }
 }
 
+void WinMtfOutput::SetDefaultClipPath()
+{
+    mbClipNeedsUpdate = true;
+    aClipPath.setDefaultClipPath();
+}
 
 WinMtfOutput::WinMtfOutput( GDIMetaFile& rGDIMetaFile ) :
     mnLatestTextAlign   ( 0 ),
diff --git a/vcl/source/filter/wmf/winmtf.hxx b/vcl/source/filter/wmf/winmtf.hxx
index 8e18f7e..d2aa83d 100644
--- a/vcl/source/filter/wmf/winmtf.hxx
+++ b/vcl/source/filter/wmf/winmtf.hxx
@@ -307,6 +307,7 @@ public :
     void        intersectClipRect( const Rectangle& rRect );
     void        excludeClipRect( const Rectangle& rRect );
     void        moveClipRegion( const Size& rSize );
+    void        setDefaultClipPath();
 
     bool        isEmpty() const { return maClip.isCleared(); }
 
@@ -763,6 +764,7 @@ public:
                             sal_Int32 nClippingMode,
                             sal_Bool bIsMapped
                         );
+    void                SetDefaultClipPath();
     void                UpdateClipRegion();
     void                AddFromGDIMetaFile( GDIMetaFile& rGDIMetaFile );
 
commit 01ae17576263874c86cb2af96414515dd283b4cb
Author: Luboš Luňák <l.lunak at collabora.com>
Date:   Wed Feb 4 19:39:52 2015 +0100

    discard excessive (X11) autorepeat keyboard events if they overload LO
    
    If e.g. a document is slow to redraw, scrolling it by holding down a key such
    as PageDown can make LO lag behind and continue processing the queued up
    input events even (long) after the key has been released. Since with autorepeat
    keyboard events the normal user expectations are to hold it until something
    happens and the exact number of the events doesn't matter, simply discard
    excessive autorepeat keyboard events if LO can't keep up with them.
    
    (cherry picked from commit fc29d34dc60dda5ddbc8f0444684bd2f4eb3668e)
    
    Change-Id: I45acdc9aa5033647fb80760991437dddfcb6591c

diff --git a/vcl/inc/unx/salframe.h b/vcl/inc/unx/salframe.h
index 1a58b904..acdc800 100644
--- a/vcl/inc/unx/salframe.h
+++ b/vcl/inc/unx/salframe.h
@@ -76,7 +76,6 @@ class VCLPLUG_GEN_PUBLIC X11SalFrame : public SalFrame
     X11SalGraphics  *pGraphics_;            // current frame graphics
     X11SalGraphics  *pFreeGraphics_;        // first free frame graphics
 
-    XLIB_Time       nReleaseTime_;      // timestamp of last key release
     sal_uInt16      nKeyCode_;          // last key code
     sal_uInt16      nKeyState_;         // last key state
     int             nCompose_;          // compose state
diff --git a/vcl/unx/generic/window/salframe.cxx b/vcl/unx/generic/window/salframe.cxx
index fdf4723..0ca58c2 100644
--- a/vcl/unx/generic/window/salframe.cxx
+++ b/vcl/unx/generic/window/salframe.cxx
@@ -717,7 +717,6 @@ X11SalFrame::X11SalFrame( SalFrame *pParent, sal_uLong nSalFrameStyle,
     hCursor_                    = None;
     nCaptured_                  = 0;
 
-     nReleaseTime_              = 0;
     nKeyCode_                   = 0;
     nKeyState_                  = 0;
     nCompose_                   = -1;
@@ -3107,6 +3106,66 @@ bool X11SalFrame::endUnicodeSequence()
 
 long X11SalFrame::HandleKeyEvent( XKeyEvent *pEvent )
 {
+    if( pEvent->type == KeyRelease )
+    {
+        // Ignore autorepeat keyrelease events. If there is a series of keypress+keyrelease+keypress events
+        // generated by holding down a key, and if these are from autorepeat (keyrelease and the following keypress
+        // have the same timestamp), drop the autorepeat keyrelease event. Not exactly sure why this is done
+        // (possibly hiding differences between platforms, or just making it more sensible, because technically
+        // the key has not been released at all).
+        bool ignore = false;
+        // Discard queued excessive autorepeat events.
+        // If the user presses and holds down a key, the autorepeating keypress events
+        // may overload LO (e.g. if the key is PageDown and the LO cannot keep up scrolling).
+        // Reduce the load by simply discarding such excessive events (so for a KeyRelease event,
+        // check if it's followed by matching KeyPress+KeyRelease pair(s) and discard those).
+        // This shouldn't have any negative effects - unlike with normal (non-autorepeat
+        // events), the user is unlikely to rely on the exact number of resulting actions
+        // (since autorepeat generates keypress events rather quickly and it's hard to estimate
+        // how many exactly) and the idea should be just keeping the key pressed until something
+        // happens (in which case more events that just lag LO shouldn't make a difference).
+        Display* dpy = pEvent->display;
+        XKeyEvent previousRelease = *pEvent;
+        while( XPending( dpy ))
+        {
+            XEvent nextEvent1;
+            bool discard1 = false;
+            XNextEvent( dpy, &nextEvent1 );
+            if( nextEvent1.type == XLIB_KeyPress && nextEvent1.xkey.time == previousRelease.time
+                && !nextEvent1.xkey.send_event && nextEvent1.xkey.window == previousRelease.window
+                && nextEvent1.xkey.state == previousRelease.state && nextEvent1.xkey.keycode == previousRelease.keycode )
+            {   // This looks like another autorepeat keypress.
+                ignore = true;
+                if( XPending( dpy ))
+                {
+                    XEvent nextEvent2;
+                    XNextEvent( dpy, &nextEvent2 );
+                    if( nextEvent2.type == KeyRelease && nextEvent2.xkey.time <= ( previousRelease.time + 100 )
+                        && !nextEvent2.xkey.send_event && nextEvent2.xkey.window == previousRelease.window
+                        && nextEvent2.xkey.state == previousRelease.state && nextEvent2.xkey.keycode == previousRelease.keycode )
+                    {   // And the matching keyrelease -> drop them both.
+                        discard1 = true;
+                        previousRelease = nextEvent2.xkey;
+                        ignore = false; // There either will be another autorepeating keypress that'll lead to discarding
+                                        // the pEvent keyrelease, it this discarding makes that keyrelease the last one.
+                    }
+                    else
+                    {
+                        XPutBackEvent( dpy, &nextEvent2 );
+                        break;
+                    }
+                }
+            }
+            if( !discard1 )
+            {   // Unrelated event, put back and stop compressing.
+                XPutBackEvent( dpy, &nextEvent1 );
+                break;
+            }
+        }
+        if( ignore ) // This autorepeating keyrelease is followed by another keypress.
+            return 0;
+    }
+
     KeySym          nKeySym;
     KeySym          nUnmodifiedKeySym;
     int             nLen = 2048;
@@ -3974,24 +4033,6 @@ long X11SalFrame::HandleClientMessage( XClientMessageEvent *pEvent )
     return 0;
 }
 
-extern "C"
-{
-Bool call_checkKeyReleaseForRepeat( Display* pDisplay, XEvent* pCheck, XPointer pX11SalFrame )
-{
-    return X11SalFrame::checkKeyReleaseForRepeat( pDisplay, pCheck, pX11SalFrame );
-}
-}
-
-Bool X11SalFrame::checkKeyReleaseForRepeat( Display*, XEvent* pCheck, XPointer pX11SalFrame )
-{
-    X11SalFrame* pThis = (X11SalFrame*)pX11SalFrame;
-    return
-        pCheck->type            == XLIB_KeyPress &&
-        pCheck->xkey.state      == pThis->nKeyState_ &&
-        pCheck->xkey.keycode    == pThis->nKeyCode_ &&
-        pCheck->xkey.time       == pThis->nReleaseTime_  ? True : False;
-}
-
 long X11SalFrame::Dispatch( XEvent *pEvent )
 {
     long nRet = 0;
@@ -4017,14 +4058,7 @@ long X11SalFrame::Dispatch( XEvent *pEvent )
 
             case KeyRelease:
                 if( -1 == nCompose_ )
-                {
-                    nReleaseTime_ = pEvent->xkey.time;
-                    XEvent aEvent;
-                    if( XCheckIfEvent( pEvent->xkey.display, &aEvent, call_checkKeyReleaseForRepeat, (XPointer)this ) )
-                        XPutBackEvent( pEvent->xkey.display, &aEvent );
-                    else
-                        nRet        = HandleKeyEvent( &pEvent->xkey );
-                }
+                    nRet = HandleKeyEvent( &pEvent->xkey );
             break;
 
             case ButtonPress:
commit d89cad9e636d4c273bd177fda8fd059929348f63
Author: Luboš Luňák <l.lunak at collabora.com>
Date:   Wed Feb 4 19:37:27 2015 +0100

    compress (X11) mouse wheel events
    
    There is one event per wheel step, so wheeling more can create a number
    of wheel events, and LO processed those one by one. If processing one took
    long (e.g. the repaint was complicated), the scrolling visibly lagged.
    
    This commit works only for X11 VCL backend (and by extension, KDE3/4 backends).
    
    (cherry picked from commit 847513d409b146400515d7796d196b8b2a142036)
    
    Change-Id: I5eff7446da16167ec75925e75243314c68bc81a4

diff --git a/vcl/unx/generic/window/salframe.cxx b/vcl/unx/generic/window/salframe.cxx
index 374fce0..fdf4723 100644
--- a/vcl/unx/generic/window/salframe.cxx
+++ b/vcl/unx/generic/window/salframe.cxx
@@ -2664,6 +2664,51 @@ void X11SalFrame::SimulateKeyPress( sal_uInt16 nKeyCode )
     GetGenericData()->GetSalDisplay()->SimulateKeyPress(nKeyCode);
 }
 
+namespace
+{
+struct CompressWheelEventsData
+{
+    XEvent* firstEvent;
+    bool ignore;
+    int count; // number of compressed events
+};
+
+static Bool compressWheelEvents( Display*, XEvent* event, XPointer p )
+{
+    CompressWheelEventsData* data = reinterpret_cast< CompressWheelEventsData* >( p );
+    if( data->ignore )
+        return False; // we're already after the events to compress
+    if( event->type == ButtonPress || event->type == ButtonRelease )
+    {
+        const unsigned int mask = Button1Mask << ( event->xbutton.button - Button1 );
+        if( event->xbutton.button == data->firstEvent->xbutton.button
+            && event->xbutton.window == data->firstEvent->xbutton.window
+            && event->xbutton.x == data->firstEvent->xbutton.x
+            && event->xbutton.y == data->firstEvent->xbutton.y
+            && ( event->xbutton.state | mask ) == ( data->firstEvent->xbutton.state | mask ))
+        {
+            // Count if it's another press (i.e. wheel start event).
+            if( event->type == ButtonPress )
+                ++data->count;
+            return True; // And remove the event from the queue.
+        }
+    }
+    // Non-matching event, skip certain events that cannot possibly affect input processing,
+    // but otherwise ignore all further events.
+    switch( event->type )
+    {
+        case Expose:
+        case NoExpose:
+            break;
+        default:
+            data->ignore = true;
+            break;
+    }
+    return False;
+}
+
+} // namespace
+
 long X11SalFrame::HandleMouseEvent( XEvent *pEvent )
 {
     SalMouseEvent       aMouseEvt;
@@ -2883,13 +2928,23 @@ long X11SalFrame::HandleMouseEvent( XEvent *pEvent )
                     nLines = SAL_WHEELMOUSE_EVENT_PAGESCROLL;
             }
 
+            // Compress consecutive wheel events (way too fine scrolling may cause lags if one scrolling steps takes long).
+            CompressWheelEventsData data;
+            data.firstEvent = pEvent;
+            data.count = 1;
+            XEvent dummy;
+            do
+            {
+                data.ignore = false;
+            } while( XCheckIfEvent( pEvent->xany.display, &dummy, compressWheelEvents, reinterpret_cast< XPointer >( &data )));
+
             SalWheelMouseEvent  aWheelEvt;
             aWheelEvt.mnTime        = pEvent->xbutton.time;
             aWheelEvt.mnX           = pEvent->xbutton.x;
             aWheelEvt.mnY           = pEvent->xbutton.y;
-            aWheelEvt.mnDelta       = bIncrement ? 120 : -120;
+            aWheelEvt.mnDelta       = ( bIncrement ? 120 : -120 ) * data.count;
             aWheelEvt.mnNotchDelta  = bIncrement ? 1 : -1;
-            aWheelEvt.mnScrollLines = nLines;
+            aWheelEvt.mnScrollLines = nLines * data.count;
             aWheelEvt.mnCode        = sal_GetCode( pEvent->xbutton.state );
             aWheelEvt.mbHorz        = bHoriz;
 
commit a0fbb74fdecc9a93f2445da5e907019e804adad4
Author: Jan-Marek Glogowski <glogow at fbihome.de>
Date:   Tue Feb 17 10:38:50 2015 +0100

    fdo#40788 Fixup backported checkbox y-offsets
    
    Fixes the wrong option checkbox y-offsets in the old optdlg.src.
    I missed them when doing the backport and didn't check.
    
    Change-Id: I3b3991687556846b130827daa57d78df6087a2cc

diff --git a/sc/source/ui/src/optdlg.src b/sc/source/ui/src/optdlg.src
index 169a0a6..e9ec464 100644
--- a/sc/source/ui/src/optdlg.src
+++ b/sc/source/ui/src/optdlg.src
@@ -778,20 +778,20 @@ TabPage RID_SCPAGE_PRINT
     CheckBox BTN_FORCEBREAKS
     {
         HelpID = "sc:CheckBox:RID_SCPAGE_PRINT:BTN_FORCEBREAKS";
-        Pos = MAP_APPFONT ( 12 , 41 ) ;
+        Pos = MAP_APPFONT ( 12 , 28 ) ;
         Size = MAP_APPFONT ( 239 , 10 ) ;
         Text [ en-US ] = "~Always apply manual breaks";
     };
     FixedLine FL_SHEETS
     {
-        Pos = MAP_APPFONT ( 6 , 30 ) ;
+        Pos = MAP_APPFONT ( 6 , 44 ) ;
         Size = MAP_APPFONT ( 248 , 8 ) ;
         Text [ en-US ] = "Sheets";
     };
     CheckBox BTN_SELECTEDSHEETS
     {
         HelpID = "sc:CheckBox:RID_SCPAGE_PRINT:BTN_SELECTEDSHEETS";
-        Pos = MAP_APPFONT ( 12 , 41 ) ;
+        Pos = MAP_APPFONT ( 12 , 55 ) ;
         Size = MAP_APPFONT ( 239 , 10 ) ;
         Text [ en-US ] = "~Print only selected sheets";
     };


More information about the Libreoffice-commits mailing list