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. Unlike other panels, this one does not order
itself out after the modal session is finished. You must do that
yourself.
*/
- (int)runModal
{
_picked = NSOKButton;
[NSApp runModalForWindow: self];
[_optionPanel orderOut: self];
/* Don't order ourselves out, let the NSPrintOperation do that */
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;
}
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)
{
/* 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);
}
/* Private method for NSPrintOperation */
- (void) _setStatusStringValue: (NSString *)string
{
[CONTROL(self, NSPPStatusField) setStringValue: string ];
}
@end