diff --git a/ChangeLog b/ChangeLog index f52e8a69e..81b577fc3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,57 @@ +2004-07-09 Chad Hardin + * Source/GNUmakefile: + * Headers/AppKit/NSPageLayout.h: + * Source/NSPageLayout.m: + * Headers/AppKit/NSPrintInfo.h: + * Source/NSPrintInfo.m: + * Headers/AppKit/NSPrintOperation.h: + * Source/NSPrintOperation.m: + * Headers/AppKit/NSPrintPanel.h: + * Source/NSPrintPanel.m: + * Headers/AppKit/NSPrinter.h: + * Source/NSPrinter.m: + Modifications for the backend printing bundle system. + * Headers/Additions/GNUstepGUI/GSEPSPrintOperation.h: added. + * Source/GSEPSPrintOperation.m: added. + * Headers/Additions/GNUstepGUI/GSPDFPrintOperation.h: added. + * Source/GSPDFPrintOperation.m: added. + * Headers/Additions/GNUstepGUI/GSPrintOperation.h: added. + * Source/GSPrintOperation.m: added. + * Headers/Additions/GNUstepGUI/GSPrinting.h: added. + * Source/GSPrinting.m: added. + Split off the various PrintOperation classes. This makes is clear that + the printing backend bundles subclass GSPrintOperation, not NSPrintOperation. + Also, GSPDFPrintOperation will probably become large when implemented, this + clarifies the class structure and prevent NSPrintOperation.m from become + overly large and confusing. The GSPrinting class is helper for loading the + proper printer backend bundle. + * GNUMakefile: includes the Printing directory. + * Printing: Added the printing bundles home directory. + * Printing/GNUmakefile: added. + * Printing/GSLPR: Added the first printing bundle. + * Printing/GSLPR/GNUmakefile: added. + * Printing/GSLPR/GNUmakefile.postamble: added. + * Printing/GSLPR/GNUmakefile.preamble: added. + * Printing/GSLPR/GSLPRPageLayout.h: added. + * Printing/GSLPR/GSLPRPageLayout.m: added. + * Printing/GSLPR/GSLPRPrincipalClass.h: added. + * Printing/GSLPR/GSLPRPrincipalClass.m: added. + * Printing/GSLPR/GSLPRPrintInfo.h: added. + * Printing/GSLPR/GSLPRPrintInfo.m: added. + * Printing/GSLPR/GSLPRPrintOperation.h: added. + * Printing/GSLPR/GSLPRPrintOperation.m: added. + * Printing/GSLPR/GSLPRPrintPanel.h: added. + * Printing/GSLPR/GSLPRPrintPanel.m: added. + * Printing/GSLPR/GSLPRPrintPrinter.h: added. + * Printing/GSLPR/GSLPRPrintPrinter.m: added. + Here it is, the first backend printing bundle, version one. The are very + little code changes from the original source, bugs that may have been + present there would have been carried over here. However, this is just the + first round. This bundle uses GNUstep's original PageLayout and PrintPanel + GORM panels, it does not have its own. Hence, it is very simple. The plan + is for the future GSCUPS bundle to also use GNUstep's GORM panels, not for + each bundle to have their own panels. + 2004-07-09 Fred Kiefer * Source/NSPanel.m: diff --git a/GNUmakefile b/GNUmakefile index fc47f66e9..07a697e59 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -56,7 +56,8 @@ PrinterTypes \ TextConverters \ ColorPickers \ KeyBindings \ -Resources +Resources \ +Printing ifeq ($(doc), yes) SUBPROJECTS += Documentation diff --git a/Headers/Additions/GNUstepGUI/GSEPSPrintOperation.h b/Headers/Additions/GNUstepGUI/GSEPSPrintOperation.h new file mode 100644 index 000000000..ddfa8cd48 --- /dev/null +++ b/Headers/Additions/GNUstepGUI/GSEPSPrintOperation.h @@ -0,0 +1,59 @@ +/** GSEPSPrintOperation + + Controls generation of EPS print output. + + Copyright (C) 1996,2004 Free Software Foundation, Inc. + + Author: Scott Christley + Date: 1996 + Author: Fred Kiefer + Date: November 2000 + Updated to new specification + Author: Adam Fedor + Date: Oct 2001 + Modified for Printing Backend Support + Author: Chad Hardin + Date: June 2004 + + 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. +*/ + +#ifndef _GNUstep_H_GSEPSPrintOperation +#define _GNUstep_H_GSEPSPrintOperation + +#include +#include +#include "AppKit/NSPrintOperation.h" + +@class NSString; +@class NSView; +@class NSPrintInfo; + +// subclass for EPS output +@interface GSEPSPrintOperation: NSPrintOperation +{ +} + +- (id) initWithView:(NSView *)aView + insideRect:(NSRect)rect + toPath:(NSString *)path + printInfo:(NSPrintInfo *)aPrintInfo; +@end + + +#endif // _GNUstep_H_GSEPSPrintOperation diff --git a/Headers/Additions/GNUstepGUI/GSPDFPrintOperation.h b/Headers/Additions/GNUstepGUI/GSPDFPrintOperation.h new file mode 100644 index 000000000..0ff6f1f9f --- /dev/null +++ b/Headers/Additions/GNUstepGUI/GSPDFPrintOperation.h @@ -0,0 +1,61 @@ +/** GSPDFPrintOperation + + Controls generation of PDF print output. + + Copyright (C) 1996,2004 Free Software Foundation, Inc. + + Author: Scott Christley + Date: 1996 + Author: Fred Kiefer + Date: November 2000 + Updated to new specification + Author: Adam Fedor + Date: Oct 2001 + Modified for Printing Backend Support + Author: Chad Hardin + Date: June 2004 + + 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. +*/ + +#ifndef _GNUstep_H_GSPDFPrintOperation +#define _GNUstep_H_GSPDFPrintOperation + +#include +#include +#include "AppKit/NSPrintOperation.h" + +@class NSString; + +@class NSView; +@class NSPrintInfo; + +// subclass for PDF output +@interface GSPDFPrintOperation: NSPrintOperation +{ +} + +- (id) initWithView:(NSView *)aView + insideRect:(NSRect)rect + toPath:(NSString *)path + printInfo:(NSPrintInfo *)aPrintInfo; +@end + + +#endif // _GNUstep_H_GSPDFPrintOperation + diff --git a/Headers/Additions/GNUstepGUI/GSPrintOperation.h b/Headers/Additions/GNUstepGUI/GSPrintOperation.h new file mode 100644 index 000000000..bb768483c --- /dev/null +++ b/Headers/Additions/GNUstepGUI/GSPrintOperation.h @@ -0,0 +1,59 @@ +/** GSPrintOperation + + Controls generation of print jobs. Backends determine the + file format and how to send the data to the printer. + + Copyright (C) 1996,2004 Free Software Foundation, Inc. + + Author: Scott Christley + Date: 1996 + Author: Fred Kiefer + Date: November 2000 + Updated to new specification + Author: Adam Fedor + Date: Oct 2001 + Modified for Printing Backend Support + Author: Chad Hardin + Date: June 2004 + + 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. +*/ + +#ifndef _GNUstep_H_GSPrintOperation +#define _GNUstep_H_GSPrintOperation + +#include "AppKit/NSPrintOperation.h" + + +@class NSView; +@class NSPrintInfo; + + +@interface GSPrintOperation: NSPrintOperation +{ +} + +- (id) initWithView:(NSView *)aView + printInfo:(NSPrintInfo *)aPrintInfo; + +- (BOOL) _deliverSpooledResult; +@end + + +#endif // _GNUstep_H_GSPrintOperation + diff --git a/Headers/Additions/GNUstepGUI/GSPrinting.h b/Headers/Additions/GNUstepGUI/GSPrinting.h new file mode 100644 index 000000000..c115780f6 --- /dev/null +++ b/Headers/Additions/GNUstepGUI/GSPrinting.h @@ -0,0 +1,63 @@ +/** GSPrinting + + Loads the proper bundle for the printing backend and + contains the class GSPrintingPrincipleClass, which is subclassed + by printing backend bundles. + + Copyright (C) 2004 Free Software Foundation, Inc. + + Author: Chad Elliott Hardin + Date: June 2004 + + 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. +*/ +#ifndef _GNUstep_H_GSPrinting +#define _GNUstep_H_GSPrinting + +#include + + +@interface GSPrinting : NSObject +{ +} + ++(NSBundle*) printingBundle; + +@end + + +@interface GSPrintingPrincipalClass : NSObject +{ +} + ++(Class) pageLayoutClass; + ++(Class) printInfoClass; + ++(Class) printOperationClass; + ++(Class) printPanelClass; + ++(Class) printerClass; + ++(Class) gsPrintOperationClass; + +@end + + +#endif // _GNUstep_H_GSPrinting diff --git a/Headers/AppKit/NSPrintInfo.h b/Headers/AppKit/NSPrintInfo.h index de98b844a..5aae05d77 100644 --- a/Headers/AppKit/NSPrintInfo.h +++ b/Headers/AppKit/NSPrintInfo.h @@ -2,12 +2,15 @@ Stores information used in printing. - Copyright (C) 1996,1997 Free Software Foundation, Inc. + Copyright (C) 1996,1997,2004 Free Software Foundation, Inc. Author: Simon Frankau Date: July 1997 Author: Adam Fedor Date: Oct 2001 + Modified for Printing Backend Support + Author: Chad Hardin + Date: June 2004 This file is part of the GNUstep GUI Library. @@ -124,6 +127,17 @@ typedef enum _NSPrintingPaginationMode { @end + +// +// Used by printing backend bundles +// +@interface NSPrintInfo (Private) + ++(NSPrinter*) _resolvePrinterName: (NSString*) printerName; + +@end + + // // Printing Information Dictionary Keys // diff --git a/Headers/AppKit/NSPrintOperation.h b/Headers/AppKit/NSPrintOperation.h index 1e0a8da89..3fceaf790 100644 --- a/Headers/AppKit/NSPrintOperation.h +++ b/Headers/AppKit/NSPrintOperation.h @@ -2,7 +2,7 @@ Controls generation of EPS, PDF or PS print jobs. - Copyright (C) 1996 Free Software Foundation, Inc. + Copyright (C) 1996,2001,2004 Free Software Foundation, Inc. Author: Scott Christley Date: 1996 @@ -11,6 +11,9 @@ Updated to new specification Author: Adam Fedor Date: Oct 2001 + Modified for Printing Backend Support + Author: Chad Hardin + Date: June 2004 This file is part of the GNUstep GUI Library. @@ -66,7 +69,7 @@ typedef enum _NSPrintingPageOrder { NSView *_accessoryView; NSPrintingPageOrder _pageOrder; BOOL _showPanels; - BOOL _pathSet; + //BOOL _pathSet; removed, just test _path for nil int _currentPage; } @@ -178,4 +181,22 @@ typedef enum _NSPrintingPageOrder { @end + +// +// Private method used by the NSPrintOperation subclasses +// such as GSEPSPrintOperation, GSPDFPrintOperation. This +// also includes GSPrintOperation, which is used in the printing +// backend system. Printing bundles subclass GSPrintOperation +// and use that to interface with the native printing system. +// +@interface NSPrintOperation (Private) + +- (id) initWithView:(NSView *)aView + insideRect:(NSRect)rect + toData:(NSMutableData *)data + printInfo:(NSPrintInfo *)aPrintInfo; + +@end + + #endif // _GNUstep_H_NSPrintOperation diff --git a/Headers/AppKit/NSPrintPanel.h b/Headers/AppKit/NSPrintPanel.h index 3707ef86b..8b7e79b0d 100644 --- a/Headers/AppKit/NSPrintPanel.h +++ b/Headers/AppKit/NSPrintPanel.h @@ -3,10 +3,13 @@ Standard panel to query users for info on a print job - Copyright (C) 1996 Free Software Foundation, Inc. + Copyright (C) 1996,2004 Free Software Foundation, Inc. Author: Scott Christley Date: 1996 + Modified for Printing Backend Support + Author: Chad Hardin + Date: June 2004 This file is part of the GNUstep GUI Library. @@ -55,7 +58,10 @@ enum { NSPPOptionsButton = 33, NSPPPaperFeedButton = 34, NSPPLayoutButton = 35, - NSPPResolutionButton = 36, + //The following are not actually in the OpenStep spec. + //However, It is prudent to keep them here, I am just + //making you aware of this fact. + NSPPResolutionButton = 36, NSPPOptionOKButton = 40 }; @@ -66,7 +72,7 @@ enum { id _accessoryView; id _savePath; int _picked; - NSRange _pages; + NSRange _pages; //this may also be removed } // @@ -107,4 +113,17 @@ enum { @end +// +// Methods used by printing backend bundles that subclass NSPrintPanel +// +@interface NSPrintPanel (Private) + +/* Private method used by NSPrintOperation */ +- (void) _setStatusStringValue: (NSString *)string; + +/*Private method for saving a print job as a file*/ +- (BOOL) _getSavePath; + +@end + #endif // _GNUstep_H_NSPrintPanel diff --git a/Headers/AppKit/NSPrinter.h b/Headers/AppKit/NSPrinter.h index d43a35b15..300f263ae 100644 --- a/Headers/AppKit/NSPrinter.h +++ b/Headers/AppKit/NSPrinter.h @@ -3,10 +3,13 @@ Class representing a printer's or printer model's capabilities. - Copyright (C) 1996, 1997 Free Software Foundation, Inc. + Copyright (C) 1996, 1997,2004 Free Software Foundation, Inc. Authors: Simon Frankau Date: June 1997 + Modified for Printing Backend Support + Author: Chad Hardin + Date: June 2004 This file is part of the GNUstep GUI Library. @@ -47,7 +50,24 @@ typedef enum _NSPrinterTableStatus { { NSString *_printerHost, *_printerName, *_printerNote, *_printerType; int _cacheAcceptsBinary, _cacheOutputOrder; - BOOL _isRealPrinter; + + //The way openstep handled NSPrinter was odd, it had a concept of "real" + //printers and + //not real printers. Printers that were not real were simply parsed PPDs, + //whether the printer was actually available or not was irrevelatn. This is + //is where the all the -types and +types methods come from. Apple's + //adoption of CUPS forced them to change this behavior, now, their types + //methods only search for the types of printers that are actually avaiable, + //it has nothing to do with the PPDs that happen to be avaiable on the file + //system. I think this is also the behavior we should adopt. Not simply + //because it is what Apple does but because it facilitates a generic printing + //backend system, especially one that will likely be using CUPS itself. + //This is why the following ivar is removed and the behavior of this class + //and the GSLPR Bundle has been changed. Doing this has also allowed me + //to put a lot of generic code in ths class that would have otherwise had + //to have been handles by each bundle. See +printerWithType: in NSPrinter.m + //BOOL _isRealPrinter; + NSMutableDictionary *_PPD; NSMutableDictionary *_PPDOptionTranslation; NSMutableDictionary *_PPDArgumentTranslation; @@ -112,4 +132,29 @@ typedef enum _NSPrinterTableStatus { @end + +// +// Private methods that will be usefull for the +// printing backend bundles that subclass NSPrinter +// +@interface NSPrinter (Private) +// +// Initialisation method used by backend bundles +// +-(id) initWithName:(NSString *)name + withType:(NSString *)type + withHost:(NSString *)host + withNote:(NSString *)note; + +-(id) addValue:(NSString *)value + andValueTranslation:(NSString *)valueTranslation +andOptionTranslation:(NSString *)optionTranslation + forKey:(NSString *)key; + + +-(id) addString: (NSString*) string + forKey: (NSString*) key + inTable: (NSMutableDictionary*) table; +@end + #endif // _GNUstep_H_NSPrinter diff --git a/Printing/GNUmakefile b/Printing/GNUmakefile new file mode 100644 index 000000000..9a3ef422b --- /dev/null +++ b/Printing/GNUmakefile @@ -0,0 +1,39 @@ +# +# Makefile for the GNUstep Printing Backend Bundles +# +# Copyright (C) 2004 Free Software Foundation, Inc. +# +# Author: Chad Hardin GSLPRPageLayout + + Standard panel for querying user about page layout. + + Copyright (C) 2001,2004 Free Software Foundation, Inc. + + Written By: Adam Fedor + Date: Oct 2001 + Modified for Printing Backend Support + Author: Chad Hardin + Date: June 2004 + + 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. +*/ + +#ifndef _GNUstep_H_GSLPRPageLayout +#define _GNUstep_H_GSLPRPageLayout + +#include + + +@class NSPrintInfo; +@class NSView; + + +@interface GSLPRPageLayout: NSPageLayout +{ +} + +@end + +#endif // _GNUstep_H_NSPageLayout diff --git a/Printing/GSLPR/GSLPRPageLayout.m b/Printing/GSLPR/GSLPRPageLayout.m new file mode 100644 index 000000000..26ce5c715 --- /dev/null +++ b/Printing/GSLPR/GSLPRPageLayout.m @@ -0,0 +1,72 @@ +/** GSLPRPageLayout + + + + Copyright (C) 2004 Free Software Foundation, Inc. + Author: Chad Hardin + Date: June 2004 + + 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 +//#include +//#include +//#include "GSGuiPrivate.h" +#include "GSLPRPageLayout.h" +//#include "GNUstepGUI/GSPrinting.h" + + + +@implementation GSLPRPageLayout +// +// Class methods +// ++ (void)initialize +{ + NSDebugMLLog(@"GSPrinting", @""); + if (self == [GSLPRPageLayout class]) + { + // Initial version + [self setVersion:1]; + } +} + + ++ (id) allocWithZone: (NSZone*)zone +{ + NSDebugMLLog(@"GSPrinting", @""); + return NSAllocateObject(self, 0, zone); +} + + +@end diff --git a/Printing/GSLPR/GSLPRPrincipalClass.h b/Printing/GSLPR/GSLPRPrincipalClass.h new file mode 100644 index 000000000..cc6618117 --- /dev/null +++ b/Printing/GSLPR/GSLPRPrincipalClass.h @@ -0,0 +1,37 @@ +/* + Project: GSLPR + + Copyright (C) 2004 Free Software Foundation + + Author: Chad Hardin + + Created: 2004-06-12 19:40:40 +0000 by Chad Hardin + + This application is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This application 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 General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. +*/ + +#ifndef _GSLPRPRINCIPALCLASS_H_ +#define _GSLPRPRINCIPALCLASS_H_ + +#include + +@interface GSLPRPrincipalClass : GSPrintingPrincipalClass +{ +} + +@end + +#endif // _GSLPRPRINCIPALCLASS_H_ + diff --git a/Printing/GSLPR/GSLPRPrincipalClass.m b/Printing/GSLPR/GSLPRPrincipalClass.m new file mode 100644 index 000000000..2a1fb71f0 --- /dev/null +++ b/Printing/GSLPR/GSLPRPrincipalClass.m @@ -0,0 +1,79 @@ +/* + Project: GSLPR + + Copyright (C) 2004 Free Software Foundation + + Author: Chad Hardin + + Created: 2004-06-12 19:40:40 +0000 by Chad Hardin + + This application is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This application 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 General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. +*/ + +#include +#include "GSLPRPrincipalClass.h" +#include "GSLPRPageLayout.h" +#include "GSLPRPrintInfo.h" +#include "GSLPRPrintOperation.h" +#include "GSLPRPrintPanel.h" +#include "GSLPRPrinter.h" + + +@implementation GSLPRPrincipalClass +// +// Class methods +// ++(Class) pageLayoutClass +{ + NSDebugMLLog(@"GSPrinting", @""); + return [GSLPRPageLayout class]; +} + ++(Class) printInfoClass +{ + NSDebugMLLog(@"GSPrinting", @""); + return [GSLPRPrintInfo class]; +} + ++(Class) printOperationClass +{ + NSDebugMLLog(@"GSPrinting", @""); + return [GSLPRPrintOperation class]; +} + + ++(Class) printPanelClass +{ + NSDebugMLLog(@"GSPrinting", @""); + return [GSLPRPrintPanel class]; +} + + ++(Class) printerClass +{ + NSDebugMLLog(@"GSPrinting", @""); + return [GSLPRPrinter class]; +} + + ++(Class) gsPrintOperationClass +{ + NSDebugMLLog(@"GSPrinting", @""); + return [GSLPRPrintOperation class]; +} + + + +@end diff --git a/Printing/GSLPR/GSLPRPrintInfo.h b/Printing/GSLPR/GSLPRPrintInfo.h new file mode 100644 index 000000000..f6e80ad17 --- /dev/null +++ b/Printing/GSLPR/GSLPRPrintInfo.h @@ -0,0 +1,48 @@ +/** NSPrintInfo + + Stores information used in printing. + + Copyright (C) 1996,1997,2004 Free Software Foundation, Inc. + + Author: Simon Frankau + Date: July 1997 + Author: Adam Fedor + Date: Oct 2001 + Modified for Printing Backend Support + Author: Chad Hardin + Date: June 2004 + + 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. +*/ + +#ifndef _GNUstep_H_GSLPRPrintInfo +#define _GNUstep_H_GSLPRPrintInfo + +#include +#include + + + +@interface GSLPRPrintInfo: NSPrintInfo +{ +} +@end + + + +#endif // _GNUstep_H_GSLPRPrintInfo diff --git a/Printing/GSLPR/GSLPRPrintInfo.m b/Printing/GSLPR/GSLPRPrintInfo.m new file mode 100644 index 000000000..9cb79c64f --- /dev/null +++ b/Printing/GSLPR/GSLPRPrintInfo.m @@ -0,0 +1,164 @@ +/* + GSLPRPrintInfo.m + + Stores information used in printing + + Copyright (C) 1996,1997,2004 Free Software Foundation, Inc. + + Author: Simon Frankau + Date: July 1997 + Modified for Printing Backend Support + Author: Chad Hardin + Date: June 2004 + + 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 "GSLPRPrintInfo.h" +#include "GSLPRPrinter.h" + + + + +@implementation GSLPRPrintInfo + +// +// Class methods +// ++ (void)initialize +{ + NSDebugMLLog(@"GSPrinting", @""); + if (self == [GSLPRPrintInfo class]) + { + // Initial version + [self setVersion:1]; + } +} + + ++ (id) allocWithZone: (NSZone*)zone +{ + NSDebugMLLog(@"GSPrinting", @""); + return NSAllocateObject(self, 0, zone); +} + + ++(NSPrinter*) defaultPrinter +{ + NSUserDefaults *defaults; + NSString *name; + + NSDebugMLLog(@"GSPrinting", @""); + defaults = [NSUserDefaults standardUserDefaults]; + name = [defaults objectForKey: @"GSLPRDefaultPrinter"]; + + if( name == nil ) + { + name = [[GSLPRPrinter printerNames] objectAtIndex: 0]; + } + else + { + if( [GSLPRPrinter printerWithName: name] == nil ) + { + name = [[GSLPRPrinter printerNames] objectAtIndex: 0]; + } + } + return [GSLPRPrinter printerWithName: name]; +} + + + ++ (void)setDefaultPrinter:(NSPrinter *)printer +{ + NSUserDefaults *defaults; + NSMutableDictionary *globalDomain; + + NSDebugMLLog(@"GSPrinting", @""); + defaults = [NSUserDefaults standardUserDefaults]; + + globalDomain = (NSMutableDictionary*)[defaults persistentDomainForName: NSGlobalDomain]; + + if( globalDomain ) + { + globalDomain = [globalDomain mutableCopy]; + + [globalDomain setObject: [printer name] + forKey: @"GSLPRDefaultPrinter"]; + + [defaults setPersistentDomain: globalDomain + forName: NSGlobalDomain]; + } + else + { + NSDebugMLLog(@"GSPrinting", @"(GSLPR) Could not save default printer named %@ to NSUserDefaults GSLPRDefaultPrinter in NSGlobalDomain.", [printer name]); + } + +} + + + + +-(id) initWithDictionary:(NSDictionary *)aDict +{ + NSPrinter *printer; + NSString *pageSize; + NSSize size; + NSMutableDictionary *dict; + + NSDebugMLLog(@"GPrinting", @""); + self = [super initWithDictionary: nil]; + + printer = [GSLPRPrintInfo defaultPrinter]; + [self setPrinter: printer]; + + + /* Set up other defaults from the printer object */ + pageSize = [printer stringForKey: @"DefaultPageSize" + inTable: @"PPD"]; + + /* FIXME: Need to check for AutoSelect and probably a million other things... */ + if (pageSize == nil) + pageSize = @"A4"; + + [self setPaperName: pageSize]; + + /* Set default margins. FIXME: Probably should check ImageableArea */ + [self setRightMargin: 36]; + + [self setLeftMargin: 36]; + + [self setTopMargin: 72]; + + [self setBottomMargin: 72]; + + return self; +} + + + + +@end diff --git a/Printing/GSLPR/GSLPRPrintOperation.h b/Printing/GSLPR/GSLPRPrintOperation.h new file mode 100644 index 000000000..12449f239 --- /dev/null +++ b/Printing/GSLPR/GSLPRPrintOperation.h @@ -0,0 +1,53 @@ +/** NSPrintOperation + + Controls generation of EPS, PDF or PS print jobs. + + Copyright (C) 1996,2004 Free Software Foundation, Inc. + + Author: Scott Christley + Date: 1996 + Author: Fred Kiefer + Date: November 2000 + Updated to new specification + Author: Adam Fedor + Date: Oct 2001 + Modified for Printing Backend Support + Author: Chad Hardin + Date: June 2004 + + 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. +*/ + +#ifndef _GNUstep_H_GSLPRPrintOperation +#define _GNUstep_H_GSLPRPrintOperation + +#include + +//GSPrintOperation is subclasses of GSPrintOperation, NOT NSPrintOperation. +//NSPrintOperation does a lot of work that is pretty generic. +//GSPrintOperation contains the method that does the actual +//spooling. A future Win32 printing printing bundle +//will likely have to implement much more +@interface GSLPRPrintOperation : GSPrintOperation +{ +} + + +@end + +#endif // _GNUstep_H_GSLPRPrintOperation diff --git a/Printing/GSLPR/GSLPRPrintOperation.m b/Printing/GSLPR/GSLPRPrintOperation.m new file mode 100644 index 000000000..bed01a9e0 --- /dev/null +++ b/Printing/GSLPR/GSLPRPrintOperation.m @@ -0,0 +1,168 @@ +/* + GLPRSPrintOperation.m + + Controls operations generating EPS, PDF or PS print jobs. + + Copyright (C) 1996 Free Software Foundation, Inc. + + Author: Scott Christley + Date: 1996 + Author: Fred Kiefer + Date: November 2000 + Started implementation. + Modified for Printing Backend Support + Author: Chad Hardin + Date: June 2004 + + 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include "GSLPRPrintOperation.h" + +#define NSNUMBER(a) [NSNumber numberWithInt: (a)] +#define NSFNUMBER(a) [NSNumber numberWithFloat: (a)] + + + + +//A subclass of GSPrintOperation, NOT NSPrintOperation. +@implementation GSLPRPrintOperation +// +// Class methods +// ++ (id) allocWithZone: (NSZone*)zone +{ + NSDebugMLLog(@"GSPrinting", @""); + return NSAllocateObject(self, 0, zone); +} + + +- (id)initWithView:(NSView *)aView + printInfo:(NSPrintInfo *)aPrintInfo +{ + self = [super initWithView: aView + printInfo: aPrintInfo]; + + _path = [NSTemporaryDirectory() stringByAppendingPathComponent: @"GSLPRPrintJob-"]; + + _path = [_path stringByAppendingString: + [[NSProcessInfo processInfo] globallyUniqueString]]; + + _path = [_path stringByAppendingPathExtension: @"ps"]; + + RETAIN( _path ); + + return self; +} + + + +- (BOOL) _deliverSpooledResult +{ + int copies; + NSDictionary *dict; + NSTask *task; + NSString *name, *status; + NSMutableArray *args; + + NSDebugMLLog(@"GSPrinting", @""); + name = [[_printInfo printer] name]; + status = [NSString stringWithFormat: @"Spooling to printer %@.", name]; + [_printPanel _setStatusStringValue: status]; + + dict = [_printInfo dictionary]; + args = [NSMutableArray array]; + copies = [[dict objectForKey: NSPrintCopies] intValue]; + if (copies > 1) + [args addObject: [NSString stringWithFormat: @"-#%0d", copies]]; + if ([name isEqual: @"Unknown"] == NO) + { + [args addObject: @"-P"]; + [args addObject: name]; + } + [args addObject: _path]; + + task = [NSTask new]; + [task setLaunchPath: @"lpr"]; + [task setArguments: args]; + [task launch]; + [task waitUntilExit]; + AUTORELEASE(task); + return YES; +} + +- (NSGraphicsContext*)createContext +{ + NSMutableDictionary *info; + + //NSDebugMLLog(@"GSPrinting", @"_path is %@", _path); + if (_context) + { + NSDebugMLLog(@"GSPrinting", @"Already had context, returning it."); + return _context; + } + NSDebugMLLog(@"GSPrinting", @"Creating context."); + + info = [_printInfo dictionary]; + if (_path == nil) + { + NSString *output = [info objectForKey: NSPrintSavePath]; + + if (output) + { + ASSIGN(_path, output); + } + } + + NSDebugMLLog(@"GSPrinting", @"_path is %@", _path); + + [info setObject: _path + forKey: @"NSOutputFile"]; + + [info setObject: NSGraphicsContextPSFormat + forKey: NSGraphicsContextRepresentationFormatAttributeName]; + + _context = RETAIN([NSGraphicsContext graphicsContextWithAttributes: info]); + + return _context; +} + +@end diff --git a/Printing/GSLPR/GSLPRPrintPanel.h b/Printing/GSLPR/GSLPRPrintPanel.h new file mode 100644 index 000000000..a2834fede --- /dev/null +++ b/Printing/GSLPR/GSLPRPrintPanel.h @@ -0,0 +1,46 @@ +/* + GSLPRPrintPanel.h + + Standard panel to query users for info on a print job + + Copyright (C) 1996,2004 Free Software Foundation, Inc. + + Author: Scott Christley + Date: 1996 + Modified for Printing Backend Support + Author: Chad Hardin + Date: June 2004 + + 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. + +*/ + +#ifndef _GNUstep_H_GSLPRPrintPanel +#define _GNUstep_H_GSLPRPrintPanel + +#include + + +@interface GSLPRPrintPanel : NSPrintPanel +{ +} + + +@end + +#endif // _GNUstep_H_GSLPRPrintPanel diff --git a/Printing/GSLPR/GSLPRPrintPanel.m b/Printing/GSLPR/GSLPRPrintPanel.m new file mode 100644 index 000000000..e8278964a --- /dev/null +++ b/Printing/GSLPR/GSLPRPrintPanel.m @@ -0,0 +1,64 @@ +/** GSLPRPrintPanel + + Standard panel for querying user about printing. + + Copyright (C) 2001,2004 Free Software Foundation, Inc. + + Written By: Adam Fedor + Date: Oct 2001 + Modified for Printing Backend Support + Author: Chad Hardin + Date: June 2004 + + 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 "config.h" +#include +//#include +//#include +//#include +//#include +//#include "AppKit/NSApplication.h" +//#include "AppKit/NSForm.h" +//#include "AppKit/NSNibLoading.h" +//#include "AppKit/NSPrinter.h" +//#include "AppKit/NSPrintPanel.h" +//#include "AppKit/NSPrintInfo.h" +//#include "AppKit/NSPrintOperation.h" +//#include "AppKit/NSPopUpButton.h" +//#include "AppKit/NSSavePanel.h" +//#include "AppKit/NSView.h" +//#include "GSGuiPrivate.h" +#include "GSLPRPrintPanel.h" +//#include "GNUstepGUI/GSPrinting.h" + + + +@implementation GSLPRPrintPanel +// +// Class methods +// ++ (id) allocWithZone: (NSZone*)zone +{ + NSDebugMLLog(@"GSPrinting", @""); + return NSAllocateObject(self, 0, zone); +} + +@end diff --git a/Printing/GSLPR/GSLPRPrinter.h b/Printing/GSLPR/GSLPRPrinter.h new file mode 100644 index 000000000..9f07725ad --- /dev/null +++ b/Printing/GSLPR/GSLPRPrinter.h @@ -0,0 +1,47 @@ +/* + NSPrinter.h + + Class representing a printer's or printer model's capabilities. + + Copyright (C) 1996, 1997,2004 Free Software Foundation, Inc. + + Authors: Simon Frankau + Date: June 1997 + Modified for Printing Backend Support + Author: Chad Hardin + Date: June 2004 + + 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. +*/ + +#ifndef _GNUstep_H_GSLPRPrinter +#define _GNUstep_H_GSLPRPrinter + +#include + + + +@interface GSLPRPrinter : NSPrinter +{ +} + + + +@end + +#endif // _GNUstep_H_GSLPRPrinter diff --git a/Printing/GSLPR/GSLPRPrinter.m b/Printing/GSLPR/GSLPRPrinter.m new file mode 100644 index 000000000..50f095d5f --- /dev/null +++ b/Printing/GSLPR/GSLPRPrinter.m @@ -0,0 +1,897 @@ +/** GSLPRPrinter + + Class representing a printer's or printer model's capabilities. + + Copyright (C) 1996, 1997, 2004 Free Software Foundation, Inc. + + Authors: Simon Frankau + Date: June 1997 + Modified for Printing Backend Support + Author: Chad Hardin + Date: June 2004 + + 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. + + If you are interested in a warranty or support for this source code, + contact Scott Christley for more information. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. +*/ + +/* NB: + * There are a few FIXMEs in the functionality left. + * Parsing of the PPDs is somewhat suboptimal. + * (I think it's best to leave optimisation until more of GNUstep is done). + * The *OpenUI, *CloseUI, *OpenGroup and *CloseGroup are not processed. + * (This is not required in the OpenStep standard, but could be useful). + */ + +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "AppKit/AppKitExceptions.h" +#include "AppKit/NSGraphics.h" +#include "GSLPRPrinter.h" +#include "GNUstepGUI/GSPrinting.h" + +// The maximum level of nesting of *Include directives +#define MAX_PPD_INCLUDES 4 + +// A macro to skip whitespace over lines +#define skipSpace(x) [x scanCharactersFromSet:\ + [NSCharacterSet whitespaceAndNewlineCharacterSet]\ + intoString:NULL] + +static NSString *NSPrinter_PATH = @"PostScript/PPD"; +static NSString *NSPrinter_INDEXFILE = @"Printers"; + +// +// Class variables: +// + + +static NSDictionary *printerIndexDict = nil; //The list of printers from NSPrinter_INDEXFILE +static NSMutableDictionary *printerObjNameDict = nil; //Printer objects mapped to names + +// An array to cache the available printer types +static NSArray *printerTypesAvailable = nil; + +// +// Class variables used during scanning: +// + +// Character sets used in scanning. +static NSCharacterSet *newlineSet = nil; +static NSCharacterSet *keyEndSet = nil; +static NSCharacterSet *optKeyEndSet = nil; +static NSCharacterSet *valueEndSet = nil; +// Array of Repeated Keywords (Appendix B of the PostScript Printer +// Description File Format Specification). +static NSArray *repKeys = nil; +// Array to collect the values of symbol values in. +static NSMutableDictionary *PPDSymbolValues; +// File name of the file being processed +static NSString *PPDFileName; + +#ifndef LIB_FOUNDATION_LIBRARY + +static void __NSRetainNothing(void *table, const void *anObject) +{ +} + +static void __NSReleaseNothing(void *table, void *anObject) +{ +} + +static NSString* __NSDescribeObjects(void *table, const void *anObject) +{ + return [(NSObject*)anObject description]; +} + +static const NSMapTableValueCallBacks NSNonRetainedObjectMapValueCallBacks = { + (void (*)(NSMapTable *, const void *))__NSRetainNothing, + (void (*)(NSMapTable *, void *))__NSReleaseNothing, + (NSString *(*)(NSMapTable *, const void *))__NSDescribeObjects +}; + +#endif /* LIB_FOUNDATION_LIBRARY */ + + +// Convert a character to a value between 0 and 15 +static int gethex(unichar character) +{ + switch (character) + { + case '0': return 0; + case '1': return 1; + case '2': return 2; + case '3': return 3; + case '4': return 4; + case '5': return 5; + case '6': return 6; + case '7': return 7; + case '8': return 8; + case '9': return 9; + case 'A': return 10; + case 'B': return 11; + case 'C': return 12; + case 'D': return 13; + case 'E': return 14; + case 'F': return 15; + case 'a': return 10; + case 'b': return 11; + case 'c': return 12; + case 'd': return 13; + case 'e': return 14; + case 'f': return 15; + } + [NSException + raise:NSPPDParseException + format:@"Badly formatted hexadeximal substring in PPD printer file."]; + // NOT REACHED + return 0; /* Quiet compiler warnings */ +} + +// Function to convert hexadecimal substrings +static NSString *interpretQuotedValue(NSString *qString) +{ + NSScanner *scanner; + NSCharacterSet *emptySet; + NSString *value = nil; + NSString *part; + int stringLength; + int location; + NSRange range; + + // Don't bother unless there's something to convert + range = [qString rangeOfString:@"<"]; + if(!range.length) + return qString; + + scanner = [NSScanner scannerWithString:qString]; + emptySet = [NSCharacterSet characterSetWithCharactersInString:@""]; + [scanner setCharactersToBeSkipped:emptySet]; + if(![scanner scanUpToString:@"<" intoString:&value]) + value = [NSString string]; + stringLength = [qString length]; + + while (![scanner isAtEnd]) { + [scanner scanString:@"<" intoString:NULL]; + skipSpace(scanner); + while (![scanner scanString:@">" intoString:NULL]) + { + location = [scanner scanLocation]; + if (location+2 > stringLength) + { + [NSException + raise:NSPPDParseException + format:@"Badly formatted hexadecimal substring in PPD printer file."]; + // NOT REACHED + } + value = [value stringByAppendingFormat:@"%c", + 16 * gethex([qString characterAtIndex:location]) + + gethex([qString characterAtIndex:location+1])]; + [scanner setScanLocation:location+2]; + skipSpace(scanner); + } + if([scanner scanUpToString:@"<" intoString:&part]) + { + value = [value stringByAppendingString:part]; + } + } + return value; +} + +static NSString *getFile(NSString *name, NSString *type) +{ + return [NSBundle pathForLibraryResource: name + ofType: type + inDirectory: NSPrinter_PATH]; +} + + +@interface GSLPRPrinter (private) ++ loadPrinterIndexFile; +-(id)initWithPPD:(NSString *)PPDstring + withName:(NSString *)name + withType:(NSString *)type + withHost:(NSString *)host + withNote:(NSString *)note + fromFile:(NSString *)file; + +- loadPPD:(NSString *)PPDstring + inclusionNum:(int)includeNum; + +- addPPDKeyword:(NSString *)mainKeyword + withScanner:(NSScanner *)PPDdata; + +- addPPDUIConstraint:(NSScanner *)constraint; + +- addPPDOrderDependency:(NSScanner *)dependency; + +@end + + +@implementation GSLPRPrinter + +// +// Class methods +// ++ (void)initialize +{ + NSDebugMLLog(@"GSPrinting", @""); + if (self == [GSLPRPrinter class]) + { + // Initial version + [self setVersion:1]; + } +} + ++ (id) allocWithZone: (NSZone*)zone +{ + NSDebugMLLog(@"GSPrinting", @""); + return NSAllocateObject(self, 0, zone); +} + +// +// Finding an NSPrinter +// ++ (NSPrinter *)printerWithName:(NSString *)name +{ + NSString *path; + NSArray *printerInfo; + NSPrinter *printer; + /* Contents of printerInfo array: + * [0]: NSString of the printer's type + * [1]: NSString of the printer's host + * [2]: NSString of the printer's note + */ + + NSDebugMLLog(@"GSPrinting", @""); + // Make sure the printer names dictionary etc. exists + if (!printerIndexDict) + [self loadPrinterIndexFile]; + + if( name == nil ) + return nil; + + printer = [printerObjNameDict objectForKey: name]; + // If the NSPrinter object for the printer already exists, return it + if (printer) + return printer; + + // Otherwise, try to find the information in the printerIndexDict + printerInfo = [printerIndexDict objectForKey: name]; + // Make sure you can find the printer name in the dictionary + if (!printerInfo) + { + [NSException raise: NSGenericException + format: @"Could not find printer named %@", name]; + // NOT REACHED + } + // Create it + path = getFile([printerInfo objectAtIndex:0], @"ppd"); + // If not found + if (path == nil || [path length] == 0) + { + [NSException raise: NSGenericException + format: @"Could not find PPD file %@.ppd", + [printerInfo objectAtIndex:0]]; + // NOT REACHED + } + + printer = [(GSLPRPrinter*)[self alloc] + initWithPPD: [NSString stringWithContentsOfFile:path] + withName: name + withType: [printerInfo objectAtIndex:0] + withHost: [printerInfo objectAtIndex:1] + withNote: [printerInfo objectAtIndex:2] + fromFile: [printerInfo objectAtIndex:0]]; + + // Once created, set it in the dict for later use, this also retains it + [printerObjNameDict setObject: printer + forKey: name]; + + return [printer autorelease]; +} + + ++ (NSArray *)printerNames +{ + NSDebugMLLog(@"GSPrinting", @""); + if(!printerIndexDict) + [self loadPrinterIndexFile]; + + return [printerIndexDict allKeys]; +} + + + +// +// Instance methods +// + + +// +// Private Methods +// + +// +// Allocate the printer name to PPD filename index dictionary +// ++ loadPrinterIndexFile +{ + NSString *path; + + NSDebugMLLog(@"GSPrinting", @""); + printerObjNameDict = [NSMutableDictionary dictionary]; + + // Load the index file + path = [NSBundle pathForLibraryResource: NSPrinter_INDEXFILE + ofType: nil + inDirectory: @"PostScript"]; + + // If not found + if (path == nil || [path length] == 0) + { + NSLog(@"Could not find index of printers, file %@", NSPrinter_INDEXFILE); + printerIndexDict = [NSDictionary dictionaryWithObject: + [NSArray arrayWithObjects: @"Apple_LaserWriter_II_NTX", + @"localhost", @"A Note", nil] + forKey: @"Unknown"]; + } + else + { + printerIndexDict = [NSDictionary dictionaryWithContentsOfFile:path]; + } + RETAIN(printerObjNameDict); + RETAIN(printerIndexDict); + + return self; +} + +// +// Initialisation method +// +// To keep loading of PPDs relatively fast, not much checking is done on it. +-(id)initWithPPD:(NSString *)PPDstring + withName:(NSString *)name + withType:(NSString *)type + withHost:(NSString *)host + withNote:(NSString *)note + fromFile:(NSString *)file +{ + NSAutoreleasePool *subpool; + NSEnumerator *objEnum; + NSMutableArray *valArray; + + self = [super initWithName: name + withType: type + withHost: host + withNote: note]; + + NSDebugMLLog(@"GSPrinting", @""); + + // Create a temporary autorelease pool, as many temporary objects are used + subpool = [[NSAutoreleasePool alloc] init]; + // Create character sets used during scanning + newlineSet = [NSCharacterSet characterSetWithCharactersInString:@"\n\r"]; + keyEndSet = [NSCharacterSet characterSetWithCharactersInString:@"\n\r\t: "]; + optKeyEndSet = [NSCharacterSet characterSetWithCharactersInString:@"\n\r:/"]; + valueEndSet = [NSCharacterSet characterSetWithCharactersInString:@"\n\r/"]; + // Allowed repeated keys, used during scanning. + repKeys = [NSArray arrayWithObjects:@"Emulators", + @"Extensions", + @"FaxSupport", + //@"Include", (handled separately) + @"Message", + @"PrinterError", + @"Product", + @"Protocols", + @"PSVersion", + @"Source", + @"Status", + //@"UIConstraints", (handled separately) + // Even though this is not mentioned in the list of repeated keywords, + // it's often repeated anyway, so I'm putting it here. + @"InkName", + nil]; + // Set the file name to use + PPDFileName = file; + // NB: There are some structure keywords (such as OpenUI/CloseUI) that may + // be repeated, but as yet are not used. Since they are structure keywords, + // they'll probably need special processing anyway, and so aren't + // added to this list. + // Create dictionary for temporary storage of symbol values + PPDSymbolValues = [NSMutableDictionary dictionary]; + // And scan the PPD itself + [self loadPPD:PPDstring inclusionNum:0]; + // Search the PPD dictionary for symbolvalues, and substitute them. + objEnum = [_PPD objectEnumerator]; + while ((valArray = [objEnum nextObject])) + { + NSString *oldValue; + NSString *newValue; + int i, max; + max = [valArray count]; + for(i=0 ; i < max ; i++ ) + { + oldValue = [valArray objectAtIndex:i]; + if ([oldValue isKindOfClass:[NSString class]] + && ![oldValue isEqual:@""] + && [[oldValue substringToIndex:1] isEqual:@"^"]) + { + newValue = [PPDSymbolValues + objectForKey:[oldValue substringFromIndex:1]]; + if (!newValue) + { + [NSException raise: NSPPDParseException + format:@"Unknown symbol value, ^%@ in PPD file %@.ppd", + oldValue, PPDFileName]; + // NOT REACHED + } + [valArray replaceObjectAtIndex:i withObject:newValue]; + } + } + } + +#if 0 + // DISABLED: Though the following keywords *should* be present, there seems + // to be few problems is they are omitted. Many of the .ppd files I have + // don't have *LanguageEncoding, for example. + + // Make sure all the required keys are present + objEnum = [[NSArray arrayWithObjects:@"NickName", + @"ModelName", + @"PCFileName", + @"Product", + @"PSVersion", + @"FileVersion", + @"FormatVersion", + @"LanguageEncoding", + @"LanguageVersion", + @"PageSize", + @"PageRegion", + @"ImageableArea", + @"PaperDimension", + @"PPD-Adobe", + nil] objectEnumerator]; + + while (checkVal = [objEnum nextObject]) + { + if (![self isKey:checkVal inTable:@"PPD"]) + { + [NSException raise:NSPPDParseException + format:@"Required keyword *%@ not found in PPD file %@.ppd", + checkVal, PPDFileName]; + // NOT REACHED + } + } +#endif + + // Release the local autoreleasePool + RELEASE(subpool); + return self; +} + +- loadPPD:(NSString *)PPDstring + inclusionNum:(int)includeNum +{ + NSScanner *PPDdata; + NSString *keyword; + + // Set up the scanner - Appending a newline means that it should be + // able to process the last line correctly + PPDdata = [NSScanner scannerWithString: + [PPDstring stringByAppendingString:@"\n"]]; + + [PPDdata setCharactersToBeSkipped:[NSCharacterSet whitespaceCharacterSet]]; + + // Main processing starts here... + while (1) // Check it is not at end only after skipping the blanks + { + // Get to the start of a new keyword, skipping blank lines + skipSpace(PPDdata); + + if ([PPDdata isAtEnd]) + break; + + // All new entries should starts '*' + if (![PPDdata scanString:@"*" intoString:NULL]) + { + [NSException raise:NSPPDParseException + format:@"Line not starting * in PPD file %@.ppd", + PPDFileName]; + // NOT REACHED + } + // Skip lines starting '*%', '*End', '*SymbolLength', or '*SymbolEnd' + if ([PPDdata scanString:@"%" intoString:NULL] + || [PPDdata scanString:@"End" intoString:NULL] + || [PPDdata scanString:@"SymbolLength" intoString:NULL] + || [PPDdata scanString:@"SymbolEnd" intoString:NULL]) + { + [PPDdata scanUpToCharactersFromSet:newlineSet intoString:NULL]; + continue; + } + + // Read main keyword, up to a colon, space or newline + [PPDdata scanUpToCharactersFromSet:keyEndSet intoString:&keyword]; + + // Loop if there is no value section + if ([PPDdata scanCharactersFromSet:newlineSet intoString:NULL]) + continue; + + // Add the line to the relevant table + if ([keyword isEqual:@"OrderDependency"]) + { + [self addPPDOrderDependency:PPDdata]; + } + else if ([keyword isEqual:@"UIConstraints"]) + { + [self addPPDUIConstraint:PPDdata]; + } + else if ([keyword isEqual:@"Include"]) + { + NSString *fileName; + NSString *path; + [PPDdata scanString:@":" + intoString:NULL]; + + // Find the filename between two "s" + [PPDdata scanString:@"\"" + intoString:NULL]; + + [PPDdata scanUpToString:@"\"" + intoString:&fileName]; + + [PPDdata scanString:@"\"" + intoString:NULL]; + + // Load the file + path = getFile(fileName, nil); + // If not found + if (path == nil || [path length] == 0) + { + [NSException raise:NSPPDIncludeNotFoundException + format:@"Could not find included PPD file %@", + fileName]; + // NOT REACHED + } + includeNum++; + + if (includeNum > MAX_PPD_INCLUDES) + { + [NSException raise:NSPPDIncludeStackOverflowException + format:@"Too many *Includes in PPD"]; + // NOT REACHED + } + + [self loadPPD:[NSString stringWithContentsOfFile:path] + inclusionNum:includeNum]; + } + else if ([keyword isEqual:@"SymbolValue"]) + { + NSString *symbolName; + NSString *symbolVal; + if (![PPDdata scanString:@"^" intoString:NULL]) + { + [NSException raise:NSPPDParseException + format:@"Badly formatted *SymbolValue in PPD file %@.ppd", + PPDFileName]; + // NOT REACHED + } + [PPDdata scanUpToString:@":" + intoString:&symbolName]; + + [PPDdata scanString:@":" + intoString:NULL]; + + [PPDdata scanString:@"\"" + intoString:NULL]; + + [PPDdata scanUpToString:@"\"" + intoString:&symbolVal]; + + if (!symbolVal) + symbolVal = @""; + + [PPDdata scanString:@"\"" + intoString:NULL]; + + [PPDSymbolValues setObject:symbolVal + forKey:symbolName]; + + } + else + { + [self addPPDKeyword:keyword + withScanner:PPDdata]; + } + } + return self; +} + +- addPPDKeyword:(NSString *)mainKeyword + withScanner:(NSScanner *)PPDdata +{ + NSString *optionKeyword = nil; + NSString *optionTranslation = nil; + NSString *value = nil; + NSString *valueTranslation = nil; + // Scan off any optionKeyword + [PPDdata scanUpToCharactersFromSet:optKeyEndSet intoString:&optionKeyword]; + if ([PPDdata scanCharactersFromSet:newlineSet intoString:NULL]) + { + [NSException raise:NSPPDParseException + format:@"Keyword has optional keyword but no value in PPD file %@.ppd", + PPDFileName]; + // NOT REACHED + } + if ([PPDdata scanString:@"/" intoString:NULL]) + { + // Option keyword translation exists - scan it + [PPDdata scanUpToString:@":" intoString:&optionTranslation]; + } + [PPDdata scanString:@":" intoString:NULL]; + // Read the value part + // Values starting with a " are read until the second ", ignoring \n etc. + + if ([PPDdata scanString:@"\"" intoString:NULL]) + { + [PPDdata scanUpToString:@"\"" + intoString:&value]; + + if (!value) + value = @""; + + [PPDdata scanString:@"\"" + intoString:NULL]; + + // It is a QuotedValue if it's in quotes, and there is no option + // key, or the main key is a *JCL keyword + if (!optionKeyword || [[mainKeyword substringToIndex:3] + isEqualToString:@"JCL"]) + { + value = interpretQuotedValue(value); + } + } + else + { + // Otherwise, scan up to the end of line or '/' + [PPDdata scanUpToCharactersFromSet:valueEndSet + intoString:&value]; + } + // If there is a value translation, scan it + if ([PPDdata scanString:@"/" intoString:NULL]) + { + [PPDdata scanUpToCharactersFromSet:newlineSet + intoString:&valueTranslation]; + } + // The translations also have to have any hex substrings interpreted + if (optionTranslation) + optionTranslation = interpretQuotedValue(optionTranslation); + + if (valueTranslation) + valueTranslation = interpretQuotedValue(valueTranslation); + + // The keyword (or keyword/option pair, if there's a option), should only + // only have one value, unless it's one of the optionless keywords which + // allow multiple instances. + // If a keyword is read twice, 'first instance is correct', according to + // the standard. + // Finally, add the strings to the tables + if (optionKeyword) + { + NSString *mainAndOptionKeyword=[mainKeyword + stringByAppendingFormat:@"/%@", + optionKeyword]; + + if ([self isKey:mainAndOptionKeyword inTable:@"PPD"]) + return self; + + [self addValue:value + andValueTranslation:valueTranslation + andOptionTranslation:optionTranslation + forKey:mainAndOptionKeyword]; + + // Deal with the oddities of stringForKey:inTable: + // If this method is used to find a keyword with options, using + // just the keyword it should return an empty string + // stringListForKey:inTable:, however, should return the list of + // option keywords. + // This is done by making the first item in the array an empty + // string, which will be skipped by stringListForKey:, if necessary + if (![_PPD objectForKey:mainKeyword]) + { + [self addString:@"" + forKey:mainKeyword + inTable:_PPD]; + + [self addString:@"" + forKey:mainKeyword + inTable:_PPDOptionTranslation]; + + [self addString:@"" + forKey:mainKeyword + inTable:_PPDArgumentTranslation]; + + } + + [self addValue:optionKeyword + andValueTranslation:optionKeyword + andOptionTranslation:optionKeyword + forKey:mainKeyword]; + } + else + { + if ([self isKey:mainKeyword inTable:@"PPD"] && + ![repKeys containsObject:mainKeyword]) + { + return self; + } + + [self addValue:value + andValueTranslation:valueTranslation + andOptionTranslation:optionTranslation + forKey:mainKeyword]; + } + return self; +} + +- addPPDUIConstraint:(NSScanner *)constraint +{ + NSString *mainKey1 = nil; + NSString *optionKey1 = nil; + NSString *mainKey2 = nil; + NSString *optionKey2 = nil; + // UIConstraint should have no option keyword + if (![constraint scanString:@":" intoString:NULL]) + { + [NSException raise:NSPPDParseException + format:@"UIConstraints has option keyword in PPDFileName %@.ppd", + PPDFileName]; + // NOT REACHED + } + + // Skip the '*' + [constraint scanString:@"*" + intoString:NULL]; + + // Scan the bits. Stuff not starting with * must be an optionKeyword + [constraint scanUpToCharactersFromSet:[NSCharacterSet whitespaceCharacterSet] + intoString:&mainKey1]; + if (![constraint scanString:@"*" intoString:NULL]) + { + [constraint scanUpToCharactersFromSet: + [NSCharacterSet whitespaceCharacterSet] + intoString:&optionKey1]; + + [constraint scanString:@"*" + intoString:NULL]; + + } + + [constraint scanUpToCharactersFromSet: + [NSCharacterSet whitespaceAndNewlineCharacterSet] + intoString:&mainKey2]; + + if (![constraint scanCharactersFromSet:newlineSet intoString:NULL]) + { + [constraint scanUpToCharactersFromSet: + [NSCharacterSet whitespaceAndNewlineCharacterSet] + intoString:&optionKey2]; + } + else + { + optionKey2 = @""; + } + // Add to table + if (optionKey1) + mainKey1 = [mainKey1 stringByAppendingFormat:@"/%@", optionKey1]; + + [self addString:mainKey2 + forKey:mainKey1 + inTable:_PPDUIConstraints]; + + [self addString:optionKey2 + forKey:mainKey1 + inTable:_PPDUIConstraints]; + + return self; +} + +- addPPDOrderDependency:(NSScanner *)dependency +{ + NSString *realValue = nil; + NSString *section = nil; + NSString *keyword = nil; + NSString *optionKeyword = nil; + // Order dependency should have no option keyword + if (![dependency scanString:@":" intoString:NULL]) + { + [NSException raise:NSPPDParseException + format:@"OrderDependency has option keyword in PPD file %@.ppd", + PPDFileName]; + // NOT REACHED + } + [dependency scanUpToCharactersFromSet:[NSCharacterSet whitespaceCharacterSet] + intoString:&realValue]; + + [dependency scanUpToCharactersFromSet:[NSCharacterSet whitespaceCharacterSet] + intoString:§ion]; + + [dependency scanString:@"*" + intoString:NULL]; + + [dependency scanUpToCharactersFromSet: + [NSCharacterSet whitespaceAndNewlineCharacterSet] + intoString:&keyword]; + + if (![dependency scanCharactersFromSet:newlineSet intoString:NULL]) + { + // Optional keyword exists + [dependency scanUpToCharactersFromSet: + [NSCharacterSet whitespaceAndNewlineCharacterSet] + intoString:&optionKeyword]; + } + // Go to next line of PPD file + [dependency scanCharactersFromSet:newlineSet + intoString:NULL]; + + // Add to table + if (optionKeyword) + keyword = [keyword stringByAppendingFormat:@"/%s", optionKeyword]; + + [self addString:realValue + forKey:keyword + inTable:_PPDOrderDependency]; + + [self addString:section + forKey:keyword + inTable:_PPDOrderDependency]; + + return self; +} + + + + +-(id) initWithCoder: (NSCoder*) coder +{ + self = [super initWithCoder: coder]; + return self; +} + +-(void) encodeWithCoder: (NSCoder*) coder +{ + [super encodeWithCoder: coder]; +} + + +@end diff --git a/Source/GNUmakefile b/Source/GNUmakefile index 46a57bcfc..8ac7a118d 100644 --- a/Source/GNUmakefile +++ b/Source/GNUmakefile @@ -191,7 +191,12 @@ GSTitleView.m \ GSToolbar.m \ GSToolbarView.m \ GSStandardWindowDecorationView.m \ -GSWindowDecorationView.m +GSWindowDecorationView.m \ +GSPrinting.m \ +GSPrintOperation.m \ +GSEPSPrintOperation.m \ +GSPDFPrintOperation.m + # Turn off NSMenuItem warning that NSMenuItem conforms to , # but does not implement 's methods itself (it inherits @@ -363,7 +368,11 @@ GSToolbar.h \ GSToolbarView.h \ GSNibCompatibility.h \ GSDragView.h \ -GSTitleView.h +GSTitleView.h \ +GSPrinting.h \ +GSPrintOperation.h \ +GSEPSPrintOperation.h \ +GSPDFPrintOperation.h libgnustep-gui_HEADER_FILES = ${GUI_HEADERS} diff --git a/Source/GSEPSPrintOperation.m b/Source/GSEPSPrintOperation.m new file mode 100644 index 000000000..52d6616ea --- /dev/null +++ b/Source/GSEPSPrintOperation.m @@ -0,0 +1,151 @@ +/* + GSEPSPrintOperation.m + + Controls operations generating EPS output files. + + Copyright (C) 1996, 2004 Free Software Foundation, Inc. + + Author: Scott Christley + Date: 1996 + Author: Fred Kiefer + Date: November 2000 + Started implementation. + Author: Chad Hardin + Date: June 2004 + Modified for printing backend support, split off from NSPrintOperation.m + + 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 "AppKit/NSView.h" +#include "AppKit/NSPrintInfo.h" +#include "AppKit/NSPrintOperation.h" +#include "GNUstepGUI/GSEPSPrintOperation.h" + + +/** + + Class Description +

