/** NSPrintPanel Standard panel for querying user about printing. Copyright (C) 2001 Free Software Foundation, Inc. Written By: Adam Fedor Date: Oct 2001 This file is part of the GNUstep GUI Library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static NSPrintPanel *shared_instance; #define GSPANELNAME @"GSPrintPanel" #define CONTROL(panel, name) [[panel contentView] viewWithTag: name] /** 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