• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: Report printing
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Report printing


  • Subject: Re: Report printing
  • From: "Louis C. Sacha" <email@hidden>
  • Date: Sun, 30 Nov 2003 06:20:15 -0800

Hello...

Well, I didn't run into that problem for my implementation, because I was caching the PDF data outside the drawRect: method, mainly to speed up redrawing since the display involved a bunch of calculations on a large set of data. So I didn't have problems printing, because the PDF data was already cached (similar to the case where you created the pdf data in your initializer).

I did a bit of digging, and it appears the reason that it is failing for you when you try to make the PDF inside the drawRect: method is that there can only be one NSPrintOperation per thread. You already have one print operation running to print the whole printView, and the dataWithPDFInsideRect: method for the recordView uses a print operation to generate the PDF data (which fails). I figured this out from the documentation for NSPrintOperation in the AppKit documentation, based on the information about the class method PDFOperationWithView:insideRect:toData: which talks about raising an exception if there is already a
print operation in progress.

So there are two possible workarounds:

1) Similar to what you mentioned, create the pdfData for all of your records during the initialization of printView and store them in an NSArray that you add as an instance variable. Then during drawRect: access the records as needed out of the NSArray. Depending on how many records might be printed at one time, this might be the safest approach, but for large numbers of records it might result in memory problems and have speed issues.

2) Use multithreading to get around the one print operation per thread limit...

(Note: I created a test case to verify the original problem and make sure this solution actually works, but I haven't done any rigorous testing... so user beware. Hopefully other list members will point out any problems that might remain. This was tested on 10.2.6.)

To do this, you would need to add one instance variable and the following methods (or something similar) to your RecordView class:

@interface RecordView : NSView
{
...
volatile BOOL doneRendering;
}
...
@end

@implementation RecordView
...

- (NSData *)dataWithPDFInsideRect:(NSRect)rect
/* This method overrides the default NSView version to allow the view to be rendered to PDF within another print operation. If there is already a print operation running on the current thread, this method spawns a new thread to render the PDF, otherwise the default NSView version of dataWithPDFInsideRect: is called... */
{
if ([NSPrintOperation currentOperation])
{
NSMutableData *renderedData = [[NSMutableData alloc] init];
NSMutableDictionary *info = [NSMutableDictionary dictionary];
[info setObject:renderedData forKey:@"output"];
[info setObject:[NSValue valueWithRect:rect] forKey:@"region"];
doneRendering = FALSE;
[NSThread detachNewThreadSelector:@selector(_renderViewAsPDF:) toTarget:self withObject:info];
while (!doneRendering)
{
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.01]];
}
if ([renderedData length] > 0) {return [renderedData autorelease];}
else
{
[renderedData release];
return nil;
}
}
else
{
return [super dataWithPDFInsideRect:rect];
}
}

- (void)_renderViewAsPDF:(NSDictionary *)info
/* this method is not intended to be called directly */
/* used by dataWithPDFInsideRect: when multithreading is required */
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
BOOL success = FALSE;
NSRect rect = [(NSValue *)[info objectForKey:@"region"] rectValue];
NSMutableData *output = [info objectForKey:@"output"];
success = [[NSPrintOperation PDFOperationWithView:self insideRect:rect toData:output] runOperation];
if (!success) {[output setLength:0];}
doneRendering = TRUE;

[pool release];
}

@end


Hope that gets everything working for you.

Louis




Now, during printing, an alert dialog pops up, telling me that the print operation failed. Debugging shows that the

[recordView dataWithPDFInsideRect:[recordView bounds]]

message fails; I get the following output in the console window:

*** malloc[4379]: Deallocation of a pointer not malloced: 0xbfffcad0; This could be a double free(), or free() called with the middle of an allocated block; Try setting environment variable MallocHelp to see tools to help debug
2003-11-26 00:05:16.166 PayMaker[4379] PMSessionEndDocumentNoDialog failed (error code = -30879)
2003-11-26 00:05:16.166 PayMaker[4379] *** -[NSAutoreleasePool dealloc]: Exception ignored while releasing an object in an autorelease pool: NSInternalInconsistencyException Failed to end PMPrintContext


I'm stuck at this point. Why does dataWithPDFInsideRect fail within drawRect? I've tried to put pdfData = [recordView dataWithPDFInsideRect:[recordView bounds]] into printView's init method; there it works perfectly, I can later use the pdfData in drawRect as shown above and the recordView appears on my page as expected. recordView is not a subview of printView (it does not matter if it is or not; the error message remains the same).

Thanks for your help!

Beat
_______________________________________________
cocoa-dev mailing list | email@hidden
Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored.

References: 
 >Re: Report printing (From: Beat Koch <email@hidden>)

  • Prev by Date: Re: more float rounding info
  • Next by Date: Re: Getting NSTextField from NSWindow firstResponder
  • Previous by thread: Re: Report printing
  • Next by thread: Application Overview
  • Index(es):
    • Date
    • Thread