home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 January: Mac OS SDK / Dev.CD Jan 97 SDK2.toast / Development Kits (Disc 2) / OpenDoc / OpenDoc Development / Debugging Support / OpenDoc™ Source Code / Utilities / Printer.cpp < prev    next >
Encoding:
Text File  |  1996-08-28  |  16.9 KB  |  649 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        Printer.cpp
  3.  
  4.     Contains:    Base class for OpenDoc printing utility.
  5.  
  6.     Owned by:    Jens Alfke
  7.  
  8.     Copyright:    © 1995-96 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.          <2>      2/2/96    JA        Filled in header comments
  13.          <1>      2/2/96    JA        first checked in
  14.  
  15.     To Do:
  16. */
  17.  
  18.  
  19. // -- OpenDoc --
  20.  
  21. #ifndef _ALTPOINT_
  22. #include <AltPoint.h>
  23. #endif
  24.  
  25. #ifndef SOM_ODCanvas_xh
  26. #include <Canvas.xh>
  27. #endif
  28.  
  29. #ifndef SOM_ODClipboard_xh
  30. #include <Clipbd.xh>
  31. #endif
  32.  
  33. #ifndef SOM_Module_OpenDoc_Commands_defined
  34. #include <CmdDefs.xh>
  35. #endif
  36.  
  37. #ifndef SOM_ODDispatcher_xh
  38. #include <Disptch.xh>
  39. #endif
  40.  
  41. #ifndef SOM_ODFacet_xh
  42. #include <Facet.xh>
  43. #endif
  44.  
  45. #ifndef SOM_ODFrame_xh
  46. #include <Frame.xh>
  47. #endif
  48.  
  49. #ifndef SOM_ODMenuBar_xh
  50. #include <MenuBar.xh>
  51. #endif
  52.  
  53. #ifndef SOM_ODSession_xh
  54. #include <ODSessn.xh>
  55. #endif
  56.  
  57. #ifndef SOM_ODStorageSystem_xh
  58. #include <ODStor.xh>
  59. #endif
  60.  
  61. #ifndef SOM_ODPart_xh
  62. #include <Part.xh>
  63. #endif
  64.  
  65. #ifndef SOM_ODPlatformTypeList_xh
  66. #include <PfTypLs.xh>
  67. #endif
  68.  
  69. #ifndef SOM_ODShape_xh
  70. #include <Shape.xh>
  71. #endif
  72.  
  73. #ifndef SOM_Module_OpenDoc_StdProps_defined
  74. #include <StdProps.xh>
  75. #endif
  76.  
  77. #ifndef SOM_Module_OpenDoc_StdTypes_defined
  78. #include <StdTypes.xh>
  79. #endif
  80.  
  81. #ifndef SOM_ODStorageUnit_xh
  82. #include <StorageU.xh>
  83. #endif
  84.  
  85. #ifndef SOM_ODTransform_xh
  86. #include <Trnsform.xh>
  87. #endif
  88.  
  89. #ifndef SOM_ODWindowState_xh
  90. #include <WinStat.xh>
  91. #endif
  92.  
  93. // -- OpenDoc Utilities --
  94.  
  95. #ifndef _EXCEPT_
  96. #include <Except.h>
  97. #endif
  98.  
  99. #ifndef _ITEXT_
  100. #include <IText.h>
  101. #endif
  102.  
  103. #ifndef _DLOGUTIL_
  104. #include <DlogUtil.h>
  105. #endif
  106.  
  107. #ifndef _ODDEBUG_
  108. #include <ODDebug.h>
  109. #endif
  110.  
  111. #ifndef _ODNEW_
  112. #include <ODNew.h>
  113. #endif
  114.  
  115. #ifndef _ODUTILS_
  116. #include <ODUtils.h>
  117. #endif
  118.  
  119. #ifndef _STORUTIL_
  120. #include <StorUtil.h>
  121. #endif
  122.  
  123. #ifndef _TEMPOBJ_
  124. #include <TempObj.h>
  125. #endif
  126.  
  127. #ifndef _USERSRCM_
  128. #include <UseRsrcM.h>
  129. #endif
  130.  
  131. // -- MacToolbox --
  132.  
  133. #ifndef __GESTALT__
  134. #include <Gestalt.h>
  135. #endif
  136.  
  137. #ifndef __GXGRAPHICS__
  138. #include <GXGraphics.h>
  139. #endif
  140.  
  141. #ifndef __GXPRINTING__
  142. #include <GXPrinting.h>
  143. #endif
  144.  
  145. #ifndef __PRINTING__
  146. #include <Printing.h>
  147. #endif
  148.  
  149. #ifndef __TEXTUTILS__
  150. #include <TextUtils.h>
  151. #endif
  152.  
  153. #ifndef __TOOLUTILS__
  154. #include <ToolUtils.h>
  155. #endif
  156.  
  157. // -- Printer --
  158. #define _PRINTER_PRIVATE_
  159. #ifndef _PRINTER_
  160. #include "Printer.h"
  161. #endif
  162.  
  163. #pragma segment Printer
  164.  
  165.  
  166. //=================================================================================
  167. // CWithPrintingOpen helper class
  168. //
  169. //    This is a stack-based object that opens printing in its constructor and
  170. //    closes it in its destructor. This provides a simple and exception-safe way
  171. //    to open up printing for the duration of a method or block.
  172. //=================================================================================
  173.  
  174. CWithPrintingOpen::CWithPrintingOpen( CPrinter *printer )
  175.     :fPrinter(kODNULL)
  176. {
  177.     if( ! printer->IsPrintingOpen() ) {
  178.         printer->OpenPrinting();            // Only open it if it wasn't open
  179.         fPrinter = printer;
  180.     }
  181. }
  182.  
  183. CWithPrintingOpen::~CWithPrintingOpen( )
  184. {
  185.     if( fPrinter )
  186.         fPrinter->ClosePrinting();            // Only close if printing was already open
  187. }
  188.  
  189.  
  190. //=================================================================================
  191. // CWithDialogState helper class
  192. //
  193. //    This is a stack-based object that sets up state for a modal dialog in its
  194. //    constructor, and resets the state in the destructor. It deactivates the front
  195. //    window, removes the "Redo" item from the Edit menu, and updates the Mac scrap.
  196. //=================================================================================
  197.  
  198. CWithDialogState::CWithDialogState( Environment *ev, ODSession *session )
  199. {
  200.     GetPort(&fPort);
  201.     fEv = ev;
  202.     fWindowState = session->GetWindowState(ev);
  203.     TempODMenuBar menuBar = fWindowState->AcquireCurrentMenuBar(ev);
  204.     fWindowState->DeactivateFrontWindows(ev);
  205.     ODDialogBegin(ev, session, menuBar, kODNULL);
  206.     InitCursor();
  207. }
  208.  
  209. CWithDialogState::~CWithDialogState( )
  210. {
  211.     ODDialogEnd();
  212.     fWindowState->ActivateFrontWindows(fEv);
  213.     SetPort(fPort);
  214.     InitCursor();
  215. }
  216.  
  217.  
  218. //=================================================================================
  219. // BusyCursor helper function
  220. //=================================================================================
  221.  
  222. void BusyCursor( )
  223. {
  224.     SetCursor(*GetCursor(watchCursor));
  225. }
  226.  
  227. //=================================================================================
  228. // CPrinter implementation
  229. //=================================================================================
  230.  
  231. //---------------------------------------------------------------------------------
  232. // CPrinter::New  [static method]
  233. //---------------------------------------------------------------------------------
  234.  
  235. CPrinter* CPrinter::New( Environment *ev, ODStorageUnit *su )
  236. {
  237.     // Create & initialize the appropriate type of CPrinter object:
  238.     
  239.     long gxVersion, gxPrintVersion;
  240.     CPrinter *p;
  241.  
  242.     if ( Gestalt(gestaltGraphicsVersion, &gxVersion) == noErr &&
  243.             Gestalt(gestaltGXPrintingMgrVersion, &gxPrintVersion) == noErr &&
  244.             (void*)GXInitPrinting != (void*)kUnresolvedCFragSymbolAddress )
  245.         p= new CGXPrinter;
  246.     else
  247.         p= new CQDPrinter;
  248.         
  249.     TRY{
  250.         p->Initialize(ev,su);
  251.     }CATCH_ALL{
  252.         delete p;
  253.         RERAISE;
  254.     }ENDTRY
  255.     return p;
  256. }
  257.  
  258. //---------------------------------------------------------------------------------
  259. // CPrinter::CPrinter
  260. //---------------------------------------------------------------------------------
  261.  
  262. CPrinter::CPrinter()
  263. {
  264.     fDirty = kODFalse;
  265.     fPrintFacet = kODNULL;
  266.     fPrintingOpen = kODFalse;
  267. }
  268.  
  269. //---------------------------------------------------------------------------------
  270. // CPrinter::~CPrinter
  271. //---------------------------------------------------------------------------------
  272.  
  273. CPrinter::~CPrinter()
  274. {
  275.     WASSERTM(!fPrintingOpen,"Printing was not closed");
  276.     WASSERT(fPrintFacet==kODNULL);
  277.     ODSafeReleaseObject(fSU);
  278. }
  279.  
  280. //---------------------------------------------------------------------------------
  281. // CPrinter::Initialize
  282. //---------------------------------------------------------------------------------
  283.  
  284. void CPrinter::Initialize( Environment *ev, ODStorageUnit *su )
  285. {
  286.     ODAcquireObject(ev,su);
  287.     fSU = su;
  288.     fSession = ODGetSession(ev,su);
  289. }
  290.  
  291. //---------------------------------------------------------------------------------
  292. // CPrinter::OpenPrinting
  293. //---------------------------------------------------------------------------------
  294.  
  295. void CPrinter::OpenPrinting()
  296. {
  297.     WASSERTM(!fPrintingOpen,"OpenPrinting called twice");
  298.     fPrintingOpen = kODTrue;
  299. }
  300.  
  301. //---------------------------------------------------------------------------------
  302. // CPrinter::ClosePrinting
  303. //---------------------------------------------------------------------------------
  304.  
  305. void CPrinter::ClosePrinting()
  306. {
  307.     WASSERTM(fPrintingOpen,"ClosePrinting called twice");
  308.     fPrintingOpen = kODFalse;
  309. }
  310.  
  311. //---------------------------------------------------------------------------------
  312. // CPrinter::GetPlatformPrintJob
  313. //---------------------------------------------------------------------------------
  314.  
  315. ODPlatformPrintJob CPrinter::GetPlatformPrintJob( Environment* ev )
  316. {
  317.     // If the print job has not yet been loaded/created, do so now.
  318.     // Try to read a graphics-system-specific value from the standard page-setup property.
  319.     // The platform-specific subclass will do the dirty work of interpreting the
  320.     // data in the value, which we read into a handle for its convenience.
  321.     // If there is no stored page setup or it couldn't be read, make up a new one.
  322.     
  323.     ODPlatformPrintJob job = this->BasicGetPlatformPrintJob( );
  324.     
  325.     if( !job ) {
  326.         CWithPrintingOpen w(this);
  327.         
  328.         TRY
  329.             // Focus the storageUnit to the Print Job property.
  330.             if ( fSU->Exists(ev, kODPropPageSetup, kODNULL, 0) )
  331.             {
  332.                 ODValueType valueType = this->GetValueType();
  333.                 ODBoolean exists = fSU->Exists(ev,kODPropPageSetup,valueType,0);
  334.                 if( !exists ) {
  335.                     // Couldn't find main value type, try secondary one:
  336.                     valueType = this->GetSecondaryValueType();
  337.                     exists = valueType!=kODNULL && fSU->Exists(ev,kODPropPageSetup,valueType,0);
  338.                 }
  339.                 if( exists ) {
  340.                     // Found a value, now read it:
  341.                     fSU->Focus(ev, kODPropPageSetup, 0, valueType, 0, kODPosAll);
  342.                 
  343.                     ODULong size = fSU->GetSize(ev);
  344.                     TempODHandle data = ODNewHandle(size);
  345.                     StorageUnitGetValue(fSU,ev,size,ODLockHandle(data));
  346.                     ODUnlockHandle(data);
  347.                     job= this->ReadJobFromHandle(valueType,data.DontDelete());
  348.                 }
  349.             }
  350.         CATCH_ALL
  351.             WARN("Error %d internalizing print job",ErrorCode());
  352.         ENDTRY
  353.         
  354.         if( !job ) {
  355.             // Let's just make a new one:
  356.             job= this->CreateNewJob();
  357.             ASSERT(job!=kODNULL,kODErrAssertionFailed);
  358.         }
  359.     }
  360.     return job;
  361. }
  362.  
  363. //---------------------------------------------------------------------------------
  364. // CPrinter::Externalize
  365. //---------------------------------------------------------------------------------
  366.  
  367. void CPrinter::Externalize( Environment* ev, ODStorageUnit *su /*=kODNULL*/ )
  368. {
  369.     // su may be different from the part's storage unit (fSU) if the part
  370.     // is being cloned. NULL means use part's storage unit.
  371.     
  372.     if( su==kODNULL ) su=fSU;
  373.     
  374.     if( fDirty || su!=fSU ) {
  375.         CWithPrintingOpen w(this);
  376.         this->GetPlatformPrintJob(ev);
  377.         
  378.         TempODHandle data = this->CopyJobToHandle();
  379.         
  380.         // Focus to / create the Print Job property & value:
  381.         ODSUForceFocus(ev,su,kODPropPageSetup, this->GetValueType());
  382.         ODSize size = su->GetSize(ev);
  383.         if( size>0 )
  384.             su->DeleteValue(ev,size);
  385.         StorageUnitSetValue(su,ev,ODGetHandleSize(data),ODLockHandle(data));
  386.         
  387.         if( su==fSU )
  388.             fDirty = kODFalse;
  389.     }
  390. }
  391.  
  392. //---------------------------------------------------------------------------------
  393. // CPrinter::PageSetup
  394. //---------------------------------------------------------------------------------
  395.  
  396. ODBoolean CPrinter::PageSetup(Environment* ev)
  397. {
  398.     ODBoolean success = kODFalse;
  399.  
  400.     TRY
  401.         BusyCursor();
  402.         CWithPrintingOpen w(this);
  403.         CWithDialogState d(ev,fSession);
  404.         
  405.         this->GetPlatformPrintJob(ev);
  406.         
  407.         // Display the Page Setup dialog.
  408.         ODError err = kODNoError;
  409.         TRY{
  410.             success = this->RunPageSetupDialog(ev);
  411.             if( success )
  412.                 fDirty = kODTrue;
  413.         }CATCH_ALL{
  414.             err = ErrorCode();
  415.         }ENDTRY
  416.         
  417.         THROW_IF_ERROR(err);
  418.  
  419.     CATCH_ALL
  420.         this->DisplayError(ev, ErrorCode());
  421.         success= kODFalse;
  422.     ENDTRY
  423.     InitCursor();
  424.     
  425.     return success;
  426. }
  427.  
  428. //---------------------------------------------------------------------------------
  429. // CPrinter::PrintDocument
  430. //---------------------------------------------------------------------------------
  431.  
  432. void CPrinter::PrintDocument(Environment* ev, ODFrame* initiator, ODShape* area /*=kODNULL*/)
  433. {
  434.     BusyCursor();
  435.     
  436.     // If no area is specified, use the frameshape:
  437.     ODBoolean noAreaSupplied = (area==kODNULL);
  438.     if( noAreaSupplied )
  439.         area = initiator->AcquireFrameShape(ev,kODNULL);
  440.  
  441.     TRY
  442.         CWithDialogState d(ev,fSession);
  443.         
  444.         this->GetPlatformPrintJob(ev);
  445.         
  446.         CWithPrintingOpen w(this);
  447.     
  448.         ODError err = kODNoError;
  449.         TRY{
  450.             if ( this->RunPrintDialog(ev) ) {
  451.                 BusyCursor();
  452.                 // Create OpenDoc printing geometry objects.
  453.                 this->SetupPrintingEnv(ev, initiator, area);
  454.             
  455.                 this->DoPrint(ev,area);
  456.             }
  457.         }CATCH_ALL{
  458.             err = ErrorCode();
  459.         }ENDTRY
  460.         
  461.         // Tear down printing objects. We do this here instead of right after DoPrint
  462.         // so that the cleanup will happen even if SetupPrintingEnv or DoPrint throw.
  463.         this->CleanupPrintingEnv(ev, initiator);
  464.         InitCursor();
  465.  
  466.         THROW_IF_ERROR(err);        // Reraise the error, if any
  467.     
  468.     CATCH_ALL
  469.         this->DisplayError(ev, ErrorCode());
  470.         // don't reraise...
  471.     ENDTRY
  472.  
  473.     if( noAreaSupplied )
  474.         ODReleaseObject(ev,area);
  475. }
  476.  
  477.  
  478. //---------------------------------------------------------------------------------
  479. // CPrinter::SetupPrintingEnv
  480. //---------------------------------------------------------------------------------
  481.  
  482. void CPrinter::SetupPrintingEnv(Environment* ev, ODFrame* initiator, ODShape *area)
  483. {
  484.     if( fPrintFacet )
  485.         return;
  486.         
  487.     TempODPart part = initiator->AcquirePart(ev);
  488.  
  489.     // Create an external transform for our new facet. It has to counteract the
  490.     // frame's internal transform in case the frame is scrolled/zoomed/whatever.
  491.     TempODTransform xtransform = ODCopyAndRelease(ev,initiator->AcquireInternalTransform(ev,kODNULL));
  492.     xtransform->Invert(ev);
  493.     
  494.     // Create a shape for the clip-shape. It doesn't matter what it is; it'll get
  495.     // set properly in the SetPage method.
  496.     TempODShape clipshape = initiator->CreateShape(ev);
  497.  
  498.     // Get info about the type of canvas to create.
  499.     ODGraphicsSystem arch = this->GetGraphicsSystem();
  500.     ODPlatformCanvas port = this->CreatePrintingPlatformCanvas(ev,arch,initiator,area);
  501.  
  502.     // Get the window state to create objects. We need to do this
  503.     // because we don't have a valid facet yet.
  504.     ODWindowState* windowState = fSession->GetWindowState(ev);
  505.     
  506.     // Creating a printing canvas to add to our new facet.
  507.     ODCanvas* canvas = windowState->CreateCanvas(ev, arch, port, kODFalse, kODFalse);
  508.     TempODObject tempcanvas = canvas;        // Make sure it gets deleted on exception
  509.     if( arch != kODQuickDraw ) {
  510.         // Set up QD platform canvas if there isn't one already:
  511.         canvas->SetPlatformCanvas(ev, kODQuickDraw,
  512.                         this->CreatePrintingPlatformCanvas(ev,kODQuickDraw,initiator,area));
  513.     }
  514.     
  515.     canvas->SetOwner(ev, part);
  516.     canvas->SetPlatformPrintJob(ev, arch, this->GetPlatformPrintJob(ev));
  517.     
  518.     // Create a printing facet.
  519.     tempcanvas=kODNULL;
  520.     fPrintFacet = windowState->CreateFacet(ev, initiator, clipshape, xtransform,
  521.                                                 canvas, kODNULL);
  522.  
  523.     // Notify the intiator that a printing facet has been added to it.
  524.     TRY{
  525.         initiator->FacetAdded(ev, fPrintFacet);
  526.     }CATCH_ALL{
  527.         // ignore exceptions from part.
  528.     }ENDTRY
  529. }
  530.  
  531. //---------------------------------------------------------------------------------
  532. // CPrinter::CleanupPrintingEnv
  533. //---------------------------------------------------------------------------------
  534.  
  535. void CPrinter::CleanupPrintingEnv(Environment* ev, ODFrame* initiator)
  536. {
  537.     // Subclass should override to dispose platform canvas / platform print-job.
  538.     
  539.     if( fPrintFacet ) {
  540.         TRY{
  541.             initiator->FacetRemoved(ev, fPrintFacet);
  542.         }CATCH_ALL{
  543.         }ENDTRY
  544.         ODCanvas *canvas = fPrintFacet->GetCanvas(ev);
  545.         canvas->SetFacet(ev,kODNULL);
  546.         ODDeleteObject(fPrintFacet);
  547.         ODDeleteObject(canvas);
  548.     }
  549. }
  550.  
  551. //---------------------------------------------------------------------------------
  552. // CPrinter::CountPages
  553. //---------------------------------------------------------------------------------
  554.  
  555. ODULong CPrinter::CountPages(Environment* ev, ODShape* area)
  556. {
  557.     ODRect contentRect;
  558.     area->GetBoundingBox(ev, &contentRect);
  559.     
  560.     ODRect pageRect = this->GetPageRect(ev);
  561.     
  562.     ODULong horiPages = (contentRect.Width()+pageRect.Width()-1)   / pageRect.Width();
  563.     ODULong vertPages = (contentRect.Height()+pageRect.Height()-1) / pageRect.Height();
  564.     
  565.     ODULong pageCount = horiPages * vertPages;
  566.     if( pageCount == 0 )
  567.         pageCount = 1;
  568.     
  569.     return pageCount;
  570. }
  571.  
  572. //---------------------------------------------------------------------------------
  573. // CPrinter::SetPage
  574. //---------------------------------------------------------------------------------
  575.  
  576. void CPrinter::SetPage(Environment* ev, ODUShort pageNum, ODShape* area)
  577. {
  578.     ODRect contentRect;
  579.     area->GetBoundingBox(ev, &contentRect);
  580.     
  581.     ODRect pageRect = this->GetPageRect(ev);
  582.     
  583.     // Calc horizontal pages, don't let be less than one
  584.     ODUShort horiPages = (contentRect.Width()+pageRect.Width()-1) / pageRect.Width();
  585.     if (horiPages < 1)
  586.         horiPages = 1;
  587.     
  588.     // Set up a clip-shape to fit the transformed facet:
  589.     TempODShape clipShape = fPrintFacet->CreateShape(ev);
  590.     clipShape->SetRectangle(ev, &pageRect);
  591.     clipShape->Intersect(ev,area);                    // Restrict to frameshape
  592.     
  593.     // Create an offset which translates the clip shape (page region)
  594.     // back to a {0,0} coordinate space.
  595.     ODPoint offset;
  596.     offset.x = -( contentRect.left + ((pageNum - 1) % horiPages) * pageRect.Width() );
  597.     offset.y = -( contentRect.top  + ((pageNum - 1) / horiPages) * pageRect.Height() ); 
  598.  
  599.     TempODTransform transform = fPrintFacet->AcquireExternalTransform(ev,kODNULL);
  600.     transform->MoveBy(ev, &offset);                    // Scroll the external transform
  601.     
  602.     clipShape->InverseTransform(ev,transform);
  603.  
  604.     // Update the facet's geometry.
  605.     fPrintFacet->ChangeGeometry(ev, clipShape, transform, fPrintFacet->GetCanvas(ev));
  606. }
  607.  
  608. //---------------------------------------------------------------------------------
  609. // CPrinter::PrintPage
  610. //---------------------------------------------------------------------------------
  611.  
  612. void CPrinter::PrintPage(Environment* ev, ODUShort page, ODShape *area)
  613. {
  614.     // Main routine to print a particular page.
  615.     
  616.     this->SetPage(ev, page, area);
  617.     this->OpenPage(ev, page);
  618.     
  619.     TempODShape clip = fPrintFacet->AcquireClipShape(ev, kODNULL);
  620.     fPrintFacet->Update(ev, clip, kODNULL);
  621.     
  622.     this->ClosePage(ev);
  623. }
  624.  
  625. //---------------------------------------------------------------------------------
  626. // CPrinter::DisplayError
  627. //---------------------------------------------------------------------------------
  628.  
  629. void CPrinter::DisplayError(Environment* ev, ODSShort error)
  630. {
  631.     Str255        message;
  632.     Str15        number;
  633.     
  634.     CUsingLibraryResources r;
  635.     CWithDialogState d(ev,fSession);
  636.     
  637.     // Use the default (generic) error message unless we recognize the
  638.     // error number.
  639.     ODUShort index = 1;
  640.     if ( error == -4101 || error == fnfErr )
  641.         index = 2;                                        // no printer selected.
  642.     
  643.     GetIndString(message, rPrintErrorsID, index);
  644.     NumToString(error,number);
  645.     ParamText(message,number,kODNULL,kODNULL);
  646.  
  647.     ShowAlert(ev,rPrintErrorDialog,kODNULL,fSession);
  648. }
  649.