+ GSEPSPrintOperation is a subclass of NSPrintOperation + that can create eps files suitable for saving, previewing, etc. +

+
+*/ + +@implementation GSEPSPrintOperation + +- (id)initWithView:(NSView *)aView + insideRect:(NSRect)rect + toData:(NSMutableData *)data + printInfo:(NSPrintInfo *)aPrintInfo +{ + self = [super initWithView: aView + insideRect: rect + toData: data + printInfo: aPrintInfo]; + + _path = [NSTemporaryDirectory() stringByAppendingPathComponent: @"GSPrint-"]; + + _path = [_path stringByAppendingString: + [[NSProcessInfo processInfo] globallyUniqueString]]; + + _path = [_path stringByAppendingPathExtension: @"ps"]; + RETAIN( _path ); + return self; +} + +- (id) initWithView:(NSView *)aView + insideRect:(NSRect)rect + toPath:(NSString *)path + printInfo:(NSPrintInfo *)aPrintInfo +{ + NSMutableData *data = [NSMutableData data]; + + self = [super initWithView: aView + insideRect: rect + toData: data + printInfo: aPrintInfo]; + + ASSIGN(_path, path); + + return self; +} + +- (void) _print +{ + /* Save this for the view to look at. Seems like there should + be a better way to pass it to beginDocument */ + [[_printInfo dictionary] setObject: [NSValue valueWithRect: _rect] + forKey: @"NSPrintSheetBounds"]; + + [_view beginDocument]; + + [_view beginPageInRect: _rect + atPlacement: NSMakePoint(0,0)]; + + [_view displayRectIgnoringOpacity: _rect]; + [_view endDocument]; +} + +- (BOOL)isEPSOperation +{ + return YES; +} + +- (BOOL)deliverResult +{ + if (_data != nil && _path != nil) + { + NSString *eps; + + eps = [NSString stringWithContentsOfFile: _path]; + + [_data setData: [eps dataUsingEncoding:NSASCIIStringEncoding]]; + } + + return YES; +} + +- (NSGraphicsContext*)createContext +{ + NSMutableDictionary *info; + + if (_context) + return _context; + + info = [_printInfo dictionary]; + + [info setObject: _path + forKey: @"NSOutputFile"]; + + [info setObject: NSGraphicsContextPSFormat + forKey: NSGraphicsContextRepresentationFormatAttributeName]; + + _context = RETAIN([NSGraphicsContext graphicsContextWithAttributes: info]); + return _context; +} + +@end diff --git a/Source/GSPDFPrintOperation.m b/Source/GSPDFPrintOperation.m new file mode 100644 index 000000000..a48a26d2f --- /dev/null +++ b/Source/GSPDFPrintOperation.m @@ -0,0 +1,112 @@ +/* + GSPDFPrintOperation.m + + Controls operations generating PDF output files. + + Copyright (C) 1996, 2004 Free Software Foundation, Inc. + + Author: Scott Christley + Date: 1996 + Author: Fred Kiefer + Date: November 2000 + Started implementation. + Author: Chad Hardin + Date: June 2004 + Modified for printing backend support, split off from NSPrintOperation.m + 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 "AppKit/NSView.h" +#include "GNUstepGUI/GSPDFPrintOperation.h" + + +/** + + Class Description +

+ GSPDFPrintOperation produces PDF files for saving, previewing, etc +

+
+*/ + + +@implementation GSPDFPrintOperation + +- (id) initWithView:(NSView *)aView + insideRect:(NSRect)rect + toData:(NSMutableData *)data + printInfo:(NSPrintInfo*)aPrintInfo +{ + self = [super initWithView: aView + insideRect: rect + toData: data + printInfo: aPrintInfo]; + + _path = [NSTemporaryDirectory() stringByAppendingPathComponent: @"GSPrint-"]; + + _path = [_path stringByAppendingString: + [[NSProcessInfo processInfo] globallyUniqueString]]; + + _path = [_path stringByAppendingPathExtension: @"pdf"]; + RETAIN( _path ); + + return self; +} + +- (id) initWithView:(NSView *)aView + insideRect:(NSRect)rect + toPath:(NSString *)path + printInfo:(NSPrintInfo*)aPrintInfo +{ + NSMutableData *data = [NSMutableData data]; + + self = [super initWithView: aView + insideRect: rect + toData: data + printInfo: aPrintInfo]; + + ASSIGN(_path, path); + + return self; +} + +- (NSGraphicsContext*)createContext +{ + // FIXME + return nil; +} + +- (void) _print +{ + [_view displayRectIgnoringOpacity: _rect]; +} + +- (BOOL)deliverResult +{ + if (_data != nil && _path != nil && [_data length]) + return [_data writeToFile: _path atomically: NO]; + // FIXME Until we can create PDF we shoud convert the file with GhostScript + + return YES; +} + +@end diff --git a/Source/GSPrintOperation.m b/Source/GSPrintOperation.m new file mode 100644 index 000000000..7f630423b --- /dev/null +++ b/Source/GSPrintOperation.m @@ -0,0 +1,171 @@ +/* + GSPrintOperation.m + + Controls operations generating print jobs. + + Copyright (C) 1996,2004 Free Software Foundation, Inc. + + Author: Scott Christley + Date: 1996 + Author: Fred Kiefer + Date: November 2000 + Started implementation. + Author: Chad Hardin + Date: June 2004 + Modified for printing backend support, split off from NSPrintOperation.m + + 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 "AppKit/NSView.h" +#include "AppKit/NSPrintPanel.h" +#include "AppKit/NSPrintInfo.h" +#include "AppKit/NSWorkspace.h" +#include "GNUstepGUI/GSPrinting.h" +#include "GNUstepGUI/GSPrintOperation.h" + + + + +/** + + Class Description +

+ GSPrintOperation is a generic class that should be subclasses + by printing backend classes for the purpose of controlling and + sending print jobs to a printing system. +

+
+*/ + + + + +@implementation GSPrintOperation + +/** Load the appropriate bundle for the PrintInfo + (eg: GSLPRPrintInfo, GSCUPSPrintInfo). +*/ ++ (id) allocWithZone: (NSZone*) zone +{ + Class principalClass; + + principalClass = [[GSPrinting printingBundle] principalClass]; + + if( principalClass == nil ) + return nil; + + return [[principalClass gsPrintOperationClass] allocWithZone: zone]; +} + + + +- (id)initWithView:(NSView *)aView + printInfo:(NSPrintInfo *)aPrintInfo +{ + + self = [self initWithView: aView + insideRect: [aView bounds] + toData: [NSMutableData data] + printInfo: aPrintInfo]; + + _showPanels = YES; + + return self; +} + +- (NSGraphicsContext*)createContext +{ + [self subclassResponsibility: _cmd]; + return nil; +} + + +/** +/ !!!Here is the method that will be overridden in the printer bundle +*/ +- (BOOL) _deliverSpooledResult +{ + [self subclassResponsibility: _cmd]; + return NO; +} + + +- (BOOL) deliverResult +{ + BOOL success; + NSString *job; + + success = YES; + job = [_printInfo jobDisposition]; + if ([job isEqual: NSPrintPreviewJob]) + { + /* Check to see if there is a GNUstep app that can preview PS files. + It's not likely at this point, so also check for a standards + previewer, like gv. + */ + NSTask *task; + NSString *preview; + NSWorkspace *ws = [NSWorkspace sharedWorkspace]; + [_printPanel _setStatusStringValue: @"Opening in previewer..."]; + + preview = [ws getBestAppInRole: @"Viewer" + forExtension: @"ps"]; + if (preview) + { + [ws openFile: _path withApplication: preview]; + } + else + { + NSUserDefaults *def = [NSUserDefaults standardUserDefaults]; + preview = [def objectForKey: @"NSPreviewApp"]; + + if (preview == nil || [preview length] == 0) + preview = @"gv"; + + task = [NSTask new]; + [task setLaunchPath: preview]; + [task setArguments: [NSArray arrayWithObject: _path]]; + [task launch]; + AUTORELEASE(task); + } + } + else if ([job isEqual: NSPrintSpoolJob]) + { + success = [self _deliverSpooledResult]; + } + else if ([job isEqual: NSPrintFaxJob]) + { + } + + /* We can't remove the temp file because the previewer might still be + using it, perhaps the printer is also? + if ( _path ) + { + [[NSFileManager defaultManager] removeFileAtPath: _path + handler: nil]; + } + */ + return success; +} + +@end + diff --git a/Source/GSPrinting.m b/Source/GSPrinting.m new file mode 100644 index 000000000..f2cbde9d5 --- /dev/null +++ b/Source/GSPrinting.m @@ -0,0 +1,234 @@ +/** GSPrinting.m + + GSPrinting loads the proper bundle for the printing backend. + + Copyright (C) 2004 Free Software Foundation, Inc. + + Author: Chad Elliott Hardin + Date: June 2004 + + 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 "GNUstepGUI/GSPrinting.h" +#include +#include +#include +#include +#include +#include +#include +#include "AppKit/NSPanel.h" + +static NSBundle *printingBundle = nil; + + +/** + + Class Description +

+ GSPrinting is used by all of the NSPrint and the NSPageLayout + class(es) so that a printing backend bundle can be loaded. It + first utilizes NSUserDefaults to find the user's preferred printing + backend bundle. It looks for the key GSPrinting. If the user's + preferred bundle cannot be loaded, it tries to load any working + printing bundle. +

+
+*/ +@implementation GSPrinting + ++(NSBundle*) loadPrintingBundle: (NSString*) bundleName +{ + NSString *path; + NSEnumerator *libraryPathsEnumerator; + + bundleName = [bundleName stringByAppendingString: @".bundle"]; + + NSDebugLLog(@"GSPrinting", @"Looking for %@", bundleName); + + libraryPathsEnumerator = [NSStandardLibraryPaths() objectEnumerator]; + + while( (path = [libraryPathsEnumerator nextObject]) ) + { + path = [path stringByAppendingPathComponent: @"Bundles"]; + path = [path stringByAppendingPathComponent: @"GSPrinting"]; + path = [path stringByAppendingPathComponent: bundleName]; + + if ([[NSFileManager defaultManager] fileExistsAtPath: path]) + { + NSBundle *bundle; + + bundle = [NSBundle bundleWithPath: path]; + if( [bundle load] == NO ) + { + NSDebugLLog(@"GSPrinting", @"Error loading printing bundle at %@", path); + return nil; + } + else + { + //one last check to make sure the principle class can be loaded + if( [bundle principalClass] == Nil) + { + NSDebugLLog(@"GSPrinting", @"Error loading principal class from printing bundle at %@", path); + return nil; + } + //if we get here, finally, then everything should be ok, barring errors from later in loading resources. + NSDebugLLog(@"GSPrinting", @"Loaded printing bundle at %@", path); + return bundle; + } + } + } + + NSDebugLLog(@"GSPrinting", @"Unable to find printing bundle %@", bundleName); + return nil; +} + + + ++(NSBundle*) loadAnyWorkingPrintingBundle +{ + NSBundle *bundle; + + if( (bundle = [GSPrinting loadPrintingBundle: @"GSCUPS"]) ) + return bundle; + + if( (bundle = [GSPrinting loadPrintingBundle: @"GSLPR"]) ) + return bundle; + + if( (bundle = [GSPrinting loadPrintingBundle: @"GSWin32"]) ) + return bundle; + + return nil; +} + + + ++ (NSBundle*) printingBundle +{ + NSString *defaultBundleName; + NSBundle *bundle; + + if( printingBundle ) + { + return printingBundle; + } + + NSDebugLLog(@"GSPrinting", @"Bundle has not been loaded. Loading in progress..."); + + defaultBundleName = [[NSUserDefaults standardUserDefaults] stringForKey: @"GSPrinting"]; + + /*Which Printing Bundle?*/ + if( defaultBundleName == nil ) + { + NSDebugLLog(@"GSPrinting", @"User did not set a printing bundle, trying till something works"); + bundle = [GSPrinting loadAnyWorkingPrintingBundle]; + if( bundle == nil ) + { + NSDebugLLog(@"GSPrinting", @"Could not load any working printing bundle"); + NSRunAlertPanel(@"GNUstep Printing Backend System", @"Could not open any working printing bundle. Printing will not work.", @"Ok", NULL, NULL ); + return nil; + } + } + else + { + NSDebugLLog(@"GSPrinting", @"User set %@ as the printing bundle", defaultBundleName); + + bundle = [GSPrinting loadPrintingBundle: defaultBundleName]; + if( bundle == nil ) + { + NSDebugLLog(@"GSPrinting", @"User set %@ as the printing bundle but that did not work. Will try to find anything that will work", defaultBundleName); + bundle = [GSPrinting loadAnyWorkingPrintingBundle]; + if( bundle == nil ) + { + NSDebugLLog(@"GSPrinting", @"Could not load any working printing bundle"); + NSRunAlertPanel(@"GNUstep Printing Backend System", @"Could not open any working printing bundle. Printing will not work.", @"Ok", NULL, NULL ); + return nil; + } + else + { + NSString *msg; + msg = [NSString stringWithFormat: @"Your chosen printing bundle, %@, could not be loaded. %@ was loaded instead", defaultBundleName, [[bundle bundlePath] lastPathComponent]]; + NSRunAlertPanel(@"GNUstep Printing Backend System", msg, @"Ok", NULL, NULL ); + } + } + } + + printingBundle = bundle; + [printingBundle retain]; + return printingBundle; +} + +@end + + + + + + + +/** + + Class Description +

+ GSPrintingPrincipleClass is the base class that all + Printing backend bundles should use as their principle + class. Subclasses are responsible for the allocating + of that bundle's particular NSPrint, NSPageLayout, and + GSPrintOperation sublclassed objects. +

+
+*/ +@implementation GSPrintingPrincipalClass : NSObject +{ +} + ++(Class) pageLayoutClass +{ + return Nil; +} + ++(Class) printInfoClass +{ + return Nil; +} + + ++(Class) printOperationClass +{ + return Nil; +} + ++(Class) printPanelClass +{ + return Nil; +} + + ++(Class) printerClass +{ + return Nil; +} + ++(Class) gsPrintOperationClass +{ + return Nil; +} + + +@end diff --git a/Source/NSPageLayout.m b/Source/NSPageLayout.m index 168531e7a..fbd9e63e6 100644 --- a/Source/NSPageLayout.m +++ b/Source/NSPageLayout.m @@ -2,10 +2,13 @@ Standard panel for querying user about page layout. - Copyright (C) 2001 Free Software Foundation, Inc. + Copyright (C) 2001,2004 Free Software Foundation, Inc. Written By: Adam Fedor Date: Oct 2001 + Modified for Printing Backend Support + Author: Chad Hardin + Date: June 2004 This file is part of the GNUstep GUI Library. @@ -43,6 +46,7 @@ #include "AppKit/NSPageLayout.h" #include "AppKit/NSPrinter.h" #include "GSGuiPrivate.h" +#include "GNUstepGUI/GSPrinting.h" static NSPageLayout *shared_instance; @@ -82,6 +86,22 @@ static NSPageLayout *shared_instance; // // Class methods // +/** Load the appropriate bundle for the PageLayout + (eg: GSLPRPageLayout, GSCUPSPageLayout). +*/ ++ (id) allocWithZone: (NSZone*) zone +{ + Class principalClass; + + principalClass = [[GSPrinting printingBundle] principalClass]; + + if( principalClass == nil ) + return nil; + + return [[principalClass pageLayoutClass] allocWithZone: zone]; +} + + /** Creates and returns a shared instance of the NSPageLayout panel. */ + (NSPageLayout *)pageLayout @@ -403,7 +423,7 @@ static NSPageLayout *shared_instance; - (void)pickedButton:(id)sender { NSLog(@"[NSPageLayout -pickedButton:] method depreciated"); - [self pickedButton: sender]; + //[self pickedButton: sender]; } /** This method has been depreciated. It doesn't do anything useful. diff --git a/Source/NSPrintInfo.m b/Source/NSPrintInfo.m index 41eeb322c..ee1dd879b 100644 --- a/Source/NSPrintInfo.m +++ b/Source/NSPrintInfo.m @@ -3,10 +3,13 @@ Stores information used in printing - Copyright (C) 1996,1997 Free Software Foundation, Inc. + Copyright (C) 1996,1997,2004 Free Software Foundation, Inc. Author: Simon Frankau Date: July 1997 + Modified for Printing Backend Support + Author: Chad Hardin + Date: June 2004 This file is part of the GNUstep GUI Library. @@ -35,8 +38,8 @@ #include #include #include "AppKit/NSPrinter.h" - #include "AppKit/NSPrintInfo.h" +#include "GNUstepGUI/GSPrinting.h" #define NSNUMBER(val) [NSNumber numberWithInt: val] #define DICTSET(dict, obj, key) \ @@ -45,12 +48,8 @@ // FIXME: retain/release of dictionary with retain/release of printInfo? // Class variables: -static NSPrintInfo *sharedPrintInfoObject = nil; -static NSMutableDictionary *printInfoDefaults = nil; +static NSPrintInfo *sharedPrintInfo = nil; -@interface NSPrintInfo (private) -+ initPrintInfoDefaults; -@end /** @@ -76,24 +75,36 @@ static NSMutableDictionary *printInfoDefaults = nil; } } +/** Load the appropriate bundle for the PrintInfo + (eg: GSLPRPrintInfo, GSCUPSPrintInfo). +*/ ++ (id) allocWithZone: (NSZone*) zone +{ + Class principalClass; + + principalClass = [[GSPrinting printingBundle] principalClass]; + + if( principalClass == nil ) + return nil; + + return [[principalClass printInfoClass] allocWithZone: zone]; +} + // // Managing the Shared NSPrintInfo Object // + (void)setSharedPrintInfo:(NSPrintInfo *)printInfo { - sharedPrintInfoObject = printInfo; + ASSIGN(sharedPrintInfo, printInfo); } + (NSPrintInfo *)sharedPrintInfo { - if (!sharedPrintInfoObject) - { - if (!printInfoDefaults) - [NSPrintInfo initPrintInfoDefaults]; - sharedPrintInfoObject = [[self alloc] - initWithDictionary:printInfoDefaults]; - } - return sharedPrintInfoObject; + if (!sharedPrintInfo) + { + sharedPrintInfo = [[NSPrintInfo alloc] initWithDictionary: nil]; + } + return sharedPrintInfo; } // @@ -109,16 +120,26 @@ static NSMutableDictionary *printInfoDefaults = nil; // + (NSPrinter *)defaultPrinter { - if (!printInfoDefaults) - [NSPrintInfo initPrintInfoDefaults]; - return [printInfoDefaults objectForKey:NSPrintPrinter]; + Class principalClass; + + principalClass = [[GSPrinting printingBundle] principalClass]; + + if( principalClass == nil ) + return nil; + + return [[principalClass printInfoClass] defaultPrinter]; } + (void)setDefaultPrinter:(NSPrinter *)printer { - if (!printInfoDefaults) - [NSPrintInfo initPrintInfoDefaults]; - [printInfoDefaults setObject:printer forKey:NSPrintPrinter]; + Class principalClass; + + principalClass = [[GSPrinting printingBundle] principalClass]; + + if( principalClass == nil ) + return; + + [[principalClass printInfoClass] setDefaultPrinter: printer]; } // @@ -130,7 +151,40 @@ static NSMutableDictionary *printInfoDefaults = nil; - (id)initWithDictionary:(NSDictionary *)aDict { [super init]; - _info = [[NSMutableDictionary alloc] initWithDictionary:aDict]; + + _info = [[NSMutableDictionary alloc] init]; + + //put in the defaults + [self setVerticalPagination: NSAutoPagination]; + + [self setHorizontalPagination: NSClipPagination]; + + [self setJobDisposition: NSPrintSpoolJob]; + + [self setHorizontallyCentered: YES]; + + [self setVerticallyCentered: YES]; + + [self setOrientation: NSPortraitOrientation]; + + if( aDict != nil ) + { + [_info addEntriesFromDictionary: aDict]; + + if([[_info objectForKey: NSPrintPrinter] isKindOfClass: [NSString class]]) + { + NSString *printerName; + NSPrinter *printer; + + printerName = [_info objectForKey: NSPrintPrinter]; + printer = [NSPrinter printerWithName: printerName]; + + if( printer ) + [self setPrinter: printer]; + else + [_info removeObjectForKey: NSPrintPrinter]; + } + } return self; } @@ -330,20 +384,7 @@ static NSMutableDictionary *printInfoDefaults = nil; - (void)setUpPrintOperationDefaultValues { - NSEnumerator *keys, *objects; - NSString *key; - id object; - - if (!printInfoDefaults) - [NSPrintInfo initPrintInfoDefaults]; - keys = [printInfoDefaults keyEnumerator]; - objects = [printInfoDefaults objectEnumerator]; - while ((key = [keys nextObject])) - { - object = [objects nextObject]; - if (![_info objectForKey:key]) - [_info setObject:object forKey:key]; - } + [self subclassResponsibility: _cmd]; } // @@ -359,73 +400,34 @@ static NSMutableDictionary *printInfoDefaults = nil; // - (void) encodeWithCoder: (NSCoder*)aCoder { + //There is a NSPrinter in the dict, will that work as a Property list? + NSMutableDictionary *dict; + + dict = AUTORELEASE([_info mutableCopy]); + + [dict setObject: [[self printer] name] + forKey: NSPrintPrinter]; + [aCoder encodePropertyList: _info]; } - (id) initWithCoder: (NSCoder*)aDecoder { + NSString *printerName; + NSPrinter *printer; + _info = RETAIN([aDecoder decodePropertyList]); - return self; -} - -// -// Private method to initialise printing defaults dictionary -// -+ initPrintInfoDefaults -{ - NSUserDefaults *def; - NSString *defPrinter, *str; - NSPrinter *printer = nil; - - def = [NSUserDefaults standardUserDefaults]; - printInfoDefaults = [def objectForKey: @"DefaultPrinter"]; - if (printInfoDefaults) - printInfoDefaults = [printInfoDefaults mutableCopy]; - defPrinter = [printInfoDefaults objectForKey:NSPrintPrinter]; - if (defPrinter) - printer = [NSPrinter printerWithName: defPrinter]; - if (printer == nil) - defPrinter = nil; - if (printInfoDefaults == nil) - { - NSDebugLog(@"NSPrinter", @"Could not find printing defaults table"); - printInfoDefaults = RETAIN([NSMutableDictionary dictionary]); - } - if (defPrinter == nil) - { - defPrinter = [[NSPrinter printerNames] objectAtIndex: 0]; - DICTSET(printInfoDefaults, defPrinter, NSPrintPrinter); - } - - /* Replace the printer name with a real NSPrinter object */ - printer = [NSPrinter printerWithName: defPrinter]; - DICTSET(printInfoDefaults, [NSPrinter printerWithName: defPrinter], NSPrintPrinter); - - /* Set up other defaults from the printer object */ - str = [printer stringForKey:@"DefaultPageSize" inTable: @"PPD"]; - /* FIXME: Need to check for AutoSelect and probably a million other things... */ - if (str == nil) - str = @"A4"; - DICTSET(printInfoDefaults, str, NSPrintPaperName); - DICTSET(printInfoDefaults, - [NSValue valueWithSize: [NSPrintInfo sizeForPaperName: str]], - NSPrintPaperSize); - - /* Set default margins. FIXME: Probably should check ImageableArea */ - DICTSET(printInfoDefaults, NSNUMBER(36), NSPrintRightMargin); - DICTSET(printInfoDefaults, NSNUMBER(36), NSPrintLeftMargin); - DICTSET(printInfoDefaults, NSNUMBER(72), NSPrintTopMargin); - DICTSET(printInfoDefaults, NSNUMBER(72), NSPrintBottomMargin); - DICTSET(printInfoDefaults, NSNUMBER(NSPortraitOrientation), - NSPrintOrientation); - //DICTSET(printInfoDefaults, NSNUMBER(NSClipPagination), - // NSPrintHorizontalPagination); - DICTSET(printInfoDefaults, NSNUMBER(NSAutoPagination), - NSPrintVerticalPagination); - DICTSET(printInfoDefaults, NSNUMBER(1), NSPrintHorizontallyCentered); - DICTSET(printInfoDefaults, NSNUMBER(1), NSPrintVerticallyCentered); - + + printerName = [_info objectForKey: NSPrintPrinter]; + printer = [NSPrinter printerWithName: printerName]; + + if( printer ) + [self setPrinter: printer]; + else + [_info removeObjectForKey: NSPrintPrinter]; + return self; } @end + diff --git a/Source/NSPrintOperation.m b/Source/NSPrintOperation.m index c9c273011..273a2eea9 100644 --- a/Source/NSPrintOperation.m +++ b/Source/NSPrintOperation.m @@ -1,15 +1,18 @@ /* NSPrintOperation.m - Controls operations generating EPS, PDF or PS print jobs. + Controls operations generating print jobs. - Copyright (C) 1996 Free Software Foundation, Inc. + Copyright (C) 1996,2004 Free Software Foundation, Inc. Author: Scott Christley Date: 1996 Author: Fred Kiefer Date: November 2000 Started implementation. + Modified for Printing Backend Support + Author: Chad Hardin + Date: June 2004 This file is part of the GNUstep GUI Library. @@ -52,6 +55,9 @@ #include "AppKit/NSPrintOperation.h" #include "AppKit/NSWorkspace.h" #include "AppKit/PSOperators.h" +#include "GNUstepGUI/GSEPSPrintOperation.h" +#include "GNUstepGUI/GSPDFPrintOperation.h" +#include "GNUstepGUI/GSPrintOperation.h" #define NSNUMBER(a) [NSNumber numberWithInt: (a)] #define NSFNUMBER(a) [NSNumber numberWithFloat: (a)] @@ -75,20 +81,27 @@ typedef struct _page_info_t { int pageDirection; /* NSPrintPageDirection */ } page_info_t; -@interface NSPrintOperation (Private) - -- (id) initWithView:(NSView *)aView - insideRect:(NSRect)rect - toData:(NSMutableData *)data - printInfo:(NSPrintInfo *)aPrintInfo; +@interface NSPrintOperation (TrulyPrivate) +- (BOOL) _runOperation; +- (void) _setupPrintInfo; +- (void)_printOperationDidRun:(NSPrintOperation *)printOperation + success:(BOOL)success + contextInfo:(void *)contextInfo; +- (void) _printPaginateWithInfo: (page_info_t *)info + knowsRange: (BOOL)knowsRange; +- (NSRect) _rectForPage: (int)page info: (page_info_t *)info + xpage: (int *)xptr + ypage: (int *)yptr; +- (NSRect) _adjustPagesFirst: (int)first + last: (int)last + info: (page_info_t *)info; - (void) _print; - @end -@interface NSPrintPanel (Private) -- (void) _setStatusStringValue: (NSString *)string; -@end + + + @interface NSView (NSPrintOperation) @@ -102,40 +115,7 @@ typedef struct _page_info_t { - (void) _cleanupPrinting; @end -// Subclass for the regular printing -@interface GSPrintOperation: NSPrintOperation -{ -} -@end - -// subclass for EPS output -@interface GSEPSPrintOperation: NSPrintOperation -{ -} - -- (id) initEPSOperationWithView:(NSView *)aView - insideRect:(NSRect)rect - toPath:(NSString *)path - printInfo:(NSPrintInfo *)aPrintInfo; - -@end - -// subclass for PDF output -@interface GSPDFPrintOperation: NSPrintOperation -{ -} - -- (id) initPDFOperationWithView:(NSView *)aView - insideRect:(NSRect)rect - toData:(NSMutableData *)data - printInfo:(NSPrintInfo*)aPrintInfo; -- (id) initPDFOperationWithView:(NSView *)aView - insideRect:(NSRect)rect - toPath:(NSString *)path - printInfo:(NSPrintInfo*)aPrintInfo; - -@end static NSString *NSPrintOperationThreadKey = @"NSPrintOperationThreadKey"; @@ -186,7 +166,7 @@ static NSString *NSPrintOperationThreadKey = @"NSPrintOperationThreadKey"; toData:(NSMutableData *)data printInfo:(NSPrintInfo *)aPrintInfo { - return AUTORELEASE([[GSEPSPrintOperation alloc] initEPSOperationWithView: aView + return AUTORELEASE([[GSEPSPrintOperation alloc] initWithView: aView insideRect: rect toData: data printInfo: aPrintInfo]); @@ -197,7 +177,7 @@ static NSString *NSPrintOperationThreadKey = @"NSPrintOperationThreadKey"; toPath:(NSString *)path printInfo:(NSPrintInfo *)aPrintInfo { - return AUTORELEASE([[GSEPSPrintOperation alloc] initEPSOperationWithView: aView + return AUTORELEASE([[GSEPSPrintOperation alloc] initWithView: aView insideRect: rect toPath: path printInfo: aPrintInfo]); @@ -232,7 +212,7 @@ static NSString *NSPrintOperationThreadKey = @"NSPrintOperationThreadKey"; printInfo:(NSPrintInfo*)aPrintInfo { return AUTORELEASE([[GSPDFPrintOperation alloc] - initPDFOperationWithView: aView + initWithView: aView insideRect: rect toData: data printInfo: aPrintInfo]); @@ -244,7 +224,7 @@ static NSString *NSPrintOperationThreadKey = @"NSPrintOperationThreadKey"; printInfo:(NSPrintInfo*)aPrintInfo { return AUTORELEASE([[GSPDFPrintOperation alloc] - initPDFOperationWithView: aView + initWithView: aView insideRect: rect toPath: path printInfo: aPrintInfo]); @@ -293,7 +273,7 @@ static NSString *NSPrintOperationThreadKey = @"NSPrintOperationThreadKey"; { RELEASE(self); - return [[GSEPSPrintOperation alloc] initEPSOperationWithView: aView + return [[GSEPSPrintOperation alloc] initWithView: aView insideRect: rect toData: data printInfo: aPrintInfo]; @@ -466,64 +446,6 @@ static NSString *NSPrintOperationThreadKey = @"NSPrintOperationThreadKey"; return NO; } -/* Private method to run the printing operation. Needs to create an - autoreleaes pool to make sure the print context is destroyed before - returning (which closes the print file.) */ -- (BOOL) _runOperation -{ - BOOL result; - CREATE_AUTORELEASE_POOL(pool); - NSGraphicsContext *oldContext = [NSGraphicsContext currentContext]; - - [self createContext]; - if (_context == nil) - return NO; - - result = NO; - if (_pageOrder == NSUnknownPageOrder) - { - if ([[[_printInfo dictionary] objectForKey: NSPrintReversePageOrder] - boolValue] == YES) - _pageOrder = NSDescendingPageOrder; - else - _pageOrder = NSAscendingPageOrder; - } - - [NSGraphicsContext setCurrentContext: _context]; - NS_DURING - { - [self _print]; - result = YES; - [NSGraphicsContext setCurrentContext: oldContext]; - } - NS_HANDLER - { - [_view _cleanupPrinting]; - [NSGraphicsContext setCurrentContext: oldContext]; - NSRunAlertPanel(@"Error", @"Printing error: %@", - @"OK", NULL, NULL, localException); - } - NS_ENDHANDLER - [self destroyContext]; - RELEASE(pool); - return result; -} - -- (void) _setupPrintInfo -{ - BOOL knowsPageRange; - NSRange viewPageRange; - NSMutableDictionary *dict = [_printInfo dictionary]; - - knowsPageRange = [_view knowsPageRange: &viewPageRange]; - if (knowsPageRange == YES) - { - int first = viewPageRange.location; - int last = NSMaxRange(viewPageRange) - 1; - [dict setObject: NSNUMBER(first) forKey: NSPrintFirstPage]; - [dict setObject: NSNUMBER(last) forKey: NSPrintLastPage]; - } -} /** Call this message to run the print operation on a view. This includes (optionally) displaying a print panel and working with the NSView to @@ -560,31 +482,7 @@ static NSString *NSPrintOperationThreadKey = @"NSPrintOperationThreadKey"; return result; } -- (void)_printOperationDidRun:(NSPrintOperation *)printOperation - success:(BOOL)success - contextInfo:(void *)contextInfo -{ - id delegate; - SEL *didRunSelector; - NSMutableDictionary *dict; - void (*didRun)(id, SEL, BOOL, id); - if (success == YES) - { - NSPrintPanel *panel = [self printPanel]; - [panel finalWritePrintInfo]; - success = NO; - if ([self _runOperation]) - success = [self deliverResult]; - } - [self cleanUpOperation]; - dict = [_printInfo dictionary]; - didRunSelector = [[dict objectForKey: @"GSModalRunSelector"] pointerValue]; - delegate = [dict objectForKey: @"GSModalRunDelegate"]; - didRun = (void (*)(id, SEL, BOOL, id))[delegate methodForSelector: - *didRunSelector]; - didRun (delegate, *didRunSelector, success, contextInfo); -} /** Run a print operation modally with respect to a window. */ @@ -659,8 +557,10 @@ static NSString *NSPrintOperationThreadKey = @"NSPrintOperationThreadKey"; printInfo:(NSPrintInfo *)aPrintInfo { if ([NSPrintOperation currentOperation] != nil) - [NSException raise: NSPrintOperationExistsException - format: @"There is already a printoperation for this thread"]; + { + [NSException raise: NSPrintOperationExistsException + format: @"There is already a printoperation for this thread"]; + } ASSIGN(_view, aView); _rect = rect; @@ -668,18 +568,105 @@ static NSString *NSPrintOperationThreadKey = @"NSPrintOperationThreadKey"; _pageOrder = NSUnknownPageOrder; _showPanels = NO; [self setPrintInfo: aPrintInfo]; - - _path = [NSTemporaryDirectory() stringByAppendingPathComponent: @"GSPrint-"]; - _path = [_path stringByAppendingString: - [[NSProcessInfo processInfo] globallyUniqueString]]; - _path = [_path stringByAppendingPathExtension: @"ps"]; - RETAIN(_path); - _pathSet = NO; + _path = nil; _currentPage = 0; [NSPrintOperation setCurrentOperation: self]; return self; } +@end + +@implementation NSPrintOperation (TrulyPrivate) + + +/* Private method to run the printing operation. Needs to create an + autoreleaes pool to make sure the print context is destroyed before + returning (which closes the print file.) */ +- (BOOL) _runOperation +{ + BOOL result; + CREATE_AUTORELEASE_POOL(pool); + NSGraphicsContext *oldContext = [NSGraphicsContext currentContext]; + + [self createContext]; + if (_context == nil) + return NO; + + result = NO; + if (_pageOrder == NSUnknownPageOrder) + { + if ([[[_printInfo dictionary] objectForKey: NSPrintReversePageOrder] + boolValue] == YES) + _pageOrder = NSDescendingPageOrder; + else + _pageOrder = NSAscendingPageOrder; + } + + [NSGraphicsContext setCurrentContext: _context]; + NS_DURING + { + [self _print]; + result = YES; + [NSGraphicsContext setCurrentContext: oldContext]; + } + NS_HANDLER + { + [_view _cleanupPrinting]; + [NSGraphicsContext setCurrentContext: oldContext]; + NSRunAlertPanel(@"Error", @"Printing error: %@", + @"OK", NULL, NULL, localException); + } + NS_ENDHANDLER + [self destroyContext]; + RELEASE(pool); + return result; +} + +- (void) _setupPrintInfo +{ + BOOL knowsPageRange; + NSRange viewPageRange; + NSMutableDictionary *dict = [_printInfo dictionary]; + + knowsPageRange = [_view knowsPageRange: &viewPageRange]; + if (knowsPageRange == YES) + { + int first = viewPageRange.location; + int last = NSMaxRange(viewPageRange) - 1; + [dict setObject: NSNUMBER(first) forKey: NSPrintFirstPage]; + [dict setObject: NSNUMBER(last) forKey: NSPrintLastPage]; + } +} + +- (void)_printOperationDidRun:(NSPrintOperation *)printOperation + success:(BOOL)success + contextInfo:(void *)contextInfo +{ + id delegate; + SEL *didRunSelector; + NSMutableDictionary *dict; + void (*didRun)(id, SEL, BOOL, id); + + if (success == YES) + { + NSPrintPanel *panel = [self printPanel]; + [panel finalWritePrintInfo]; + success = NO; + if ([self _runOperation]) + success = [self deliverResult]; + } + [self cleanUpOperation]; + dict = [_printInfo dictionary]; + didRunSelector = [[dict objectForKey: @"GSModalRunSelector"] pointerValue]; + delegate = [dict objectForKey: @"GSModalRunDelegate"]; + didRun = (void (*)(id, SEL, BOOL, id))[delegate methodForSelector: + *didRunSelector]; + didRun (delegate, *didRunSelector, success, contextInfo); +} + + + + static NSSize scaleSize(NSSize size, double scale) @@ -1113,266 +1100,3 @@ scaleRect(NSRect rect, double scale) } @end - -@implementation GSPrintOperation - -- (id)initWithView:(NSView *)aView - printInfo:(NSPrintInfo *)aPrintInfo -{ - NSMutableData *data = [NSMutableData data]; - - self = [self initWithView: aView - insideRect: [aView bounds] - toData: data - printInfo: aPrintInfo]; - _showPanels = YES; - - return self; -} - -- (NSGraphicsContext*)createContext -{ - NSMutableDictionary *info; - if (_context) - return _context; - - info = [_printInfo dictionary]; - if (_pathSet == NO) - { - NSString *output = [info objectForKey: NSPrintSavePath]; - if (output) - { - ASSIGN(_path, output); - _pathSet = YES; - } - } - - [info setObject: _path forKey: @"NSOutputFile"]; - [info setObject: NSGraphicsContextPSFormat - forKey: NSGraphicsContextRepresentationFormatAttributeName]; - _context = RETAIN([NSGraphicsContext graphicsContextWithAttributes: info]); - - return _context; -} - -- (BOOL) _deliverSpooledResult -{ - int copies; - NSDictionary *dict; - NSTask *task; - NSString *name, *status; - NSMutableArray *args; - name = [[_printInfo printer] name]; - status = [NSString stringWithFormat: @"Spooling to printer %@.", name]; - [_printPanel _setStatusStringValue: status]; - - dict = [_printInfo dictionary]; - args = [NSMutableArray array]; - copies = [[dict objectForKey: NSPrintCopies] intValue]; - if (copies > 1) - [args addObject: [NSString stringWithFormat: @"-#%0d", copies]]; - if ([name isEqual: @"Unknown"] == NO) - { - [args addObject: @"-P"]; - [args addObject: name]; - } - [args addObject: _path]; - - task = [NSTask new]; - [task setLaunchPath: @"lpr"]; - [task setArguments: args]; - [task launch]; - [task waitUntilExit]; - AUTORELEASE(task); - return YES; -} - -- (BOOL) deliverResult -{ - BOOL success; - NSString *job; - - success = YES; - job = [_printInfo jobDisposition]; - if ([job isEqual: NSPrintPreviewJob]) - { - /* Check to see if there is a GNUstep app that can preview PS files. - It's not likely at this point, so also check for a standards - previewer, like gv. - */ - NSTask *task; - NSString *preview; - NSWorkspace *ws = [NSWorkspace sharedWorkspace]; - [_printPanel _setStatusStringValue: @"Opening in previewer..."]; - preview = [ws getBestAppInRole: @"Viewer" forExtension: @"ps"]; - if (preview) - { - [ws openFile: _path withApplication: preview]; - } - else - { - NSUserDefaults *def = [NSUserDefaults standardUserDefaults]; - preview = [def objectForKey: @"NSPreviewApp"]; - if (preview == nil || [preview length] == 0) - preview = @"gv"; - task = [NSTask new]; - [task setLaunchPath: preview]; - [task setArguments: [NSArray arrayWithObject: _path]]; - [task launch]; - AUTORELEASE(task); - } - } - else if ([job isEqual: NSPrintSpoolJob]) - { - success = [self _deliverSpooledResult]; - } - else if ([job isEqual: NSPrintFaxJob]) - { - } - - /* We can't remove the temp file because the previewer might still be - using it, perhaps the printer is also? - if (!_pathSet) - [[NSFileManager defaultManager] removeFileAtPath: _path - handler: nil]; - */ - return success; -} - -@end - -@implementation GSEPSPrintOperation - -- (id)initEPSOperationWithView:(NSView *)aView - insideRect:(NSRect)rect - toData:(NSMutableData *)data - printInfo:(NSPrintInfo *)aPrintInfo -{ - self = [self initWithView: aView - insideRect: rect - toData: data - printInfo: aPrintInfo]; - _pathSet = YES; /* Use the default temp path */ - return self; -} - -- (id) initEPSOperationWithView:(NSView *)aView - insideRect:(NSRect)rect - toPath:(NSString *)path - printInfo:(NSPrintInfo *)aPrintInfo -{ - NSMutableData *data = [NSMutableData data]; - - self = [self initEPSOperationWithView: aView - insideRect: rect - toData: data - printInfo: aPrintInfo]; - - ASSIGN(_path, path); - _pathSet = YES; - - return self; -} - -- (void) _print -{ - /* Save this for the view to look at. Seems like there should - be a better way to pass it to beginDocument */ - [[_printInfo dictionary] setObject: [NSValue valueWithRect: _rect] - forKey: @"NSPrintSheetBounds"]; - [_view beginDocument]; - [_view beginPageInRect: _rect atPlacement: NSMakePoint(0,0)]; - [_view displayRectIgnoringOpacity: _rect]; - [_view endDocument]; -} - -- (BOOL)isEPSOperation -{ - return YES; -} - -- (BOOL)deliverResult -{ - if (_data != nil && _path != nil) - { - NSString *eps; - - eps = [NSString stringWithContentsOfFile: _path]; - [_data setData: [eps dataUsingEncoding:NSASCIIStringEncoding]]; - } - - return YES; -} - -- (NSGraphicsContext*)createContext -{ - NSMutableDictionary *info; - - if (_context) - return _context; - - info = [_printInfo dictionary]; - - [info setObject: _path forKey: @"NSOutputFile"]; - [info setObject: NSGraphicsContextPSFormat - forKey: NSGraphicsContextRepresentationFormatAttributeName]; - _context = RETAIN([NSGraphicsContext graphicsContextWithAttributes: info]); - return _context; -} - -@end - -@implementation GSPDFPrintOperation - -- (id) initPDFOperationWithView:(NSView *)aView - insideRect:(NSRect)rect - toData:(NSMutableData *)data - printInfo:(NSPrintInfo*)aPrintInfo -{ - self = [self initWithView: aView - insideRect: rect - toData: data - printInfo: aPrintInfo]; - _pathSet = YES; /* Use the default temp path */ - return self; -} - -- (id) initPDFOperationWithView:(NSView *)aView - insideRect:(NSRect)rect - toPath:(NSString *)path - printInfo:(NSPrintInfo*)aPrintInfo -{ - NSMutableData *data = [NSMutableData data]; - - self = [self initPDFOperationWithView: aView - insideRect: rect - toData: data - printInfo: aPrintInfo]; - - ASSIGN(_path, path); - _pathSet = YES; - - return self; -} - -- (NSGraphicsContext*)createContext -{ - // FIXME - return nil; -} - -- (void) _print -{ - [_view displayRectIgnoringOpacity: _rect]; -} - -- (BOOL)deliverResult -{ - if (_data != nil && _path != nil && [_data length]) - return [_data writeToFile: _path atomically: NO]; - // FIXME Until we can create PDF we shoud convert the file with GhostScript - - return YES; -} - -@end diff --git a/Source/NSPrintPanel.m b/Source/NSPrintPanel.m index 4806ebb80..bce084d90 100644 --- a/Source/NSPrintPanel.m +++ b/Source/NSPrintPanel.m @@ -2,10 +2,13 @@ Standard panel for querying user about printing. - Copyright (C) 2001 Free Software Foundation, Inc. + Copyright (C) 2001,2004 Free Software Foundation, Inc. Written By: Adam Fedor Date: Oct 2001 + Modified for Printing Backend Support + Author: Chad Hardin + Date: June 2004 This file is part of the GNUstep GUI Library. @@ -42,6 +45,7 @@ #include "AppKit/NSSavePanel.h" #include "AppKit/NSView.h" #include "GSGuiPrivate.h" +#include "GNUstepGUI/GSPrinting.h" static NSPrintPanel *shared_instance; @@ -71,6 +75,22 @@ static NSPrintPanel *shared_instance; // // Class Methods // +/** Load the appropriate bundle for the PrintPanel + and alloc the class from that in our place + (eg: GSLPRPrintPanel, GSCUPSPrintPanel). +*/ ++ (id) allocWithZone: (NSZone*) zone +{ + Class principalClass; + + principalClass = [[GSPrinting printingBundle] principalClass]; + + if( principalClass == nil ) + return nil; + + return [[principalClass printPanelClass] allocWithZone: zone]; +} + /** Creates and returns a shared instance of the NSPrintPanel panel. */ + (NSPrintPanel *)printPanel diff --git a/Source/NSPrinter.m b/Source/NSPrinter.m index 220a8896f..5d0799200 100644 --- a/Source/NSPrinter.m +++ b/Source/NSPrinter.m @@ -2,10 +2,13 @@ Class representing a printer's or printer model's capabilities. - Copyright (C) 1996, 1997 Free Software Foundation, Inc. + Copyright (C) 1996, 1997, 2004 Free Software Foundation, Inc. Authors: Simon Frankau Date: June 1997 + Modified for Printing Backend Support + Author: Chad Hardin + Date: June 2004 This file is part of the GNUstep GUI Library. @@ -51,195 +54,13 @@ #include #include #include +#include #include "AppKit/AppKitExceptions.h" #include "AppKit/NSGraphics.h" - #include "AppKit/NSPrinter.h" - -// Define size used for the name and type maps - just use a small table -#define NAMEMAPSIZE 0 -#define TYPEMAPSIZE 0 - -// The maximum level of nesting of *Include directives -#define MAX_PPD_INCLUDES 4 - -// A macro to skip whitespace over lines -#define skipSpace(x) [x scanCharactersFromSet:\ - [NSCharacterSet whitespaceAndNewlineCharacterSet]\ - intoString:NULL] - -static NSString *NSPrinter_PATH = @"PostScript/PPD"; -static NSString *NSPrinter_INDEXFILE = @"Printers"; - -// -// Class variables: -// - -// Maps holding NSPrinters with the types of printers, and the real printers -static NSMapTable *typeMap = NULL; -static NSMapTable *nameMap = NULL; -// Dictionary of real printers, from which NSPrinters can be made -static NSDictionary *nameDict = nil; -// An array to cache the available printer types -static NSArray *printerTypesAvailable = nil; - -// -// Class variables used during scanning: -// - -// Character sets used in scanning. -static NSCharacterSet *newlineSet = nil; -static NSCharacterSet *keyEndSet = nil; -static NSCharacterSet *optKeyEndSet = nil; -static NSCharacterSet *valueEndSet = nil; -// Array of Repeated Keywords (Appendix B of the PostScript Printer -// Description File Format Specification). -static NSArray *repKeys = nil; -// Array to collect the values of symbol values in. -static NSMutableDictionary *PPDSymbolValues; -// File name of the file being processed -static NSString *PPDFileName; - -#ifndef LIB_FOUNDATION_LIBRARY - -static void __NSRetainNothing(void *table, const void *anObject) -{ -} - -static void __NSReleaseNothing(void *table, void *anObject) -{ -} - -static NSString* __NSDescribeObjects(void *table, const void *anObject) -{ - return [(NSObject*)anObject description]; -} - -static const NSMapTableValueCallBacks NSNonRetainedObjectMapValueCallBacks = { - (void (*)(NSMapTable *, const void *))__NSRetainNothing, - (void (*)(NSMapTable *, void *))__NSReleaseNothing, - (NSString *(*)(NSMapTable *, const void *))__NSDescribeObjects -}; - -#endif /* LIB_FOUNDATION_LIBRARY */ +#include "GNUstepGUI/GSPrinting.h" -// Convert a character to a value between 0 and 15 -static int gethex(unichar character) -{ - switch (character) - { - case '0': return 0; - case '1': return 1; - case '2': return 2; - case '3': return 3; - case '4': return 4; - case '5': return 5; - case '6': return 6; - case '7': return 7; - case '8': return 8; - case '9': return 9; - case 'A': return 10; - case 'B': return 11; - case 'C': return 12; - case 'D': return 13; - case 'E': return 14; - case 'F': return 15; - case 'a': return 10; - case 'b': return 11; - case 'c': return 12; - case 'd': return 13; - case 'e': return 14; - case 'f': return 15; - } - [NSException - raise:NSPPDParseException - format:@"Badly formatted hexadeximal substring in PPD printer file."]; - // NOT REACHED - return 0; /* Quiet compiler warnings */ -} - -// Function to convert hexadecimal substrings -static NSString *interpretQuotedValue(NSString *qString) -{ - NSScanner *scanner; - NSCharacterSet *emptySet; - NSString *value = nil; - NSString *part; - int stringLength; - int location; - NSRange range; - - // Don't bother unless there's something to convert - range = [qString rangeOfString:@"<"]; - if(!range.length) - return qString; - - scanner = [NSScanner scannerWithString:qString]; - emptySet = [NSCharacterSet characterSetWithCharactersInString:@""]; - [scanner setCharactersToBeSkipped:emptySet]; - if(![scanner scanUpToString:@"<" intoString:&value]) - value = [NSString string]; - stringLength = [qString length]; - - while (![scanner isAtEnd]) { - [scanner scanString:@"<" intoString:NULL]; - skipSpace(scanner); - while (![scanner scanString:@">" intoString:NULL]) - { - location = [scanner scanLocation]; - if (location+2 > stringLength) - { - [NSException - raise:NSPPDParseException - format:@"Badly formatted hexadecimal substring in PPD printer file."]; - // NOT REACHED - } - value = [value stringByAppendingFormat:@"%c", - 16 * gethex([qString characterAtIndex:location]) - + gethex([qString characterAtIndex:location+1])]; - [scanner setScanLocation:location+2]; - skipSpace(scanner); - } - if([scanner scanUpToString:@"<" intoString:&part]) - { - value = [value stringByAppendingString:part]; - } - } - return value; -} - -static NSString *getFile(NSString *name, NSString *type) -{ - return [NSBundle pathForLibraryResource: name - ofType: type - inDirectory: NSPrinter_PATH]; -} - - -@interface NSPrinter (private) -+ allocMaps; -- initWithPPD:(NSString *)PPDstring - withName:(NSString *)name - withType:(NSString *)type - withHost:(NSString *)host - withNote:(NSString *)note - fromFile:(NSString *)file - isReal:(BOOL)real; -- loadPPD:(NSString *)PPDstring -inclusionNum:(int)includeNum; -- addPPDKeyword:(NSString *)mainKeyword - withScanner:(NSScanner *)PPDdata; -- addPPDUIConstraint:(NSScanner *)constraint; -- addPPDOrderDependency:(NSScanner *)dependency; -- addValue:(NSString *)value - andValueTranslation:(NSString *)valueTranslation -andOptionTranslation:(NSString *)optionTranslation - forKey:(NSString *)key; -- addString:(NSString *)string - forKey:(NSString *)key - inTable:(NSMutableDictionary *)table; -@end @implementation NSPrinter @@ -255,131 +76,108 @@ andOptionTranslation:(NSString *)optionTranslation } } +/** Load the appropriate bundle for the Printer + (eg: GSLPRPrinter, GSCUPSPrinter). +*/ ++ (id) allocWithZone: (NSZone*) zone +{ + Class principalClass; + + principalClass = [[GSPrinting printingBundle] principalClass]; + + if( principalClass == nil ) + return nil; + + return [[principalClass printerClass] allocWithZone: zone]; +} + + // // Finding an NSPrinter // + (NSPrinter *)printerWithName:(NSString *)name { - NSString *path; - NSArray *printerInfo; - NSPrinter *printer; - /* Contents of printerInfo array: - * [0]: NSString of the printer's type - * [1]: NSString of the printer's host - * [2]: NSString of the printer's note - */ - // Make sure the printer names dictionary etc. exists - if (!nameMap) - [self allocMaps]; - printer = NSMapGet(nameMap, name); - // If the NSPrinter object for the printer already exists, return it - if (printer) - return printer; - // Otherwise, try to find the information in the nameDict - printerInfo = [nameDict objectForKey:name]; - // Make sure you can find the printer name in the dictionary - if (!printerInfo) - { - [NSException raise:NSGenericException - format:@"Could not find printer named %@", name]; - // NOT REACHED - } - // Create it - path = getFile([printerInfo objectAtIndex:0], @"ppd"); - // If not found - if (path == nil || [path length] == 0) - { - [NSException raise:NSGenericException - format:@"Could not find PPD file %@.ppd", - [printerInfo objectAtIndex:0]]; - // NOT REACHED - } - printer = AUTORELEASE([[self alloc] - initWithPPD:[NSString stringWithContentsOfFile:path] - withName:name - withType:[printerInfo objectAtIndex:0] - withHost:[printerInfo objectAtIndex:1] - withNote:[printerInfo objectAtIndex:2] - fromFile:[printerInfo objectAtIndex:0] - isReal:YES]); - // Once created, put it in the map table - NSMapInsert(nameMap, name, printer); - return printer; + Class principalClass; + + principalClass = [[GSPrinting printingBundle] principalClass]; + + if( principalClass == nil ) + return nil; + + return [[principalClass printerClass] printerWithName: name]; } +// +// This now different than the OpenStep spec and instead +// follows the more useful implementation Apple choosed. In +// OpenStep, this method would read a PPD and return a NSPrinter +// based upon values from that PPD, regardless if that printer +// was actually avaiable for use or not. On the contrary, Apple's +// implementation looks +// at all avaiable printers and returns one that has the same +// type. The reason for this is because they use CUPS. CUPS +// does not work by maintaining a repository of PPDs. Instead, +// the CUPS server trasnmits PPDs as they are needed, and only +// for actual real printers. Since we cannot know how the backend +// bundles will be handling their PPDs, or if they will even be using +// PPDs for that matter, (a Win32 printing backend, for example), +// I've choosen to go with Apple's implementation. Really, I see +// little use in creating a NSPrinter for a printer that is not +// available for use in the first place, I am open for commments +// on this, of course. + (NSPrinter *)printerWithType:(NSString *)type { - NSString *path; - NSPrinter *printer = nil; - // Make sure the printer types dictionary exists - if (!typeMap) - [self allocMaps]; - else - printer = NSMapGet(typeMap, type); - // If the NSPrinter is already created, use it - if (printer) - return printer; - path = getFile(type, @"ppd"); - // If not found - if (path == nil || [path length] == 0) + NSEnumerator *printerNamesEnum; + NSString *printerName; + + printerNamesEnum = [[self printerNames] objectEnumerator]; + + while( (printerName = [printerNamesEnum nextObject]) ) { - [NSException raise:NSGenericException - format:@"Could not find PPD file %@.ppd", type]; - // NOT REACHED + NSPrinter *printer; + + printer = [self printerWithName: printerName]; + + if( [[printer type] isEqualToString: type] ) + { + return printer; + } } - printer = AUTORELEASE([[self alloc] - initWithPPD:[NSString stringWithContentsOfFile:path] - withName:type withType:type withHost:@"" withNote:@"" - fromFile:path isReal:NO]); - // Once created, put it in the hash table - NSMapInsert(typeMap, type, printer); - return printer; + return nil; } + (NSArray *)printerNames { - if(!nameDict) - [NSPrinter allocMaps]; - return [nameDict allKeys]; + Class principalClass; + + principalClass = [[GSPrinting printingBundle] principalClass]; + + if( principalClass == nil ) + return nil; + + return [[principalClass printerClass] printerNames]; } +// See note at +(NSPrinter *)printerWithType:(NSString *)type + (NSArray *)printerTypes { - NSEnumerator *pathEnum; - NSBundle *lbdle; - NSString *lpath; - NSArray *ppdpaths; - NSMutableArray *printers; - NSString *path; - NSAutoreleasePool *subpool; // There's a lot of temp strings used... - int i, max; - - if (printerTypesAvailable) - return printerTypesAvailable; - - printers = RETAIN([NSMutableArray array]); - subpool = [[NSAutoreleasePool alloc] init]; - - pathEnum = [NSSearchPathForDirectoriesInDomains(GSLibrariesDirectory, - NSAllDomainsMask, YES) objectEnumerator]; - while ((lpath = [pathEnum nextObject])) + NSMutableSet *printerTypes; + NSEnumerator *printerNamesEnum; + NSString *printerName; + NSPrinter *printer; + + printerTypes = [NSMutableSet setWithCapacity:1]; + + printerNamesEnum = [[self printerNames] objectEnumerator]; + + while( (printerName = [printerNamesEnum nextObject]) ) { - lbdle = [NSBundle bundleWithPath: lpath]; - ppdpaths = [lbdle pathsForResourcesOfType:@"ppd" - inDirectory:NSPrinter_PATH]; - - // FIXME - should get name from contents of PPD, not filename - max = [ppdpaths count]; - for (i = 0; i < max; i++) - { - path = [[ppdpaths objectAtIndex:i] lastPathComponent]; - [printers addObject:[path substringToIndex:[path length]-4]]; - } + printer = [self printerWithName: printerName]; + + [printerTypes addObject: [printer type]]; } - RELEASE(subpool); - - printerTypesAvailable = printers; - return printers; + + return [printerTypes allObjects]; } // @@ -390,11 +188,6 @@ andOptionTranslation:(NSString *)optionTranslation // - (void)dealloc { - // Remove object from the appropriate table - if (_isRealPrinter) - NSMapRemove(nameMap, _printerName); - else - NSMapRemove(typeMap, _printerType); RELEASE(_printerHost); RELEASE(_printerName); RELEASE(_printerNote); @@ -830,7 +623,6 @@ andOptionTranslation:(NSString *)optionTranslation [aCoder encodeValueOfObjCType: @encode(int) at: &_cacheAcceptsBinary]; [aCoder encodeValueOfObjCType: @encode(int) at: &_cacheOutputOrder]; - [aCoder encodeValueOfObjCType: @encode(BOOL) at: &_isRealPrinter]; [aCoder encodeObject: _PPD]; [aCoder encodeObject: _PPDOptionTranslation]; @@ -850,7 +642,6 @@ andOptionTranslation:(NSString *)optionTranslation [aDecoder decodeValueOfObjCType: @encode(int) at: &_cacheAcceptsBinary]; [aDecoder decodeValueOfObjCType: @encode(int) at: &_cacheOutputOrder]; - [aDecoder decodeValueOfObjCType: @encode(BOOL) at: &_isRealPrinter]; [aDecoder decodeValueOfObjCType: @encode(id) at: &_PPD]; [aDecoder decodeValueOfObjCType: @encode(id) at: &_PPDOptionTranslation]; @@ -861,467 +652,43 @@ andOptionTranslation:(NSString *)optionTranslation return self; } -// -// Private Methods -// +@end + + + +/// +///Private implementation of routines that will be usefull +///for the printing backend bundles that subclass us. +/// +@implementation NSPrinter (Private) // -// Allocate the printer name to PPD filename index dictionary +// Initialisation method used by backend bundles // -+ allocMaps +-(id) initWithName:(NSString *)name + withType:(NSString *)type + withHost:(NSString *)host + withNote:(NSString *)note { - NSString *path; - - // Allocate name and type maps - typeMap = NSCreateMapTable(NSObjectMapKeyCallBacks, - NSNonRetainedObjectMapValueCallBacks, - TYPEMAPSIZE); - nameMap = NSCreateMapTable(NSObjectMapKeyCallBacks, - NSNonRetainedObjectMapValueCallBacks, - NAMEMAPSIZE); - - // Load the index file - path = [NSBundle pathForLibraryResource: NSPrinter_INDEXFILE - ofType: nil - inDirectory: @"PostScript"]; - // If not found - if (path == nil || [path length] == 0) - { - NSLog(@"Could not find index of printers, file %@", NSPrinter_INDEXFILE); - nameDict = [NSDictionary dictionaryWithObject: - [NSArray arrayWithObjects: @"Apple_LaserWriter_II_NTX", - @"localhost", @"A Note", nil] - forKey: @"Unknown"]; - } - else - nameDict = [NSDictionary dictionaryWithContentsOfFile:path]; - RETAIN(nameDict); - return self; -} - -// -// Initialisation method -// -// To keep loading of PPDs relatively fast, not much checking is done on it. -- initWithPPD:(NSString *)PPDstring - withName:(NSString *)name - withType:(NSString *)type - withHost:(NSString *)host - withNote:(NSString *)note - fromFile:(NSString *)file - isReal:(BOOL)real -{ - NSAutoreleasePool *subpool; - NSEnumerator *objEnum; - NSMutableArray *valArray; - + self = [super init]; + // Initialise instance variables - _printerName = RETAIN(name); - _printerType = RETAIN(type); - _printerHost = RETAIN(host); - _printerNote = RETAIN(note); + ASSIGN(_printerName, name); + ASSIGN(_printerType, type); + ASSIGN(_printerHost, host); + ASSIGN(_printerNote, note); _cacheAcceptsBinary = _cacheOutputOrder = -1; - _isRealPrinter = real; _PPD = RETAIN([NSMutableDictionary dictionary]); _PPDOptionTranslation = RETAIN([NSMutableDictionary dictionary]); _PPDArgumentTranslation = RETAIN([NSMutableDictionary dictionary]); _PPDOrderDependency = RETAIN([NSMutableDictionary dictionary]); _PPDUIConstraints = RETAIN([NSMutableDictionary dictionary]); - // Create a temporary autorelease pool, as many temporary objects are used - subpool = [[NSAutoreleasePool alloc] init]; - // Create character sets used during scanning - newlineSet = [NSCharacterSet characterSetWithCharactersInString:@"\n\r"]; - keyEndSet = [NSCharacterSet characterSetWithCharactersInString:@"\n\r\t: "]; - optKeyEndSet = [NSCharacterSet characterSetWithCharactersInString:@"\n\r:/"]; - valueEndSet = [NSCharacterSet characterSetWithCharactersInString:@"\n\r/"]; - // Allowed repeated keys, used during scanning. - repKeys = [NSArray arrayWithObjects:@"Emulators", - @"Extensions", - @"FaxSupport", - //@"Include", (handled separately) - @"Message", - @"PrinterError", - @"Product", - @"Protocols", - @"PSVersion", - @"Source", - @"Status", - //@"UIConstraints", (handled separately) - // Even though this is not mentioned in the list of repeated keywords, - // it's often repeated anyway, so I'm putting it here. - @"InkName", - nil]; - // Set the file name to use - PPDFileName = file; - // NB: There are some structure keywords (such as OpenUI/CloseUI) that may - // be repeated, but as yet are not used. Since they are structure keywords, - // they'll probably need special processing anyway, and so aren't - // added to this list. - // Create dictionary for temporary storage of symbol values - PPDSymbolValues = [NSMutableDictionary dictionary]; - // And scan the PPD itself - [self loadPPD:PPDstring inclusionNum:0]; - // Search the PPD dictionary for symbolvalues, and substitute them. - objEnum = [_PPD objectEnumerator]; - while ((valArray = [objEnum nextObject])) - { - NSString *oldValue; - NSString *newValue; - int i, max; - max = [valArray count]; - for(i=0 ; i < max ; i++ ) - { - oldValue = [valArray objectAtIndex:i]; - if ([oldValue isKindOfClass:[NSString class]] - && ![oldValue isEqual:@""] - && [[oldValue substringToIndex:1] isEqual:@"^"]) - { - newValue = [PPDSymbolValues - objectForKey:[oldValue substringFromIndex:1]]; - if (!newValue) - { - [NSException - raise:NSPPDParseException - format:@"Unknown symbol value, ^%@ in PPD file %@.ppd", - oldValue, PPDFileName]; - // NOT REACHED - } - [valArray replaceObjectAtIndex:i withObject:newValue]; - } - } - } - -#if 0 - // DISABLED: Though the following keywords *should* be present, there seems - // to be few problems is they are omitted. Many of the .ppd files I have - // don't have *LanguageEncoding, for example. - - // Make sure all the required keys are present - objEnum = [[NSArray arrayWithObjects:@"NickName", - @"ModelName", - @"PCFileName", - @"Product", - @"PSVersion", - @"FileVersion", - @"FormatVersion", - @"LanguageEncoding", - @"LanguageVersion", - @"PageSize", - @"PageRegion", - @"ImageableArea", - @"PaperDimension", - @"PPD-Adobe", - nil] objectEnumerator]; - - while (checkVal = [objEnum nextObject]) - { - if (![self isKey:checkVal inTable:@"PPD"]) - { - [NSException - raise:NSPPDParseException - format:@"Required keyword *%@ not found in PPD file %@.ppd", - checkVal, PPDFileName]; - // NOT REACHED - } - } -#endif - - // Release the local autoreleasePool - RELEASE(subpool); + return self; } -- loadPPD:(NSString *)PPDstring -inclusionNum:(int)includeNum -{ - NSScanner *PPDdata; - NSString *keyword; - // Set up the scanner - Appending a newline means that it should be - // able to process the last line correctly - PPDdata = [NSScanner scannerWithString: - [PPDstring stringByAppendingString:@"\n"]]; - [PPDdata setCharactersToBeSkipped:[NSCharacterSet whitespaceCharacterSet]]; - // Main processing starts here... - while (1) // Check it is not at end only after skipping the blanks - { - // Get to the start of a new keyword, skipping blank lines - skipSpace(PPDdata); - if ([PPDdata isAtEnd]) - break; - // All new entries should starts '*' - if (![PPDdata scanString:@"*" intoString:NULL]) - { - [NSException raise:NSPPDParseException - format:@"Line not starting * in PPD file %@.ppd", - PPDFileName]; - // NOT REACHED - } - // Skip lines starting '*%', '*End', '*SymbolLength', or '*SymbolEnd' - if ([PPDdata scanString:@"%" intoString:NULL] - || [PPDdata scanString:@"End" intoString:NULL] - || [PPDdata scanString:@"SymbolLength" intoString:NULL] - || [PPDdata scanString:@"SymbolEnd" intoString:NULL]) - { - [PPDdata scanUpToCharactersFromSet:newlineSet intoString:NULL]; - continue; - } - // Read main keyword, up to a colon, space or newline - [PPDdata scanUpToCharactersFromSet:keyEndSet intoString:&keyword]; - // Loop if there is no value section - if ([PPDdata scanCharactersFromSet:newlineSet intoString:NULL]) - continue; - // Add the line to the relevant table - if ([keyword isEqual:@"OrderDependency"]) - [self addPPDOrderDependency:PPDdata]; - else if ([keyword isEqual:@"UIConstraints"]) - [self addPPDUIConstraint:PPDdata]; - else if ([keyword isEqual:@"Include"]) - { - NSString *fileName; - NSString *path; - [PPDdata scanString:@":" intoString:NULL]; - // Find the filename between two "s - [PPDdata scanString:@"\"" intoString:NULL]; - [PPDdata scanUpToString:@"\"" intoString:&fileName]; - [PPDdata scanString:@"\"" intoString:NULL]; - // Load the file - path = getFile(fileName, nil); - // If not found - if (path == nil || [path length] == 0) - { - [NSException raise:NSPPDIncludeNotFoundException - format:@"Could not find included PPD file %@", - fileName]; - // NOT REACHED - } - includeNum++; - if (includeNum > MAX_PPD_INCLUDES) - { - [NSException raise:NSPPDIncludeStackOverflowException - format:@"Too many *Includes in PPD"]; - // NOT REACHED - } - [self loadPPD:[NSString stringWithContentsOfFile:path] - inclusionNum:includeNum]; - } - else if ([keyword isEqual:@"SymbolValue"]) - { - NSString *symbolName; - NSString *symbolVal; - if (![PPDdata scanString:@"^" intoString:NULL]) - { - [NSException - raise:NSPPDParseException - format:@"Badly formatted *SymbolValue in PPD file %@.ppd", - PPDFileName]; - // NOT REACHED - } - [PPDdata scanUpToString:@":" intoString:&symbolName]; - [PPDdata scanString:@":" intoString:NULL]; - [PPDdata scanString:@"\"" intoString:NULL]; - [PPDdata scanUpToString:@"\"" intoString:&symbolVal]; - if (!symbolVal) - symbolVal = @""; - [PPDdata scanString:@"\"" intoString:NULL]; - [PPDSymbolValues setObject:symbolVal forKey:symbolName]; - } - else - [self addPPDKeyword:keyword withScanner:PPDdata]; - } - return self; -} -- addPPDKeyword:(NSString *)mainKeyword - withScanner:(NSScanner *)PPDdata -{ - NSString *optionKeyword = nil; - NSString *optionTranslation = nil; - NSString *value = nil; - NSString *valueTranslation = nil; - // Scan off any optionKeyword - [PPDdata scanUpToCharactersFromSet:optKeyEndSet intoString:&optionKeyword]; - if ([PPDdata scanCharactersFromSet:newlineSet intoString:NULL]) - { - [NSException raise:NSPPDParseException - format:@"Keyword has optional keyword but no value in PPD file %@.ppd", - PPDFileName]; - // NOT REACHED - } - if ([PPDdata scanString:@"/" intoString:NULL]) - { - // Option keyword translation exists - scan it - [PPDdata scanUpToString:@":" intoString:&optionTranslation]; - } - [PPDdata scanString:@":" intoString:NULL]; - // Read the value part - // Values starting with a " are read until the second ", ignoring \n etc. - if ([PPDdata scanString:@"\"" intoString:NULL]) - { - [PPDdata scanUpToString:@"\"" intoString:&value]; - if (!value) - value = @""; - [PPDdata scanString:@"\"" intoString:NULL]; - // It is a QuotedValue if it's in quotes, and there is no option - // key, or the main key is a *JCL keyword - if (!optionKeyword || [[mainKeyword substringToIndex:3] - isEqualToString:@"JCL"]) - value = interpretQuotedValue(value); - } - else - { - // Otherwise, scan up to the end of line or '/' - [PPDdata scanUpToCharactersFromSet:valueEndSet intoString:&value]; - } - // If there is a value translation, scan it - if ([PPDdata scanString:@"/" intoString:NULL]) - { - [PPDdata scanUpToCharactersFromSet:newlineSet - intoString:&valueTranslation]; - } - // The translations also have to have any hex substrings interpreted - if (optionTranslation) - optionTranslation = interpretQuotedValue(optionTranslation); - if (valueTranslation) - valueTranslation = interpretQuotedValue(valueTranslation); - // The keyword (or keyword/option pair, if there's a option), should only - // only have one value, unless it's one of the optionless keywords which - // allow multiple instances. - // If a keyword is read twice, 'first instance is correct', according to - // the standard. - // Finally, add the strings to the tables - if (optionKeyword) - { - NSString *mainAndOptionKeyword=[mainKeyword - stringByAppendingFormat:@"/%@", - optionKeyword]; - if ([self isKey:mainAndOptionKeyword inTable:@"PPD"]) - return self; - [self addValue:value - andValueTranslation:valueTranslation - andOptionTranslation:optionTranslation - forKey:mainAndOptionKeyword]; - // Deal with the oddities of stringForKey:inTable: - // If this method is used to find a keyword with options, using - // just the keyword it should return an empty string - // stringListForKey:inTable:, however, should return the list of - // option keywords. - // This is done by making the first item in the array an empty - // string, which will be skipped by stringListForKey:, if necessary - if (![_PPD objectForKey:mainKeyword]) - { - [self addString:@"" forKey:mainKeyword inTable:_PPD]; - [self addString:@"" forKey:mainKeyword inTable:_PPDOptionTranslation]; - [self addString:@"" forKey:mainKeyword - inTable:_PPDArgumentTranslation]; - } - [self addValue:optionKeyword - andValueTranslation:optionKeyword - andOptionTranslation:optionKeyword - forKey:mainKeyword]; - } - else - { - if ([self isKey:mainKeyword inTable:@"PPD"] && - ![repKeys containsObject:mainKeyword]) - return self; - [self addValue:value - andValueTranslation:valueTranslation - andOptionTranslation:optionTranslation - forKey:mainKeyword]; - } - return self; -} - -- addPPDUIConstraint:(NSScanner *)constraint -{ - NSString *mainKey1 = nil; - NSString *optionKey1 = nil; - NSString *mainKey2 = nil; - NSString *optionKey2 = nil; - // UIConstraint should have no option keyword - if (![constraint scanString:@":" intoString:NULL]) - { - [NSException raise:NSPPDParseException - format:@"UIConstraints has option keyword in PPDFileName %@.ppd", - PPDFileName]; - // NOT REACHED - } - // Skip the '*' - [constraint scanString:@"*" intoString:NULL]; - // Scan the bits. Stuff not starting with * must be an optionKeyword - [constraint scanUpToCharactersFromSet:[NSCharacterSet whitespaceCharacterSet] - intoString:&mainKey1]; - if (![constraint scanString:@"*" intoString:NULL]) - { - [constraint scanUpToCharactersFromSet:[NSCharacterSet - whitespaceCharacterSet] - intoString:&optionKey1]; - [constraint scanString:@"*" intoString:NULL]; - } - [constraint scanUpToCharactersFromSet: - [NSCharacterSet whitespaceAndNewlineCharacterSet] - intoString:&mainKey2]; - if (![constraint scanCharactersFromSet:newlineSet intoString:NULL]) - { - [constraint scanUpToCharactersFromSet: - [NSCharacterSet whitespaceAndNewlineCharacterSet] - intoString:&optionKey2]; - } - else - { - optionKey2 = @""; - } - // Add to table - if (optionKey1) - mainKey1 = [mainKey1 stringByAppendingFormat:@"/%@", optionKey1]; - [self addString:mainKey2 - forKey:mainKey1 - inTable:_PPDUIConstraints]; - [self addString:optionKey2 - forKey:mainKey1 - inTable:_PPDUIConstraints]; - return self; -} - -- addPPDOrderDependency:(NSScanner *)dependency -{ - NSString *realValue = nil; - NSString *section = nil; - NSString *keyword = nil; - NSString *optionKeyword = nil; - // Order dependency should have no option keyword - if (![dependency scanString:@":" intoString:NULL]) - { - [NSException raise:NSPPDParseException - format:@"OrderDependency has option keyword in PPD file %@.ppd", - PPDFileName]; - // NOT REACHED - } - [dependency scanUpToCharactersFromSet:[NSCharacterSet whitespaceCharacterSet] - intoString:&realValue]; - [dependency scanUpToCharactersFromSet:[NSCharacterSet whitespaceCharacterSet] - intoString:§ion]; - [dependency scanString:@"*" intoString:NULL]; - [dependency scanUpToCharactersFromSet: - [NSCharacterSet whitespaceAndNewlineCharacterSet] - intoString:&keyword]; - if (![dependency scanCharactersFromSet:newlineSet intoString:NULL]) - { - // Optional keyword exists - [dependency scanUpToCharactersFromSet: - [NSCharacterSet whitespaceAndNewlineCharacterSet] - intoString:&optionKeyword]; - } - // Go to next line of PPD file - [dependency scanCharactersFromSet:newlineSet intoString:NULL]; - // Add to table - if (optionKeyword) - keyword = [keyword stringByAppendingFormat:@"/%s", optionKeyword]; - [self addString:realValue forKey:keyword inTable:_PPDOrderDependency]; - [self addString:section forKey:keyword inTable:_PPDOrderDependency]; - return self; -} // // Adds the various values to the relevant tables, for the given key