home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c083 / 11.ddi / OWLSRC.PAK / PRINTER.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-02  |  14.0 KB  |  550 lines

  1. //----------------------------------------------------------------------------
  2. // ObjectWindows - (C) Copyright 1992, 1993 by Borland International
  3. //   source\owl\printer.cpp
  4. //----------------------------------------------------------------------------
  5. #pragma hdrignore SECTION
  6. #include <owl\owlpch.h>
  7. #include <owl\applicat.h>
  8. #include <owl\window.h>
  9. #include <owl\dc.h>
  10. #include <owl\static.h>
  11. #include <owl\printer.h>
  12.  
  13. #if !defined(SECTION) || SECTION == 1
  14.  
  15. //
  16. // Macro used to set and clear a bunch of flags at once
  17. //
  18. #define SETCLEAR(flag, set, clear)((flag) = ((flag)&~(clear))|(set))
  19.  
  20. //#define MANUAL_ABORT_CALL   // define to manually call abort proc
  21.  
  22.  
  23. //----------------------------------------------------------------------------
  24.  
  25. // TFormattedStatic - Static control that uses its resource title as a printf
  26. // format string to format text provided in the constructor
  27. //
  28. class TFormattedStatic: public TStatic {
  29.   public:
  30.     TFormattedStatic(TWindow* parent, int resId, const char far* text);
  31.    ~TFormattedStatic();
  32.   
  33.   protected:
  34.     void SetupWindow();
  35.  
  36.   private:
  37.     char far*  Text;
  38. };
  39.  
  40. TFormattedStatic::TFormattedStatic(TWindow* parent, int resId, const char far* text)
  41.   : TStatic(parent, resId, 0)
  42. {
  43.   Text = strnewdup(text);
  44. }
  45.  
  46. TFormattedStatic::~TFormattedStatic()
  47. {
  48.   delete Text;
  49. }
  50.  
  51. void
  52. TFormattedStatic::SetupWindow()
  53. {
  54.   TStatic::SetupWindow();
  55.  
  56.   char format[80];
  57.   GetText(format, sizeof(format) - 1);
  58.  
  59.   char buff[80];
  60.   wsprintf(buff, format, Text);
  61.   SetText(buff);
  62. }
  63.  
  64. //----------------------------------------------------------------------------
  65.  
  66. TPrinterAbortDlg::TPrinterAbortDlg(TWindow* parent, TResId resId,
  67.   const char far* title, const char far* device, const char far* port)
  68.   : TDialog(parent, resId),
  69.     TWindow(parent, 0)
  70. {
  71.   new TFormattedStatic(this, ID_TITLE, title);
  72.   new TFormattedStatic(this, ID_DEVICE, device);
  73.   new TFormattedStatic(this, ID_PORT, port);
  74. }
  75.  
  76. void
  77. TPrinterAbortDlg::SetupWindow()
  78. {
  79.   TDialog::SetupWindow();
  80.   EnableMenuItem(GetSystemMenu(FALSE), SC_CLOSE, MF_GRAYED);
  81. }
  82.  
  83. LRESULT
  84. TPrinterAbortDlg::EvCommand(UINT id, HWND hWndCtl, UINT notifyCode)
  85. {
  86.   TPrinter::SetUserAbort();
  87.   return TDialog::EvCommand(id, hWndCtl, notifyCode);
  88. }
  89.  
  90.  
  91. //----------------------------------------------------------------------------
  92. //
  93. //  TPrinter is an encapsulation around the Windows printer device interface.
  94. //
  95. //  Examples:
  96. //   Creating a default device printing object:
  97. //
  98. //     DefaultPrinter = new TPrinter();
  99. //
  100. //   Creating a device for a specific printer:
  101. //
  102. //     PostScriptPrinter = new TPrinter();
  103. //     PostScriptPrinter->SetDevice("PostScript Printer", "PSCRIPT", "LPT2:");
  104. //
  105. //   Allowing the user to setup the printer:
  106. //
  107. //     DefaultPrinter->Setup(MyWindow);
  108. //
  109.  
  110. BOOL TPrinter::UserAbort;    // Set by printing dialog if user cancels
  111.  
  112. //
  113. // Initialize the TPrinter object assigned to the default printer
  114. //
  115. TPrinter::TPrinter()
  116. {
  117.   Data = new TPrintDialog::TData;
  118.   memset(Data, 0, sizeof(TPrintDialog::TData));
  119.   Data->Flags = PD_ALLPAGES | PD_COLLATE;
  120.   Data->FromPage = Data->ToPage = -1;
  121.  
  122.   Error = 0;
  123.   GetDefaultPrinter();
  124. }
  125.  
  126. //
  127. // Deallocate allocated resources
  128. //
  129. TPrinter::~TPrinter()
  130. {
  131.   delete Data;
  132. }
  133.  
  134. //
  135. // Clears the association of this printer object with the current device
  136. //
  137. void TPrinter::ClearDevice()
  138. {
  139.   Data->ClearDevMode();
  140.   Data->ClearDevNames();
  141. }
  142.  
  143. //
  144. // Updata Data with info on the user's default printer.
  145. //
  146. void
  147. TPrinter::GetDefaultPrinter()
  148. {
  149.   //
  150.   // Have a printDialog go get the default printer information for us
  151.   // into DevMode and DevNames. We never actually Execute() the dialog.
  152.   //
  153.   SETCLEAR(Data->Flags, 0, PD_RETURNDC);
  154.   TPrintDialog printDialog(0, *Data);
  155.   printDialog.GetDefaultPrinter();
  156. }
  157.  
  158. void
  159. TPrinter::SetPrinter(const char* driver, const char* device, const char* output)
  160. {
  161.   Data->SetDevNames(driver, device, output);
  162. }
  163.  
  164. //
  165. // Abort procedure used during printing
  166. //
  167. BOOL FAR PASCAL _export
  168. TPrinterAbortProc(HDC, short)
  169. {
  170.   TApplication* app = GetApplicationObject();
  171.   app->PumpWaitingMessages();
  172.   return !TPrinter::GetUserAbort(); // UserAbort will have been set in the AbortDialog
  173. }
  174.  
  175. BOOL
  176. TPrinter::ExecPrintDialog(TWindow* parent)
  177. {
  178.   return TPrintDialog(parent, *Data).Execute() == IDOK;
  179. }
  180.  
  181. TWindow*
  182. TPrinter::CreateAbortWindow(TWindow* parent, TPrintout& printout)
  183. {
  184.   TWindow* win = new TPrinterAbortDlg(parent, IDD_ABORTDIALOG,
  185.                                       printout.GetTitle(),
  186.                                       Data->GetDeviceName(),
  187.                                       Data->GetOutputName());
  188.   win->Create();
  189.   return win;
  190. }
  191.  
  192. //
  193. // Helper function for Print when it is banding to calculate banding flags
  194. // and rectangle.
  195. //
  196. void
  197. TPrinter::CalcBandingFlags(TPrintDC& prnDC)
  198. {
  199.   //
  200.   // Calculate text versus graphics banding
  201.   //
  202.   if (UseBandInfo) {
  203.     TBandInfo bandInfo;
  204.     unsigned  flags = 0;
  205.  
  206.     prnDC.BandInfo(bandInfo);
  207.     if (bandInfo.HasGraphics)
  208.       flags = pfGraphics;
  209.     if (bandInfo.HasText)
  210.       flags |= pfGraphics;
  211.     Flags = (Flags & ~pfBoth) | flags;
  212.  
  213.   } else {
  214.     //
  215.     // If a driver does not support BANDINFO the Microsoft recommended way
  216.     // of determining text only bands is if the first band is the full page,
  217.     // all others are graphics only.  Otherwise it handles both.
  218.     //
  219.     if (FirstBand && !BandRect.left && !BandRect.top &&
  220.         BandRect.right == PageSize.cx && BandRect.bottom == PageSize.cy)
  221.       Flags = pfText;
  222.     else
  223.       if ((Flags & pfBoth) == pfGraphics)
  224.         // All other bands are graphics only
  225.         Flags = (Flags & ~pfBoth) | pfGraphics;
  226.       else
  227.         Flags = Flags | pfBoth;
  228.   }
  229.   FirstBand = FALSE;
  230. }
  231.  
  232. //
  233. // Print the given printout to the printer, prompting the user with a
  234. // commdlg print dialog if indicated.
  235. //
  236. BOOL
  237. TPrinter::Print(TWindow* parent, TPrintout& printout, BOOL prompt)
  238. {
  239.   PRECONDITION(parent);
  240.  
  241.   // Start from scratch
  242.   //
  243.   Error = 0;
  244.   UserAbort = FALSE;
  245.   TPrintDC*   prnDC;
  246.   HCURSOR hOrigCursor = ::SetCursor(::LoadCursor(0, IDC_WAIT));
  247.  
  248.   //
  249.   // Get page range & selection range (if any) from document
  250.   //
  251.   int selFromPage;
  252.   int selToPage;
  253.   printout.GetDialogInfo(Data->MinPage, Data->MaxPage, selFromPage, selToPage);
  254.   if (selFromPage)
  255.     Data->Flags &= ~PD_NOSELECTION;
  256.   else
  257.     Data->Flags |= PD_NOSELECTION;
  258.   if (Data->MinPage) {
  259.     Data->Flags &= ~PD_NOPAGENUMS;
  260.     if (Data->FromPage < Data->MinPage)
  261.       Data->FromPage = Data->MinPage;
  262.     else if (Data->FromPage > Data->MaxPage)
  263.       Data->FromPage = Data->MaxPage;
  264.     if (Data->ToPage < Data->MinPage)
  265.       Data->ToPage = Data->MinPage;
  266.     else if (Data->ToPage > Data->MaxPage)
  267.       Data->ToPage = Data->MaxPage;
  268.   } else
  269.     Data->Flags |= PD_NOPAGENUMS;
  270.  
  271.   //
  272.   // Create & execute a TPrintDialog (or derived) and have it return a usable
  273.   // DC if prompt is enabled. If the dialog fails because the default printer
  274.   // changed, clear our device information & try again.
  275.   //
  276.   if (prompt) {
  277.     SETCLEAR(Data->Flags, PD_RETURNDC, PD_RETURNDEFAULT|PD_PRINTSETUP);
  278.     BOOL ok = ExecPrintDialog(parent);
  279.     if (!ok && Data->Error == PDERR_DEFAULTDIFFERENT) {
  280.       ClearDevice();
  281.       ok = ExecPrintDialog(parent);
  282.     }
  283.     if (!ok)
  284.       return FALSE;
  285.  
  286.     prnDC = Data->TransferDC();   // We now own the DC, let prnDC manage it
  287.  
  288.   // Construct the DC directly if prompting was not enabled.
  289.   //
  290.   } else {
  291.     prnDC = new TPrintDC(Data->GetDriverName(), Data->GetDeviceName(),
  292.                          Data->GetOutputName(), Data->GetDevMode());
  293.   }
  294.   if (!prnDC)
  295.     THROW( TXPrinter() );
  296.  
  297.   //
  298.   // Get the page size
  299.   //
  300.   PageSize.cx = prnDC->GetDeviceCaps(HORZRES);
  301.   PageSize.cy = prnDC->GetDeviceCaps(VERTRES);
  302.   printout.SetPrintParams(prnDC, PageSize);
  303.  
  304.   //
  305.   // Create modeless abort dialog using strings & unlock the devname struct
  306.   //
  307.   TWindow* abortWin;
  308.   TRY {
  309.     abortWin = CreateAbortWindow(parent, printout);
  310.   }
  311.   CATCH( (...) {
  312.     delete prnDC;
  313.     RETHROW;
  314.   })
  315.  
  316.   ::SetCursor(hOrigCursor);
  317.   parent->EnableWindow(FALSE);
  318.  
  319.   #if defined (__DLL__)
  320.     // We don't need to make a proc instance for DLLs
  321.     ABORTPROC abortProcInst = (ABORTPROC)TPrinterAbortProc;
  322.   #else
  323.     ABORTPROC abortProcInst = (ABORTPROC)MakeProcInstance((FARPROC)TPrinterAbortProc, *parent->GetModule());
  324.   #endif
  325.   prnDC->SetAbortProc(abortProcInst);
  326.  
  327.   //
  328.   // Only band if the user requests banding and the printer
  329.   // supports banding
  330.   //
  331.   BOOL banding = printout.WantBanding() &&
  332.                 (prnDC->GetDeviceCaps(RASTERCAPS) & RC_BANDING);
  333.   if (banding)
  334.     //
  335.     // Only use BANDINFO if supported.
  336.     //
  337.     UseBandInfo = prnDC->QueryEscSupport(BANDINFO);
  338.  
  339.   else
  340.     //
  341.     // Set the banding rectangle to full page
  342.     //
  343.     BandRect.Set(0, 0, PageSize.cx, PageSize.cy);
  344.  
  345.   //
  346.   // If more than one(uncollated) copy was requested, see if printer can
  347.   // handle it for performance and user convenience.
  348.   //
  349.   int copiesPerPass = 1;
  350.   if (!(Data->Flags & PD_COLLATE))
  351.     prnDC->SetCopyCount(Data->Copies, copiesPerPass);
  352.  
  353.   //
  354.   // Figure out which page range to use: Selection, Dialog's from/to,
  355.   // whole doc range or all possible pages.
  356.   //
  357.   int fromPage;
  358.   int toPage;
  359.   if (prompt && (Data->Flags & PD_SELECTION) || selFromPage) {
  360.     fromPage = selFromPage;
  361.     toPage = selToPage;
  362.   } else if (prompt && (Data->Flags & PD_PAGENUMS)) {
  363.     fromPage = Data->FromPage;
  364.     toPage = Data->ToPage;
  365.   } else if (Data->MinPage) {
  366.     fromPage = Data->MinPage;
  367.     toPage = Data->MaxPage;
  368.   } else {
  369.     fromPage = 1;
  370.     toPage = INT_MAX;
  371.   }
  372.  
  373.   //
  374.   // Copies loop, one pass per block of document copies.
  375.   //
  376.   printout.BeginPrinting();
  377.   for (int copies = Data->Copies; copies > 0; copies -= copiesPerPass) {
  378.  
  379.     //
  380.     // On last multi-copy pass, may need to adjust copy count
  381.     //
  382.     if (copiesPerPass > 1 && copies < copiesPerPass)
  383.       prnDC->SetCopyCount(copies, copiesPerPass);
  384.  
  385.     //
  386.     // Whole document loop, one pass per page
  387.     //
  388.     Flags = pfBoth;
  389.     Error = prnDC->StartDoc(printout.GetTitle(), 0);  // get PD_PRINTTOFILE ?
  390.     printout.BeginDocument(fromPage, toPage, Flags);
  391.  
  392.     for (int pageNum = fromPage;
  393.          Error > 0 && pageNum <= toPage && printout.HasPage(pageNum);
  394.          pageNum++) {
  395.  
  396.       //
  397.       // Begin the page by getting the first band or calling StartPage()
  398.       //
  399.       if (banding) {
  400.         FirstBand = TRUE;
  401.         Error = prnDC->NextBand(BandRect);
  402.       } else
  403.         Error = prnDC->StartPage();
  404.  
  405.       //
  406.       // Whole page loop, one pass per band (once when not banding)
  407.       //
  408.       while (Error > 0 && !BandRect.IsEmpty()) {
  409.         //
  410.         // [Manually call the abort proc between bands or pages]
  411.         //
  412.         #if defined(MANUAL_ABORT_CALL)
  413.           prnDC->QueryAbort();
  414.         #endif
  415.  
  416.         if (banding) {
  417.           CalcBandingFlags(*prnDC);
  418.           if (printout.WantForceAllBands() && (Flags & pfBoth) == pfGraphics)
  419.             prnDC->SetPixel(TPoint(0, 0), 0);  // Some old drivers need this 
  420.           prnDC->DPtoLP(BandRect, 2);
  421.         }
  422.  
  423.         printout.PrintPage(pageNum, BandRect, Flags);
  424.         if (banding)
  425.           Error = prnDC->NextBand(BandRect);
  426.         else
  427.           break;
  428.       }
  429.  
  430.       //
  431.       // EndPage (NEWFRAME) need only called if not banding
  432.       //
  433.       if (Error > 0 && !banding)
  434.         Error = prnDC->EndPage();
  435.  
  436.     }  // Whole Document-loop
  437.  
  438.     // Tell GDI the document is finished
  439.     if (Error > 0)
  440.       #if defined(MANUAL_ABORT_CALL)
  441.         if (banding && UserAbort)
  442.           prnDC->AbortDoc();
  443.         else
  444.       #endif
  445.         prnDC->EndDoc();
  446.  
  447.     printout.EndDocument();
  448.  
  449.   } // Copy-loop
  450.   printout.EndPrinting();
  451.  
  452.   if (copiesPerPass > 1)
  453.     prnDC->SetCopyCount(1, copiesPerPass);
  454.  
  455.   //
  456.   // Re-enable parent and free allocated resources
  457.   //
  458.   # if !defined (__DLL__)
  459.     FreeProcInstance((FARPROC)abortProcInst);
  460.   #endif
  461.  
  462.   parent->EnableWindow(TRUE);
  463.   abortWin->Destroy();
  464.   delete abortWin;
  465.   delete prnDC;
  466.  
  467.   //
  468.   // Report error if not already done so by printmgr
  469.   //
  470.   if (Error & SP_NOTREPORTED)
  471.     ReportError(parent, printout);
  472.  
  473.   return Error > 0 && !UserAbort;
  474. }
  475.  
  476. //
  477. // Setup opens a dialog as a child of the given window to setup the
  478. // printer using the commdlg printer setup. The options button
  479. // allows the user acces to the specific driver's options.
  480. //
  481. void TPrinter::Setup(TWindow* parent)
  482. {
  483.   SETCLEAR(Data->Flags, PD_PRINTSETUP, PD_RETURNDEFAULT|PD_RETURNDC);
  484.   ExecPrintDialog(parent);
  485. }
  486.  
  487. void
  488. TPrinter::ReportError(TWindow* parent, TPrintout& printout)
  489. {
  490.   WORD  errorId;
  491.  
  492.   switch (Error) {
  493.     case SP_ERROR:
  494.       errorId = IDS_PRNGENERROR;
  495.       break;
  496.     case SP_APPABORT:
  497.       errorId = IDS_PRNCANCEL;
  498.       break;
  499.     case SP_USERABORT:
  500.       errorId = IDS_PRNMGRABORT;
  501.       break;
  502.     case SP_OUTOFDISK:
  503.       errorId = IDS_PRNOUTOFDISK;
  504.       break;
  505.     case SP_OUTOFMEMORY:
  506.       errorId = IDS_PRNOUTOFMEMORY;
  507.       break;
  508.     default:
  509.       return;
  510.   }
  511.  
  512.   TModule& module = *parent->GetModule();
  513.   char  errorTemplate[40];
  514.   char  errorStr[40];
  515.   module.LoadString(IDS_PRNERRORTEMPLATE, errorTemplate, sizeof(errorTemplate));
  516.   module.LoadString(errorId, errorStr, sizeof(errorStr));
  517.  
  518.   char  errorMsg[80];
  519.   wsprintf(errorMsg, errorTemplate, printout.GetTitle(), (char far*)errorStr);
  520.  
  521.   char  errorCaption[80];
  522.   module.LoadString(IDS_PRNERRORCAPTION, errorCaption, sizeof(errorCaption));
  523.   parent->MessageBox(errorMsg, errorCaption, MB_OK | MB_ICONSTOP);
  524. }
  525.  
  526. TPrinter::TXPrinter::TXPrinter(UINT resId) : TXOwl(resId)
  527. {
  528. }
  529.  
  530. #endif
  531. #if !defined(SECTION) || SECTION == 2
  532.  
  533. IMPLEMENT_STREAMABLE(TPrinter);
  534.  
  535. void*
  536. TPrinter::Streamer::Read(ipstream& is, uint32 version) const
  537. {
  538.   GetObject()->Data->Read(is, version);
  539.   return GetObject();
  540. }
  541.  
  542. void
  543. TPrinter::Streamer::Write(opstream& os) const
  544. {
  545.   GetObject()->Data->Write(os);
  546. }
  547.  
  548. #endif
  549.  
  550.