Class Description
NSPrintPanel provides a standard print panel allowing the user to
specify information about how a document is to be printed, including
the page range, number of copies and scale of the document. It also
allows the user to save the document to a file or preview it.
When a print: message is sent to an NSView or NSWindow, an
NSPrintOpertation is created which manages printing of a view. The
NSPrintOperation object would by default show a print panel in a modal
loop for the user. You can avoid showing the print panel by sending
the setShowsPanels: message in the print operation with a NO argument.
*/
@implementation NSPrintPanel
//
// Class Methods
//
/** Creates and returns a shared instance of the NSPrintPanel panel.
*/
+ (NSPrintPanel *)printPanel
{
if (shared_instance == nil)
{
shared_instance = [[NSPrintPanel alloc] init];
}
return shared_instance;
}
//
// Instance methods
//
- (id) init
{
int style = NSTitledWindowMask;
NSRect frame = NSMakeRect(300, 300, 420, 350);
return [self initWithContentRect: frame
styleMask: style
backing: NSBackingStoreBuffered
defer: YES];
}
/* Designated initializer */
- (id) initWithContentRect: (NSRect)contentRect
styleMask: (unsigned int)aStyle
backing: (NSBackingStoreType)bufferingType
defer: (BOOL)flag
screen: (NSScreen*)aScreen
{
int i;
id control;
NSArray *subviews, *list;
NSString *panel;
NSDictionary *table;
self = [super initWithContentRect: contentRect
styleMask: aStyle
backing: bufferingType
defer: flag
screen: aScreen];
if (self == nil)
return nil;
panel = [NSBundle pathForGNUstepResource: GSPANELNAME ofType: @"gorm"
inDirectory: nil];
if (panel == nil)
{
NSRunAlertPanel(@"Error", @"Could not find print panel resource",
@"OK", NULL, NULL);
return nil;
}
table = [NSDictionary dictionaryWithObject: self forKey: @"NSOwner"];
if ([NSBundle loadNibFile: panel
externalNameTable: table
withZone: [self zone]] == NO)
{
NSRunAlertPanel(@"Error", @"Could not load print panel resource",
@"OK", NULL, NULL);
return nil;
}
/* Transfer the objects to us. FIXME: There must be a way to
instantiate the panel directly */
subviews = [[_panel contentView] subviews];
for (i = 0; i < [subviews count]; i++)
{
[_contentView addSubview: [subviews objectAtIndex: i]];
}
DESTROY(_panel);
/* Setup the layout popup */
control = CONTROL(self, NSPPLayoutButton);
list = [NSArray arrayWithObjects: @"1 up", @"2 up", @"4 up", @"6 up",
@"8 up", nil];
[control removeAllItems];
for (i = 0; i < [list count]; i++)
{
[control addItemWithTitle: [list objectAtIndex: i]];
}
[control selectItemAtIndex: 0];
return self;
}
//
// Customizing the Panel
//
/** Set the accessory view for the print panel
*/
- (void)setAccessoryView:(NSView *)aView
{
ASSIGN(_accessoryView, aView);
}
/** Returns the accessory view for the print panel
*/
- (NSView *)accessoryView
{
return _accessoryView;
}
//
// Running the Panel
//
/** Display the Print panel in a modal loop. Saves any aquired
information in the NSPrintInfo object for the current NSPrintOperation.
Returns NSCancelButton if the user clicks the Cancel button or
NSOKButton otherwise.
*/
- (int)runModal
{
_picked = NSOKButton;
[NSApp runModalForWindow: self];
[_optionPanel orderOut: self];
[self orderOut: self];
return (_picked == NSCancelButton) ? NSCancelButton : NSOKButton;
}
- (void) beginSheetWithPrintInfo: (NSPrintInfo *)printInfo
modalForWindow: (NSWindow *)docWindow
delegate: (id)delegate
didEndSelector: (SEL)didEndSelector
contextInfo: (void *)contextInfo
{
_picked = NSOKButton;
[NSApp beginSheet: self
modalForWindow: docWindow
modalDelegate: delegate
didEndSelector: didEndSelector
contextInfo: contextInfo];
[_optionPanel orderOut: self];
[self orderOut: self];
}
- (BOOL) _getSavePath
{
int result;
NSSavePanel *sp;
sp = [NSSavePanel savePanel];
[sp setRequiredFileType: @"ps"];
result = [sp runModal];
if (result == NSOKButton)
{
_savePath = RETAIN([sp filename]);
}
return (result == NSOKButton);
}
/* Private communication with our panel objects */
- (void) _pickedButton: (id)sender
{
int tag = [sender tag];
if (tag == NSPPSaveButton)
{
_picked = NSPPSaveButton;
if ([self _getSavePath] == NO)
{
/* User pressed save, then changed his mind, so go back to
the print panel (don't stop the modal session) */
return;
}
}
else if (tag == NSPPPreviewButton)
{
_picked = NSPPPreviewButton;
NSRunAlertPanel(@"Sorry", @"Previewing of print file not implemented",
@"OK", NULL, NULL);
/* Don't stop the modal session */
return;
}
else if (tag ==NSFaxButton )
{
_picked = NSFaxButton;
NSRunAlertPanel(@"Sorry", @"Faxing of print file not implemented",
@"OK", NULL, NULL);
/* Don't stop the modal session */
return;
}
else if (tag == NSCancelButton)
{
_picked = NSCancelButton;
}
else if (tag == NSOKButton)
{
_picked = NSOKButton;
}
else if (tag == NSPPOptionsButton)
{
/* Open the options panel */
NSLog(@"Running _optionPanel modal");
[NSApp runModalForWindow: _optionPanel];
[_optionPanel orderOut: self];
return;
}
else if (tag == NSPPOptionOKButton)
{
NSLog(@"order out options");
/* Do nothing. Just stops model on the options panel */
}
else
{
NSLog(@"Print panel buttonAction: from unknown sender - x%x\n",
(unsigned)sender);
}
[NSApp stopModalWithCode: _picked];
}
- (void) _pickedPage: (id)sender
{
id pageMatrix = CONTROL(self, NSPPPageChoiceMatrix);
id fromRangeForm = CONTROL(self, NSPPPageRangeFrom);
id toRangeForm = CONTROL(self, NSPPPageRangeTo);
if ([pageMatrix selectedColumn] == 0)
{
[[fromRangeForm cellAtIndex: 0] setStringValue: @"" ];
[[toRangeForm cellAtIndex: 0] setStringValue: @"" ];
}
else
{
NSString *str;
str = [NSString stringWithFormat: @"%d", _pages.location];
[[fromRangeForm cellAtIndex: 0] setStringValue: str];
str = [NSString stringWithFormat: @"%d", NSMaxRange(_pages)-1];
[[toRangeForm cellAtIndex: 0] setStringValue: str];
}
}
/* Depreciated communication methods */
/** This method has been depreciated. It doesn't do anything useful.
*/
- (void)pickedButton:(id)sender
{
NSLog(@"[NSPrintPanel -pickedButton:] method depreciated");
[self pickedButton: sender];
}
/** This method has been depreciated. It doesn't do anything useful.
*/
- (void)pickedAllPages:(id)sender
{
NSLog(@"[NSPrintPanel -pickedAllPages:] method depreciated");
[self _pickedPage: sender];
}
/** This method has been depreciated. It doesn't do anything useful.
*/
- (void)pickedLayoutList:(id)sender
{
NSLog(@"[NSPrintPanel -pickedLayoutList:] method depreciated");
}
//
// Communicating with the NSPrintInfo Object
//
/** Setup the display in the receiver's panel based on the values stored
in the NSPrintInfo object from the current NSPrintOperation.
*/
- (void)updateFromPrintInfo
{
id control;
int layout;
double scale;
NSString *str;
NSPrinter *printer;
NSDictionary *dict;
NSPrintInfo* info = [[NSPrintOperation currentOperation] printInfo];
printer = [info printer];
dict = [info dictionary];
/* Setup printer information */
[CONTROL(self, NSPPNameField) setStringValue: [printer name] ];
[CONTROL(self, NSPPNoteField) setStringValue: [printer note] ];
[CONTROL(self, NSPPStatusField) setStringValue: @"Idle" ];
/* Setup copies, page range, scale */
[CONTROL(self, NSPPCopiesField) setIntValue: 1];
[[CONTROL(self, NSPPPageRangeFrom) cellAtIndex: 0] setStringValue: @"" ];
[[CONTROL(self, NSPPPageRangeTo) cellAtIndex: 0] setStringValue: @"" ];
[CONTROL(self, NSPPPageChoiceMatrix) selectCellAtRow: 0 column: 0];
if ([dict objectForKey: NSPrintScalingFactor])
scale = [[dict objectForKey: NSPrintScalingFactor] doubleValue];
else
scale = 0;
if (scale == 0)
scale = 1;
[CONTROL(self, NSPPScaleField) setIntValue: (int)(scale*100)];
dict = [info dictionary];
NSDebugLLog(@"NSPrinting",
@"Update PrintInfo dictionary\n %@ \n --------------", dict);
_pages = NSMakeRange([[dict objectForKey: NSPrintFirstPage] intValue],
[[dict objectForKey: NSPrintLastPage] intValue]);
if (NSMaxRange(_pages) == 0)
_pages = NSMakeRange(1, 0);
/* Setup the layout popup */
layout = [[dict objectForKey: NSPrintPagesPerSheet] intValue];
if (layout == 0)
layout = 1;
if (layout > 4)
layout = 4;
control = CONTROL(self, NSPPLayoutButton);
[control selectItemAtIndex: (int)(layout/2)];
/* Setup the resolution popup */
control = CONTROL(_optionPanel, NSPPResolutionButton);
[control removeAllItems];
/* FIXME: Get default from printInfo? */
str = [printer stringForKey:@"DefaultResolution" inTable: @"PPD"];
if (str)
{
NSArray *list;
list = [printer stringListForKey:@"Resolution" inTable: @"PPD"];
if ([list count])
{
int i;
NSString *display, *option;
for (i = 0; i < [list count]; i++)
{
NSString *key = [list objectAtIndex: i];
option = [@"Resolution/" stringByAppendingString: key];
display = [printer stringForKey: option
inTable: @"PPDOptionTranslation"];
if (display == nil)
display = key;
[control addItemWithTitle: display];
}
option = [@"Resolution/" stringByAppendingString: str];
display = [printer stringForKey: option
inTable: @"PPDOptionTranslation"];
if (display == nil)
display = str;
[control selectItemWithTitle: display];
}
else
{
[control addItemWithTitle: str];
}
}
else
[control addItemWithTitle: @"Unknown"];
/* Setup the paper feed popup */
control = CONTROL(_optionPanel, NSPPPaperFeedButton);
[control removeAllItems];
str = [printer stringForKey:@"DefaultInputSlot" inTable: @"PPD"];
if (str)
{
NSString *manual;
NSArray *list;
manual = [printer stringForKey:@"DefaultManualFeed" inTable: @"PPD"];
if (manual)
[control addItemWithTitle: @"Manual"];
list = [printer stringListForKey:@"InputSlot" inTable: @"PPD"];
if ([list count])
{
int i;
NSString *display, *option;
for (i = 0; i < [list count]; i++)
{
NSString *paper = [list objectAtIndex: i];
option = [@"InputSlot/" stringByAppendingString: paper];
display = [printer stringForKey: option
inTable: @"PPDOptionTranslation"];
if (display == nil)
display = paper;
[control addItemWithTitle: display];
}
/* FIXME: What if manual is default ? */
option = [@"InputSlot/" stringByAppendingString: str];
display = [printer stringForKey: option
inTable: @"PPDOptionTranslation"];
if (display == nil)
display = str;
[control selectItemWithTitle: display];
}
else
{
[control addItemWithTitle: str];
}
}
else
[control addItemWithTitle: @"Unknown"];
}
#define NSNUMBER(a) [NSNumber numberWithInt: (a)]
/** Saves information set by the user in the receiver's panel
in the NSPrintInfo object from the current NSPrintOperation.
*/
- (void)finalWritePrintInfo
{
id control;
double scale;
int layout;
NSString *sel;
NSArray *list;
NSPrinter *printer;
NSMutableDictionary *dict;
NSMutableDictionary *features;
NSPrintInfo* info = [[NSPrintOperation currentOperation] printInfo];
dict = [info dictionary];
printer = [info printer];
features = [dict objectForKey: NSPrintJobFeatures];
/* Copies */
control = CONTROL(self, NSPPCopiesField);
if ([control intValue] > 1)
{
[dict setObject: NSNUMBER([control intValue])
forKey: NSPrintCopies];
}
/* Pages */
control = CONTROL(self, NSPPPageChoiceMatrix);
if ([control selectedColumn] != 0)
{
id fromRangeForm = CONTROL(self, NSPPPageRangeFrom);
id toRangeForm = CONTROL(self, NSPPPageRangeTo);
[dict setObject: NSNUMBER([[fromRangeForm cellAtIndex: 0] intValue])
forKey: NSPrintFirstPage];
[dict setObject: NSNUMBER([[toRangeForm cellAtIndex: 0] intValue])
forKey: NSPrintLastPage];
[dict setObject: NSNUMBER(NO) forKey: NSPrintAllPages];
}
else
[dict setObject: NSNUMBER(YES) forKey: NSPrintAllPages];
/* Scale */
control = CONTROL(self, NSPPScaleField);
scale = [control doubleValue]/100.0;
if (scale <= 0)
scale = .1;
if (scale >= 10)
scale = 10;
[control setIntValue: (int)(scale*100)];
[dict setObject: [NSNumber numberWithDouble: scale]
forKey: NSPrintScalingFactor];
/* Layout */
layout = [CONTROL(self, NSPPLayoutButton) indexOfSelectedItem] * 2;
if (layout == 0)
layout = 1;
[dict setObject: NSNUMBER(layout) forKey: NSPrintPagesPerSheet];
/* Resolution */
/* Here we take advantage of the fact the names in the popup list
are in the same order as the PPD file, so we don't actually compare
the values */
control = CONTROL(_optionPanel, NSPPResolutionButton);
list = [printer stringListForKey: @"Resolution" inTable: @"PPD"];
if (list)
{
NSString *def;
sel = [list objectAtIndex: [control indexOfSelectedItem]];
def = [printer stringForKey:@"DefaultResolution" inTable: @"PPD"];
if ([sel isEqual: def] == NO
|| [features objectForKey: @"Resolution"])
{
if (features == nil)
{
features = [NSMutableDictionary dictionary];
[dict setObject: features forKey: NSPrintJobFeatures];
}
sel = [@"Resolution/" stringByAppendingString: sel];
[features setObject: sel forKey: @"Resolution"];
}
}
/* Input Slot */
control = CONTROL(_optionPanel, NSPPPaperFeedButton);
list = [printer stringListForKey:@"InputSlot" inTable: @"PPD"];
if (list)
{
int selected;
NSString *def, *manual;
sel = nil;
selected = [control indexOfSelectedItem];
manual = [printer stringForKey:@"DefaultManualFeed" inTable: @"PPD"];
if (manual)
{
if (selected == 0)
sel = @"Manual";
else
selected--;
}
if (sel == nil)
sel = [list objectAtIndex: selected];
def = [printer stringForKey:@"DefaultInputSlot" inTable: @"PPD"];
if ([sel isEqual: @"Manual"] == YES)
{
[dict setObject: NSPrintManualFeed forKey: NSPrintPaperFeed];
/* FIXME: This needs to be more robust. I'm just assuming
that all Manual Feed keys can be True or False (which is
the case for all the ppd files that I know of). */
[dict setObject: @"ManualFeed/True" forKey: NSPrintManualFeed];
[features setObject: @"ManualFeed/True" forKey: NSPrintPaperFeed];
}
else if ([sel isEqual: def] == NO
|| [dict objectForKey: NSPrintPaperFeed])
{
if (features == nil)
{
features = [NSMutableDictionary dictionary];
[dict setObject: features forKey: NSPrintJobFeatures];
}
sel = [@"InputSlot/" stringByAppendingString: sel];
[features setObject: sel forKey: @"InputSlot"];
[dict setObject: sel forKey: NSPrintPaperFeed];
}
}
/* Job Resolution */
switch (_picked)
{
case NSPPSaveButton:
sel = NSPrintSaveJob;
[dict setObject: _savePath forKey: NSPrintSavePath];
break;
case NSPPPreviewButton:
sel = NSPrintPreviewJob;
break;
case NSFaxButton:
sel = NSPrintFaxJob;
break;
case NSOKButton:
sel = NSPrintSpoolJob;
break;
case NSCancelButton:
default:
sel = NSPrintCancelJob;
}
[info setJobDisposition: sel];
NSDebugLLog(@"NSPrinting",
@"Final info dictionary ----\n %@ \n --------------", dict);
}
@end