[futurebasic] Re: [FB] Report Printing

Message: < previous - next > : Reply : Subscribe : Cleanse
Home   : June 2011 : Group Archive : Group : All Groups

From: Brian S <fblistserve@...>
Date: Sun, 19 Jun 2011 21:40:06 -0700
On Jun 11, 2011, at 8:13 PM, Brian S wrote:

> Acceptable solutions are anything that isn’t currently marked deprecated or legacy by Apple. CG/CT/CF and combinations thereof qualify as do Cocoa solutions.

Here is the report printing demo I threatened to post. No globals, no pascal strings. There are flaws with #3 being my concern. When compiled using Robert’s slick DECARBONATE define, LegacyAPISurvery shows zero. Hopefully, this will help anyone wanting to modernize code. Even though it probably will take a Cocoa solution to address flaw #3, my thought was most listers would prefer a non-Objective-C demo. Let me know if I’m wrong ( wouldn’t be the first time and won’t be the last! ).

'---------------------
/*
Print to Preview of columnar data using CoreText and Core Printing.

(1) Prints rudimentary columns with headings as a proof of concept
(2) fn PMSessionSetDestination used to send output to Preview app
(3) fn PMSessionGetCGGraphicsContext used to obtain CGContextRef.
(4) No QDBeginCGContext/QDEndCGContext required due to #3
(5) No draw handler because we don't want to explicitly request a carbon event
(6) Non-deprecated APIs used such as PMSessionBeginCGDocumentNoDialog

Known flaws and/or needing improvement:
(1) Pagination - page breaks are arbitrary for the demo and typically would be calculated.
(2) No error checking
(3) While not legacy/deprecated, PMSessionBeginPage(), PMSessionEndPage() and PMSessionEndDocument() are not in 64-bit Carbon 

by Brian S. 14-June-2011 
*/

include "Tlbx CoreText.incl"

// PMDefinitions.h
_kPMDestinationPrinter = 1
_kPMDestinationFile = 2
_kPMDestinationFax = 3
_kPMDestinationPreview = 4
_kPMDestinationProcessPDF = 5

_myLinesPerPage  = 40 // change to suit
_myColumnTabStop = 100// Tab stops are all 100 here but there is no need for them to be the same

#define PMDestinationType as UInt16

// PMCore.h
toolbox fn PMSessionSetDestination( PMPrintSession session,PMPrintSettings settings, PMDestinationType type, CFStringRef  format, CFURLRef location ) = OSStatus
toolbox fn PMSessionGetCGGraphicsContext( PMPrintSession printSession, CGContextRef *context ) = OSStatus
toolbox fn PMSessionBeginCGDocumentNoDialog( PMPrintSession printSession, PMPrintSettings settings, PMPageFormat format ) = OSStatus
toolbox fn PMSessionEndDocumentNoDialog ( PMPrintSession printSession ) = OSStatus

// PMApplication.h
toolbox fn PMSessionBeginCGDocument( PMPrintSession printSession, PMPrintSettings settings, PMPageFormat format ) = OSStatus


local fn EndPage(  printSession as ^PMPrintSession  )
'~'1
if ( printSession.nil& ) then fn PMSessionEndPage( printSession.nil& ) 
end fn


local fn EndPrintSession( printSession as ^PMPrintSession, printSettings as ^PMPrintSettings,  pageFormat as ^PMPageFormat )

