Files
wxWidgets/src/msw/printwin.cpp
Václav Slavík e7aa9bb7c0 Show progress of printing in wxMSW.
Add the number of the page being printed as well as the total to the
wxMSW printing progress window. Improved the layout and fixed some i18n
issues in the process.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@72308 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
2012-08-09 15:52:15 +00:00

466 lines
13 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// Name: src/msw/printwin.cpp
// Purpose: wxWindowsPrinter framework
// Author: Julian Smart
// Modified by:
// Created: 04/01/98
// RCS-ID: $Id$
// Copyright: (c) Julian Smart
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// ===========================================================================
// declarations
// ===========================================================================
// ---------------------------------------------------------------------------
// headers
// ---------------------------------------------------------------------------
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
// Don't use the Windows printer if we're in wxUniv mode and using
// the PostScript architecture
#if wxUSE_PRINTING_ARCHITECTURE && (!defined(__WXUNIVERSAL__) || !wxUSE_POSTSCRIPT_ARCHITECTURE_IN_MSW)
#ifndef WX_PRECOMP
#include "wx/msw/wrapcdlg.h"
#include "wx/window.h"
#include "wx/msw/private.h"
#include "wx/utils.h"
#include "wx/dc.h"
#include "wx/app.h"
#include "wx/msgdlg.h"
#include "wx/intl.h"
#include "wx/log.h"
#include "wx/dcprint.h"
#include "wx/dcmemory.h"
#include "wx/image.h"
#endif
#include "wx/msw/dib.h"
#include "wx/msw/dcmemory.h"
#include "wx/msw/printwin.h"
#include "wx/msw/printdlg.h"
#include "wx/msw/private.h"
#include "wx/msw/dcprint.h"
#if wxUSE_ENH_METAFILE
#include "wx/msw/enhmeta.h"
#endif
#include <stdlib.h>
// ---------------------------------------------------------------------------
// private functions
// ---------------------------------------------------------------------------
BOOL CALLBACK wxAbortProc(HDC hdc, int error);
// ---------------------------------------------------------------------------
// wxWin macros
// ---------------------------------------------------------------------------
IMPLEMENT_DYNAMIC_CLASS(wxWindowsPrinter, wxPrinterBase)
IMPLEMENT_CLASS(wxWindowsPrintPreview, wxPrintPreviewBase)
// ===========================================================================
// implementation
// ===========================================================================
// ---------------------------------------------------------------------------
// Printer
// ---------------------------------------------------------------------------
wxWindowsPrinter::wxWindowsPrinter(wxPrintDialogData *data)
: wxPrinterBase(data)
{
}
bool wxWindowsPrinter::Print(wxWindow *parent, wxPrintout *printout, bool prompt)
{
sm_abortIt = false;
sm_abortWindow = NULL;
if (!printout)
{
sm_lastError = wxPRINTER_ERROR;
return false;
}
if (m_printDialogData.GetMinPage() < 1)
m_printDialogData.SetMinPage(1);
if (m_printDialogData.GetMaxPage() < 1)
m_printDialogData.SetMaxPage(9999);
// Create a suitable device context
wxPrinterDC *dc wxDUMMY_INITIALIZE(NULL);
if (prompt)
{
dc = wxDynamicCast(PrintDialog(parent), wxPrinterDC);
if (!dc)
return false;
}
else
{
dc = new wxPrinterDC(m_printDialogData.GetPrintData());
}
// May have pressed cancel.
if (!dc || !dc->IsOk())
{
if (dc) delete dc;
return false;
}
wxPrinterDCImpl *impl = (wxPrinterDCImpl*) dc->GetImpl();
HDC hdc = ::GetDC(NULL);
int logPPIScreenX = ::GetDeviceCaps(hdc, LOGPIXELSX);
int logPPIScreenY = ::GetDeviceCaps(hdc, LOGPIXELSY);
::ReleaseDC(NULL, hdc);
int logPPIPrinterX = ::GetDeviceCaps((HDC) impl->GetHDC(), LOGPIXELSX);
int logPPIPrinterY = ::GetDeviceCaps((HDC) impl->GetHDC(), LOGPIXELSY);
if (logPPIPrinterX == 0 || logPPIPrinterY == 0)
{
delete dc;
sm_lastError = wxPRINTER_ERROR;
return false;
}
printout->SetPPIScreen(logPPIScreenX, logPPIScreenY);
printout->SetPPIPrinter(logPPIPrinterX, logPPIPrinterY);
// Set printout parameters
printout->SetDC(dc);
int w, h;
dc->GetSize(&w, &h);
printout->SetPageSizePixels((int)w, (int)h);
printout->SetPaperRectPixels(dc->GetPaperRect());
dc->GetSizeMM(&w, &h);
printout->SetPageSizeMM((int)w, (int)h);
// Create an abort window
wxBusyCursor busyCursor;
printout->OnPreparePrinting();
// Get some parameters from the printout, if defined
int fromPage, toPage;
int minPage, maxPage;
printout->GetPageInfo(&minPage, &maxPage, &fromPage, &toPage);
if (maxPage == 0)
{
sm_lastError = wxPRINTER_ERROR;
return false;
}
// Only set min and max, because from and to have been
// set by the user
m_printDialogData.SetMinPage(minPage);
m_printDialogData.SetMaxPage(maxPage);
wxPrintAbortDialog *win = CreateAbortWindow(parent, printout);
wxYield();
::SetAbortProc(GetHdcOf(*impl), wxAbortProc);
if (!win)
{
wxLogDebug(wxT("Could not create an abort dialog."));
sm_lastError = wxPRINTER_ERROR;
delete dc;
return false;
}
sm_abortWindow = win;
sm_abortWindow->Show();
wxSafeYield();
printout->OnBeginPrinting();
sm_lastError = wxPRINTER_NO_ERROR;
int minPageNum = minPage, maxPageNum = maxPage;
if ( !m_printDialogData.GetAllPages() )
{
minPageNum = m_printDialogData.GetFromPage();
maxPageNum = m_printDialogData.GetToPage();
}
const int maxCopyCount = m_printDialogData.GetNoCopies();
for ( int copyCount = 1; copyCount <= maxCopyCount; copyCount++ )
{
if ( !printout->OnBeginDocument(minPageNum, maxPageNum) )
{
wxLogError(_("Could not start printing."));
sm_lastError = wxPRINTER_ERROR;
break;
}
if (sm_abortIt)
{
sm_lastError = wxPRINTER_CANCELLED;
break;
}
int pn;
for ( pn = minPageNum;
pn <= maxPageNum && printout->HasPage(pn);
pn++ )
{
win->SetProgress(pn - minPageNum + 1,
maxPageNum - minPageNum + 1,
copyCount, maxCopyCount);
if ( sm_abortIt )
{
sm_lastError = wxPRINTER_CANCELLED;
break;
}
dc->StartPage();
bool cont = printout->OnPrintPage(pn);
dc->EndPage();
if ( !cont )
{
sm_lastError = wxPRINTER_CANCELLED;
break;
}
}
printout->OnEndDocument();
}
printout->OnEndPrinting();
if (sm_abortWindow)
{
sm_abortWindow->Show(false);
wxDELETE(sm_abortWindow);
}
delete dc;
return sm_lastError == wxPRINTER_NO_ERROR;
}
wxDC *wxWindowsPrinter::PrintDialog(wxWindow *parent)
{
wxDC *dc = NULL;
wxWindowsPrintDialog dialog(parent, & m_printDialogData);
int ret = dialog.ShowModal();
if (ret == wxID_OK)
{
dc = dialog.GetPrintDC();
m_printDialogData = dialog.GetPrintDialogData();
if (dc == NULL)
sm_lastError = wxPRINTER_ERROR;
else
sm_lastError = wxPRINTER_NO_ERROR;
}
else
sm_lastError = wxPRINTER_CANCELLED;
return dc;
}
bool wxWindowsPrinter::Setup(wxWindow *WXUNUSED(parent))
{
#if 0
// We no longer expose that dialog
wxPrintDialog dialog(parent, & m_printDialogData);
dialog.GetPrintDialogData().SetSetupDialog(true);
int ret = dialog.ShowModal();
if (ret == wxID_OK)
{
m_printDialogData = dialog.GetPrintDialogData();
}
return (ret == wxID_OK);
#else
return false;
#endif
}
/*
* Print preview
*/
wxWindowsPrintPreview::wxWindowsPrintPreview(wxPrintout *printout,
wxPrintout *printoutForPrinting,
wxPrintDialogData *data)
: wxPrintPreviewBase(printout, printoutForPrinting, data)
{
DetermineScaling();
}
wxWindowsPrintPreview::wxWindowsPrintPreview(wxPrintout *printout,
wxPrintout *printoutForPrinting,
wxPrintData *data)
: wxPrintPreviewBase(printout, printoutForPrinting, data)
{
DetermineScaling();
}
wxWindowsPrintPreview::~wxWindowsPrintPreview()
{
}
bool wxWindowsPrintPreview::Print(bool interactive)
{
if (!m_printPrintout)
return false;
wxWindowsPrinter printer(&m_printDialogData);
return printer.Print(m_previewFrame, m_printPrintout, interactive);
}
void wxWindowsPrintPreview::DetermineScaling()
{
ScreenHDC dc;
int logPPIScreenX = ::GetDeviceCaps(dc, LOGPIXELSX);
int logPPIScreenY = ::GetDeviceCaps(dc, LOGPIXELSY);
m_previewPrintout->SetPPIScreen(logPPIScreenX, logPPIScreenY);
// Get a device context for the currently selected printer
wxPrinterDC printerDC(m_printDialogData.GetPrintData());
int printerWidthMM;
int printerHeightMM;
int printerXRes;
int printerYRes;
int logPPIPrinterX;
int logPPIPrinterY;
wxRect paperRect;
if ( printerDC.IsOk() )
{
wxPrinterDCImpl *impl = (wxPrinterDCImpl*) printerDC.GetImpl();
HDC dc = GetHdcOf(*impl);
printerWidthMM = ::GetDeviceCaps(dc, HORZSIZE);
printerHeightMM = ::GetDeviceCaps(dc, VERTSIZE);
printerXRes = ::GetDeviceCaps(dc, HORZRES);
printerYRes = ::GetDeviceCaps(dc, VERTRES);
logPPIPrinterX = ::GetDeviceCaps(dc, LOGPIXELSX);
logPPIPrinterY = ::GetDeviceCaps(dc, LOGPIXELSY);
paperRect = printerDC.GetPaperRect();
if ( logPPIPrinterX == 0 ||
logPPIPrinterY == 0 ||
printerWidthMM == 0 ||
printerHeightMM == 0 )
{
m_isOk = false;
}
}
else
{
// use some defaults
printerWidthMM = 150;
printerHeightMM = 250;
printerXRes = 1500;
printerYRes = 2500;
logPPIPrinterX = 600;
logPPIPrinterY = 600;
paperRect = wxRect(0, 0, printerXRes, printerYRes);
m_isOk = false;
}
m_pageWidth = printerXRes;
m_pageHeight = printerYRes;
m_previewPrintout->SetPageSizePixels(printerXRes, printerYRes);
m_previewPrintout->SetPageSizeMM(printerWidthMM, printerHeightMM);
m_previewPrintout->SetPaperRectPixels(paperRect);
m_previewPrintout->SetPPIPrinter(logPPIPrinterX, logPPIPrinterY);
// At 100%, the page should look about page-size on the screen.
m_previewScaleX = float(logPPIScreenX) / logPPIPrinterX;
m_previewScaleY = float(logPPIScreenY) / logPPIPrinterY;
}
#if wxUSE_ENH_METAFILE
bool wxWindowsPrintPreview::RenderPageIntoBitmap(wxBitmap& bmp, int pageNum)
{
// The preview, as implemented in wxPrintPreviewBase (and as used prior to
// wx3) is inexact: it uses screen DC, which has much lower resolution and
// has other properties different from printer DC, so the preview is not
// quite right.
//
// To make matters worse, if the application depends heavily on
// GetTextExtent() or does text layout itself, the output in preview and on
// paper can be very different. In particular, wxHtmlEasyPrinting is
// affected and the preview can be easily off by several pages.
//
// To fix this, we render the preview into high-resolution enhanced
// metafile with properties identical to the printer DC. This guarantees
// metrics correctness while still being fast.
// print the preview into a metafile:
wxPrinterDC printerDC(m_printDialogData.GetPrintData());
wxEnhMetaFileDC metaDC(printerDC,
wxEmptyString,
printerDC.GetSize().x, printerDC.GetSize().y);
if ( !RenderPageIntoDC(metaDC, pageNum) )
return false;
wxEnhMetaFile *metafile = metaDC.Close();
if ( !metafile )
return false;
// now render the metafile:
wxMemoryDC bmpDC;
bmpDC.SelectObject(bmp);
bmpDC.Clear();
wxRect outRect(0, 0, bmp.GetWidth(), bmp.GetHeight());
metafile->Play(&bmpDC, &outRect);
delete metafile;
// TODO: we should keep the metafile and reuse it when changing zoom level
return true;
}
#endif // wxUSE_ENH_METAFILE
BOOL CALLBACK wxAbortProc(HDC WXUNUSED(hdc), int WXUNUSED(error))
{
MSG msg;
if (!wxPrinterBase::sm_abortWindow) /* If the abort dialog isn't up yet */
return(TRUE);
/* Process messages intended for the abort dialog box */
while (!wxPrinterBase::sm_abortIt && ::PeekMessage(&msg, 0, 0, 0, TRUE))
if (!IsDialogMessage((HWND) wxPrinterBase::sm_abortWindow->GetHWND(), &msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
/* bAbort is TRUE (return is FALSE) if the user has aborted */
return !wxPrinterBase::sm_abortIt;
}
#endif
// wxUSE_PRINTING_ARCHITECTURE