home *** CD-ROM | disk | FTP | other *** search
- //----------------------------------------------------------------------------
- // ObjectWindows
- // (C) Copyright 1992, 1994 by Borland International, All Rights Reserved
- //
- //----------------------------------------------------------------------------
- #pragma hdrignore SECTION
- #include <owl/owlpch.h>
- #include <owl/applicat.h>
- #include <owl/appdict.h>
- #include <owl/window.h>
- #include <owl/framewin.h>
- #include <owl/dc.h>
- #include <owl/static.h>
- #include <owl/printer.h>
-
- #if !defined(SECTION) || SECTION == 1
-
- //
- // Macro used to set and clear a bunch of flags at once
- //
- #define SETCLEAR(flag, set, clear)((flag) = ((flag)&~(clear))|(set))
-
- //#define MANUAL_ABORT_CALL // define to manually call abort proc
-
-
- //----------------------------------------------------------------------------
-
- // TFormattedStatic - Static control that uses its resource title as a printf
- // format string to format one or two text strings provided in the constructor
- //
- class TFormattedStatic: public TStatic {
- public:
- TFormattedStatic(TWindow* parent, int resId, const char far* text,
- const char far* text2=0);
- ~TFormattedStatic();
-
- protected:
- void SetupWindow();
-
- private:
- char far* Text;
- char far* Text2;
- };
-
- TFormattedStatic::TFormattedStatic(TWindow* parent, int resId,
- const char far* text, const char far* text2)
- :
- TStatic(parent, resId, 0)
- {
- Text = strnewdup(text);
- Text2 = text2 ? strnewdup(text2) : 0;
- }
-
- TFormattedStatic::~TFormattedStatic()
- {
- delete Text;
- delete Text2;
- }
-
- void
- TFormattedStatic::SetupWindow()
- {
- TStatic::SetupWindow();
-
- // Use the Title retrieved from the resource as a printf template for
- // the one or two text strings, then set the text directly to the control to
- // preserve the Title
- //
- char buff[80];
- wsprintf(buff, Title, Text, Text2); // second text string is optional
- SetText(buff);
- }
-
- // TNumericStatic - Static control that uses its resource title as a printf
- // format string to format one or two text strings provided in the constructor
- //
- class TNumericStatic: public TStatic {
- public:
- TNumericStatic(TWindow* parent, int resId, int number);
-
- protected:
- LRESULT EvSetNumber(WPARAM wParam, LPARAM lParam);
-
- private:
- int Number;
-
- DECLARE_RESPONSE_TABLE(TNumericStatic);
- };
- #define WM_SETNUMBER WM_USER+100
-
- DEFINE_RESPONSE_TABLE1(TNumericStatic, TStatic)
- EV_MESSAGE(WM_SETNUMBER, EvSetNumber),
- END_RESPONSE_TABLE;
-
- TNumericStatic::TNumericStatic(TWindow* parent, int resId, int number)
- :
- TStatic(parent, resId, 0),
- Number(number)
- {
- }
-
- //
- // Handle our user defined message to set the number displayed in the %d part
- // of the Title format string. If the number is <= 0, then hide this window
- //
- LRESULT
- TNumericStatic::EvSetNumber(WPARAM wParam, LPARAM)
- {
- Number = wParam;
- if (Number > 0) {
- char buff[80];
- wsprintf(buff, Title, Number);
- SetText(buff);
- }
- HWND hWndDefault = Parent->GetDlgItem(-1);
- if (Number > 0) {
- SetWindowPos(HWND_TOP, 0, 0, 0, 0,
- SWP_NOSIZE|SWP_NOMOVE|SWP_SHOWWINDOW);
- if (hWndDefault)
- ::ShowWindow(hWndDefault, SW_HIDE);
- UpdateWindow();
- }
- return 0;
- }
-
-
- //----------------------------------------------------------------------------
-
- DEFINE_RESPONSE_TABLE1(TPrinterAbortDlg, TDialog)
- EV_COMMAND(IDCANCEL, CmCancel),
- END_RESPONSE_TABLE;
-
-
- TPrinterAbortDlg::TPrinterAbortDlg(TWindow* parent,
- TResId resId,
- const char far* title,
- const char far* device,
- const char far* port,
- HDC prnDC)
- :
- TDialog(parent, resId),
- TWindow(parent, 0),
- PrnDC(prnDC)
- {
- new TNumericStatic(this, ID_PAGE, 0);
- new TFormattedStatic(this, ID_TITLE, title);
- new TFormattedStatic(this, ID_DEVICE, device, port);
- }
-
- void
- TPrinterAbortDlg::SetupWindow()
- {
- // ignore missing controls, resource may be different
- //
- TRY {
- TDialog::SetupWindow();
- }
- CATCH( (...) {
- } )
- EnableMenuItem(GetSystemMenu(false), SC_CLOSE, MF_GRAYED);
- }
-
- //
- // Handle the print-cancel button by setting the user print abort flag in the
- // application.
- //
- void
- TPrinterAbortDlg::CmCancel()
- {
- TPrinter::SetUserAbort(PrnDC);
- HWND hBtn = GetDlgItem(IDCANCEL);
- if (hBtn)
- ::EnableWindow(hBtn, false);
- }
-
-
- //----------------------------------------------------------------------------
- //
- // TPrinter is an encapsulation around the Windows printer device interface.
- //
- // Examples:
- // Creating a default device printing object:
- //
- // DefaultPrinter = new TPrinter();
- //
- // Creating a device for a specific printer:
- //
- // PostScriptPrinter = new TPrinter();
- // PostScriptPrinter->SetDevice("PostScript Printer", "PSCRIPT", "LPT2:");
- //
- // Allowing the user to setup the printer:
- //
- // DefaultPrinter->Setup(MyWindow);
- //
-
- HDC TPrinter::UserAbortDC = 0; // Set by printing dialog if user cancels
-
- //
- // Initialize the TPrinter object assigned to the default printer
- //
- TPrinter::TPrinter(TApplication* app)
- {
- Data = new TPrintDialog::TData;
- Error = 0;
- Application = app ? app : ::GetApplicationObject();
- CHECK(Application);
- GetDefaultPrinter();
- }
-
- //
- // Deallocate allocated resources
- //
- TPrinter::~TPrinter()
- {
- delete Data;
- }
-
- //
- // Clears the association of this printer object with the current device
- //
- void TPrinter::ClearDevice()
- {
- Data->ClearDevMode();
- Data->ClearDevNames();
- }
-
- //
- // Updata Data with info on the user's default printer.
- //
- void
- TPrinter::GetDefaultPrinter()
- {
- //
- // Have a printDialog go get the default printer information for us
- // into DevMode and DevNames. We never actually Execute() the dialog.
- //
- SETCLEAR(Data->Flags, 0, PD_RETURNDC);
- TPrintDialog printDialog(Application->GetMainWindow(), *Data);
- printDialog.GetDefaultPrinter();
- }
-
- //
- // Associate this printer object with actual printer info: driver name, device
- // name and output port name.
- //
- void
- TPrinter::SetPrinter(const char* driver, const char* device, const char* output)
- {
- Data->SetDevNames(driver, device, output);
- }
-
- //
- // Abort procedure used during printing, called by windows. Returns true to
- // continue the print job, false to cancel.
- //
- int CALLBACK __export
- TPrinterAbortProc(HDC hDC, int code)
- {
- GetApplicationObject()->PumpWaitingMessages();
-
- // UserAbortDC will have been set by the AbortDialog
- //
- if (TPrinter::GetUserAbort() == hDC || TPrinter::GetUserAbort() == HDC(-1)) {
- TPrinter::SetUserAbort(0);
- return false;
- }
- return code == 0 || code == SP_OUTOFDISK;
- }
-
- //
- // Virtual called from within Print() to construct and execute a print dialog
- // before actual printing occurs. Return true to continue printing, false to
- // cancel
- //
- bool
- TPrinter::ExecPrintDialog(TWindow* parent)
- {
- return TPrintDialog(parent, *Data).Execute() == IDOK;
- }
-
- //
- // Virtual called from withing Print() just before the main printing loop to
- // construct and create the printing status, or abort window. This window
- // should use the control IDs specified in printer.rh
- //
- TWindow*
- TPrinter::CreateAbortWindow(TWindow* parent, TPrintout& printout)
- {
- TDC* dc = printout.GetPrintDC();
- TWindow* win = new TPrinterAbortDlg(parent, IDD_ABORTDIALOG,
- printout.GetTitle(),
- Data->GetDeviceName(),
- Data->GetOutputName(),
- dc ? HDC(*dc) : HDC(-1));
- win->Create();
- return win;
- }
-
- //
- // Helper function for Print when it is banding used to calculate banding flags
- // and rectangle.
- //
- void
- TPrinter::CalcBandingFlags(TPrintDC& prnDC)
- {
- //
- // Calculate text versus graphics banding
- //
- if (UseBandInfo) {
- TBandInfo bandInfo;
- unsigned flags = 0;
-
- prnDC.BandInfo(bandInfo);
- if (bandInfo.HasGraphics)
- flags = pfGraphics;
- if (bandInfo.HasText)
- flags |= pfGraphics;
- Flags = (Flags & ~pfBoth) | flags;
- }
- else {
- //
- // If a driver does not support BANDINFO the Microsoft recommended way
- // of determining text only bands is if the first band is the full page,
- // all others are graphics only. Otherwise it handles both.
- //
- if (FirstBand && !BandRect.left && !BandRect.top &&
- BandRect.right == PageSize.cx && BandRect.bottom == PageSize.cy)
- Flags = pfText;
- else
- if ((Flags & pfBoth) == pfGraphics)
- // All other bands are graphics only
- Flags = (Flags & ~pfBoth) | pfGraphics;
- else
- Flags = Flags | pfBoth;
- }
- FirstBand = false;
- }
-
- //
- // Print the given printout to the printer, prompting the user with a
- // commdlg print dialog if indicated.
- //
- bool
- TPrinter::Print(TWindow* parent, TPrintout& printout, bool prompt)
- {
- PRECONDITION(parent);
-
- // Start from scratch
- //
- Error = 1; // Positive 'Error' means print job is OK
- TPrintDC* prnDC;
- HCURSOR hOrigCursor = ::SetCursor(::LoadCursor(0, IDC_WAIT));
-
- //
- // Get page range & selection range (if any) from document
- //
- int selFromPage;
- int selToPage;
- printout.GetDialogInfo(Data->MinPage, Data->MaxPage, selFromPage, selToPage);
- if (selFromPage)
- Data->Flags &= ~PD_NOSELECTION;
- else
- Data->Flags |= PD_NOSELECTION;
- if (Data->MinPage) {
- Data->Flags &= ~PD_NOPAGENUMS;
- if (Data->FromPage < Data->MinPage)
- Data->FromPage = Data->MinPage;
- else if (Data->FromPage > Data->MaxPage)
- Data->FromPage = Data->MaxPage;
- if (Data->ToPage < Data->MinPage)
- Data->ToPage = Data->MinPage;
- else if (Data->ToPage > Data->MaxPage)
- Data->ToPage = Data->MaxPage;
- }
- else
- Data->Flags |= PD_NOPAGENUMS;
-
- //
- // Create & execute a TPrintDialog (or derived) and have it return a usable
- // DC if prompt is enabled. If the dialog fails because the default printer
- // changed, clear our device information & try again.
- //
- if (prompt) {
- SETCLEAR(Data->Flags, PD_RETURNDC, PD_RETURNDEFAULT|PD_PRINTSETUP);
- bool ok = ExecPrintDialog(parent);
- if (!ok && Data->Error == PDERR_DEFAULTDIFFERENT) {
- ClearDevice();
- ok = ExecPrintDialog(parent);
- }
- if (!ok)
- return false;
-
- prnDC = Data->TransferDC(); // We now own the DC, let prnDC manage it
- }
- // Construct the DC directly if prompting was not enabled.
- //
- else {
- prnDC = new TPrintDC(Data->GetDriverName(), Data->GetDeviceName(),
- Data->GetOutputName(), Data->GetDevMode());
- }
- if (!prnDC)
- THROW( TXPrinter() );
-
- //
- // Get the page size
- //
- PageSize.cx = prnDC->GetDeviceCaps(HORZRES);
- PageSize.cy = prnDC->GetDeviceCaps(VERTRES);
- printout.SetPrintParams(prnDC, PageSize);
-
- //
- // Create modeless abort dialog using strings
- //
- TWindow* abortWin;
- TRY {
- abortWin = CreateAbortWindow(parent, printout);
- }
- CATCH( (...) {
- delete prnDC;
- RETHROW;
- })
-
- ::SetCursor(hOrigCursor);
- parent->EnableWindow(false);
-
- prnDC->SetAbortProc(TPrinterAbortProc);
-
- //
- // Only band if the user requests banding and the printer
- // supports banding
- //
- bool banding = printout.WantBanding() &&
- (prnDC->GetDeviceCaps(RASTERCAPS) & RC_BANDING);
- if (banding)
- //
- // Only use BANDINFO if supported.
- //
- UseBandInfo = ToBool(prnDC->QueryEscSupport(BANDINFO));
-
- else
- //
- // Set the banding rectangle to full page
- //
- BandRect.Set(0, 0, PageSize.cx, PageSize.cy);
-
- //
- // If more than one (uncollated) copy was requested, see if printer can
- // handle it for performance and user convenience.
- //
- int copiesPerPass = 1;
- if (!(Data->Flags & PD_COLLATE))
- prnDC->SetCopyCount(Data->Copies, copiesPerPass);
-
- //
- // Figure out which page range to use: Selection, Dialog's from/to,
- // whole doc range or all possible pages.
- //
- int fromPage;
- int toPage;
- if (prompt && (Data->Flags & PD_SELECTION) || selFromPage) {
- fromPage = selFromPage;
- toPage = selToPage;
- }
- else if (prompt && (Data->Flags & PD_PAGENUMS)) {
- fromPage = Data->FromPage;
- toPage = Data->ToPage;
- }
- else if (Data->MinPage) {
- fromPage = Data->MinPage;
- toPage = Data->MaxPage;
- }
- else {
- fromPage = 1;
- toPage = INT_MAX;
- }
-
- //
- // Copies loop, one pass per block of document copies.
- //
- printout.BeginPrinting();
- for (int copies = Data->Copies;
- copies > 0 && Error > 0;
- copies -= copiesPerPass) {
-
- //
- // On last multi-copy pass, may need to adjust copy count
- //
- if (copiesPerPass > 1 && copies < copiesPerPass)
- prnDC->SetCopyCount(copies, copiesPerPass);
-
- //
- // Whole document loop, one pass per page
- //
- Flags = pfBoth;
- Error = prnDC->StartDoc(printout.GetTitle(), 0); // get PD_PRINTTOFILE ?
- printout.BeginDocument(fromPage, toPage, Flags);
-
- for (int pageNum = fromPage;
- Error > 0 && pageNum <= toPage && printout.HasPage(pageNum);
- pageNum++) {
-
- abortWin->SendDlgItemMessage(ID_PAGE, WM_SETNUMBER, pageNum);
-
- //
- // Begin the page by getting the first band or calling StartPage()
- //
- if (banding) {
- FirstBand = true;
- Error = prnDC->NextBand(BandRect);
- }
- else
- Error = prnDC->StartPage();
-
- //
- // Whole page loop, one pass per band (once when not banding)
- //
- while (Error > 0 && !BandRect.IsEmpty()) {
- //
- // [Manually call the abort proc between bands or pages]
- //
- #if defined(MANUAL_ABORT_CALL)
- prnDC->QueryAbort();
- #endif
-
- if (banding) {
- CalcBandingFlags(*prnDC);
- if (printout.WantForceAllBands() && (Flags & pfBoth) == pfGraphics)
- prnDC->SetPixel(TPoint(0, 0), 0); // Some old drivers need this
- prnDC->DPtoLP(BandRect, 2);
- }
-
- printout.PrintPage(pageNum, BandRect, Flags);
- if (banding)
- Error = prnDC->NextBand(BandRect);
- else
- break;
- }
-
- //
- // EndPage (NEWFRAME) need only called if not banding
- //
- if (Error > 0 && !banding) {
- Error = prnDC->EndPage();
- if (Error == 0) // a zero return here is OK for this call
- Error = 1;
- }
-
- } // End of Whole Document-loop
-
- // Tell GDI the document is finished
- //
- if (Error > 0)
- #if defined(MANUAL_ABORT_CALL)
- if (banding && (UserAbortDC == *prnDC || UserAbortDC == HDC(-1))
- prnDC->AbortDoc();
- else
- prnDC->EndDoc();
- #else
- prnDC->EndDoc();
- #endif
-
- printout.EndDocument();
-
- } // End of Copy-loop
- printout.EndPrinting();
-
- // Set the printer back to 1 copy
- //
- if (copiesPerPass > 1)
- prnDC->SetCopyCount(1, copiesPerPass);
-
- //
- // Re-enable parent and free allocated resources
- //
- parent->EnableWindow(true);
- abortWin->Destroy();
- delete abortWin;
- if (UserAbortDC == *prnDC) // User tried to abort, but it was too late
- UserAbortDC = 0;
- delete prnDC;
-
- //
- // Report error if not already done so by printmgr
- //
- if (Error & SP_NOTREPORTED)
- ReportError(parent, printout);
-
- return Error > 0;
- }
-
- //
- // Setup opens a dialog as a child of the given window to setup the
- // printer using the commdlg printer setup. The options button
- // allows the user acces to the specific driver's options.
- //
- void TPrinter::Setup(TWindow* parent)
- {
- SETCLEAR(Data->Flags, PD_PRINTSETUP, PD_RETURNDEFAULT|PD_RETURNDC);
- ExecPrintDialog(parent);
- }
-
- //
- // Report the printer error in a message box. First translate the SP_ codes
- // into ObjectWindows string resource IDs, and then load the strings. Don't
- // display anything if the string is not found, or the code is unknown.
- //
- void
- TPrinter::ReportError(TWindow* parent, TPrintout& printout)
- {
- uint16 errorId;
-
- switch (Error) {
- case SP_ERROR:
- errorId = IDS_PRNGENERROR;
- break;
- case SP_APPABORT:
- errorId = IDS_PRNCANCEL;
- break;
- case SP_USERABORT:
- errorId = IDS_PRNMGRABORT;
- break;
- case SP_OUTOFDISK:
- errorId = IDS_PRNOUTOFDISK;
- break;
- case SP_OUTOFMEMORY:
- errorId = IDS_PRNOUTOFMEMORY;
- break;
- default:
- return;
- }
-
- TModule& module = *parent->GetModule();
-
- char errorCaption[80];
- if (!module.LoadString(IDS_PRNERRORCAPTION, errorCaption, sizeof(errorCaption)))
- return;
-
- char errorTemplate[40];
- char errorStr[40];
- if (!module.LoadString(IDS_PRNERRORTEMPLATE, errorTemplate, sizeof(errorTemplate)))
- return;
- if (!module.LoadString(errorId, errorStr, sizeof(errorStr)))
- return;
-
- char errorMsg[80];
- wsprintf(errorMsg, errorTemplate, printout.GetTitle(), (char far*)errorStr);
-
- parent->MessageBox(errorMsg, errorCaption, MB_OK | MB_ICONSTOP);
- }
-
- TPrinter::TXPrinter::TXPrinter(uint resId) : TXOwl(resId)
- {
- }
-
- #endif
- #if !defined(SECTION) || SECTION == 2
-
- IMPLEMENT_STREAMABLE(TPrinter);
-
- void*
- TPrinter::Streamer::Read(ipstream& is, uint32 version) const
- {
- GetObject()->Data->Read(is, version);
- return GetObject();
- }
-
- void
- TPrinter::Streamer::Write(opstream& os) const
- {
- GetObject()->Data->Write(os);
- }
-
- #endif
-
-