// End Page & End Document
fn EndPage( #printSession )

fn PMSessionEndDocumentNoDialog( printSession.nil& ) // releases document to the Preview app for view/print by user

// Cleanup
fn PMRelease( printSession.nil& )
fn PMRelease( printSettings.nil& )
fn PMRelease( pageFormat.nil& )

end fn

local fn BeginPage ( printSession as ^PMPrintSession, pageFormat as ^PMPageFormat, ctx as ^CGContextRef )
'~'1
dim as OSStatus          err

// After each call to PMSessionBeginPage, the application calls PMSessionGetCGGraphicsContext to obtain the current printing CGContextRef.
err = fn PMSessionBeginPage( printSession.nil&, pageFormat.nil&, #0 )
err = fn PMSessionGetCGGraphicsContext( printSession.nil&, #ctx )

end fn

local fn SetUpPrinting( printSession as ^PMPrintSession, printSettings as ^PMPrintSettings, pageFormat as ^PMPageFormat, ctx as ^CGContextRef, orient as PMOrientation )
'~'1
dim as OSStatus               err
dim as Boolean              valid

// Get session, settings and set print destination
err = fn PMCreateSession( #printSession )
err = fn PMCreatePrintSettings( #printSettings )
if ( printSession.nil& ) then err = fn PMSessionDefaultPrintSettings( printSession.nil&, printSettings.nil& )
err = fn PMSessionValidatePrintSettings( printSession.nil&, printSettings.nil&, #_kPMDontWantBoolean )

err = fn PMSessionSetDestination( printSession.nil&, printSettings.nil&, _kPMDestinationPreview, #_nil, #_nil ) // open Preview app when done

// Page Format & Orientation
err = fn PMCreatePageFormat( #pageFormat )
err = fn PMSessionDefaultPageFormat( printSession.nil&, pageFormat.nil& )
err = fn PMSetOrientation( pageFormat.nil&, _kPMLandscape, _false )  // force landscape
err = fn PMSessionValidatePageFormat( printSession.nil&, pageFormat.nil&, @valid )

err = fn PMSessionBeginCGDocumentNoDialog( printSession.nil&, printSettings.nil&, pageFormat.nil& )

fn BeginPage( #printSession, #pageFormat, #ctx )

end fn


local fn PrintLine( ctx as CGContextRef, string as CFStringRef, x as CGFloat, y as CGFloat, font as CTFontRef, wantsUnderLine as Boolean )
'~'1
dim as CFIndex                       strLen
dim as CTLineRef                     lineRef
dim as CFMutableAttributedStringRef  attrStr
dim as CGColorRef                    black
dim as SInt32                        one
dim as CFNumberRef                   underline

// Create mutable attribute string
attrStr      = fn CFAttributedStringCreateMutable( _kCFAllocatorDefault, 0 )
CFAttributedStringReplaceString( attrStr, fn CFRangeMake( 0, 0 ), string )

// Apply font to entire string
strLen   = fn CFAttributedStringGetLength( attrStr )
CFAttributedStringSetAttribute( attrStr, fn CFRangeMake( 0, strLen ), kCTFontAttributeName, font )

// Apply black color to text
black = fn CGColorCreateGenericRGB( 0.0, 0.0, 0.0, 1.0 ) 
CFAttributedStringSetAttribute( attrStr, fn CFRangeMake( 0, strLen ), kCTForegroundColorAttributeName, black )

// Apply  underline to text - see other constant options 
long if ( wantsUnderLine )
one = _kCTUnderlineStyleSingle //_kCTUnderlineStyleNone    _kCTUnderlineStyleSingle  _kCTUnderlineStyleThick  _kCTUnderlineStyleDouble 
underline = fn CFNumberCreate( 0, _kCFNumberSInt32Type, @one )
CFAttributedStringSetAttribute( attrStr, fn CFRangeMake( 0, strLen ), kCTUnderlineStyleAttributeName, underline )
CFRelease( underline )
end if

// Create the line, set the draw x,y coordinates and draw it to the context
lineRef = fn CTLineCreateWithAttributedString( attrStr )
CGContextSetTextPosition( ctx, x, y )
CTLineDraw( lineRef, ctx )

CFRelease( lineRef )
CFRelease( attrStr )
CGColorRelease( black )
end fn


local fn PrintReportHeaders( ctx as CGContextRef )
'~'1
dim as CTFontRef         font
dim as CFStringRef       string
dim as CFIndex           i
dim as CGFloat           x, y

x = 20.0 : y = 550.0// should be measured instead of hard-code
font   = fn CTFontCreateWithName( @"Lucida Grande Bold", 14.0, 0 ) 

for i = 1 to 6
string = fn CFStringCreateWithFormat( _kCFAllocatorDefault, #0, @"%@%d", @"Head# ", i )
fn PrintLine( ctx, string, x, y, font, _true )
CFRelease( string )
x += 100
next

CFRelease( font)

end fn = y


local fn DoPageBreak( printSession as ^PMPrintSession, pageFormat as ^PMPageFormat, ctx as ^CGContextRef )
'~'1
fn EndPage( #printSession )
fn BeginPage( #printSession , #pageFormat, #ctx )

end fn


local fn DoPrinting
'~'1
dim as PMPrintSession    printSession  : printSession  = 0
dim as PMPrintSettings   printSettings : printSettings = 0
dim as CGContextRef      ctx
dim as CGFloat           x, y, ascent, descent, yOffset, xOffset
dim as PMPageFormat      pageFormat
dim as CTFontRef         font
dim as CFStringRef       string
dim as CFIndex           i,j

fn SetUpPrinting( @printSession, @printSettings, @pageFormat, @ctx, _kPMLandscape )// or _kPMPortrait

y = fn PrintReportHeaders( ctx )

font    = fn CTFontCreateWithName( @"Lucida Grande", 10.0, 0 )
ascent  = fn CTFontGetAscent( font )
descent = fn CTFontGetDescent( font )
yOffset = ascent + descent  + 1
xOffset = 20

// Outer loop is # of detail rows & inner loop # of columns in each row
for i = 1 to 85 // 85 rows
y -= yOffset :  x = xOffset

long if ( i mod _myLinesPerPage == 0 ) // page break at 40 lines per page
fn DoPageBreak( @printSession, @pageFormat, @ctx )
y = fn PrintReportHeaders( ctx )
y -= yOffset :  x = xOffset
end if

for j = 1 to 6// 6 columns of data
string = fn CFStringCreateWithFormat( _kCFAllocatorDefault, #0, @"%@ %d %d", @"Data# ", i,j )
fn PrintLine( ctx, string, x, y, font, _false )
CFRelease( string )
x += _myColumnTabStop
next

next

CFRelease( font )

fn EndPrintSession( @printSession, @printSettings, @pageFormat )

end fn

fn DoPrinting()

end
'------------------


Brian S