From f7b0c08caed76819599e50c30f1f48b13fbb9cf6 Mon Sep 17 00:00:00 2001 From: "Ithamar R. Adema" Date: Sun, 11 Apr 2010 22:01:13 +0000 Subject: [PATCH] This modifies the Postscript printer to be able to insert a pipe in between the Postscript generation and the transport addon. The actual command use as pipe is retrieved from the PPD that can be selected at printer creation time. Currently PPD selection is not shown (as the PPD directory is not available) and therefore the pipe will not be inserted. This still needs a bit of TLC, so hope to commit the last changes to fully support this later this week. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@36173 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/libs/print/libprint/PrinterData.h | 9 +- headers/libs/print/libprint/PrinterDriver.h | 1 + .../print/drivers/postscript/FilterIO.cpp | 131 ++++++++++++ .../print/drivers/postscript/FilterIO.h | 40 ++++ src/add-ons/print/drivers/postscript/Jamfile | 4 + .../print/drivers/postscript/PPDParser.cpp | 93 ++++++++ .../print/drivers/postscript/PPDParser.h | 31 +++ src/add-ons/print/drivers/postscript/PS.cpp | 198 +++++++++++++----- src/add-ons/print/drivers/postscript/PS.h | 9 + .../print/drivers/postscript/PSData.cpp | 27 +++ src/add-ons/print/drivers/postscript/PSData.h | 31 +++ .../print/drivers/postscript/PSEntry.cpp | 76 ++++--- .../print/drivers/postscript/SelectPPDDlg.cpp | 190 +++++++++++++++++ .../print/drivers/postscript/SelectPPDDlg.h | 30 +++ src/libs/print/libprint/PrinterData.cpp | 5 +- src/libs/print/libprint/PrinterDriver.cpp | 13 +- 16 files changed, 807 insertions(+), 81 deletions(-) create mode 100644 src/add-ons/print/drivers/postscript/FilterIO.cpp create mode 100644 src/add-ons/print/drivers/postscript/FilterIO.h create mode 100644 src/add-ons/print/drivers/postscript/PPDParser.cpp create mode 100644 src/add-ons/print/drivers/postscript/PPDParser.h create mode 100644 src/add-ons/print/drivers/postscript/PSData.cpp create mode 100644 src/add-ons/print/drivers/postscript/PSData.h create mode 100644 src/add-ons/print/drivers/postscript/SelectPPDDlg.cpp create mode 100644 src/add-ons/print/drivers/postscript/SelectPPDDlg.h diff --git a/headers/libs/print/libprint/PrinterData.h b/headers/libs/print/libprint/PrinterData.h index 4689762f0e..a189ecf66c 100644 --- a/headers/libs/print/libprint/PrinterData.h +++ b/headers/libs/print/libprint/PrinterData.h @@ -20,9 +20,9 @@ class BNode; class PrinterData { public: PrinterData(BNode *node = NULL); - ~PrinterData(); - void load(); - void save(); + virtual ~PrinterData(); + virtual void load(); + virtual void save(); const string &getDriverName() const; const string &getPrinterName() const; @@ -40,14 +40,13 @@ protected: PrinterData(const PrinterData &printer_data); PrinterData &operator = (const PrinterData &printer_data); + BNode *fNode; private: string fDriverName; string fPrinterName; string fComments; string fTransport; int fProtocolClass; - - BNode *fNode; }; inline const string &PrinterData::getDriverName() const diff --git a/headers/libs/print/libprint/PrinterDriver.h b/headers/libs/print/libprint/PrinterDriver.h index 4987ce712b..b0ab3092ff 100644 --- a/headers/libs/print/libprint/PrinterDriver.h +++ b/headers/libs/print/libprint/PrinterDriver.h @@ -26,6 +26,7 @@ public: virtual const char* GetCopyright() const = 0; virtual PrinterCap* InstantiatePrinterCap(PrinterData* printerData) = 0; + virtual PrinterData* InstantiatePrinterData(BNode* node); virtual GraphicsDriver* InstantiateGraphicsDriver(BMessage* settings, PrinterData* printerData, PrinterCap* printerCap) = 0; void InitPrinterDataAndCap(); diff --git a/src/add-ons/print/drivers/postscript/FilterIO.cpp b/src/add-ons/print/drivers/postscript/FilterIO.cpp new file mode 100644 index 0000000000..1f82014c91 --- /dev/null +++ b/src/add-ons/print/drivers/postscript/FilterIO.cpp @@ -0,0 +1,131 @@ +/* +* Copyright 2010, Haiku. All rights reserved. +* Distributed under the terms of the MIT License. +* +* Authors: +* Ithamar R. Adema +*/ + +#include "FilterIO.h" + +#include +#include + +#include +#include +#include + +FilterIO::FilterIO(const BString& cmdline) + : BDataIO() +{ + BString cmd(cmdline); + const char *argv[4]; + + argv[0] = strdup("/bin/sh"); + argv[1] = strdup("-c"); + argv[2] = strdup(cmd.String()); + argv[3] = NULL; + + InitData(3,argv); + + free((void*)argv[0]); + free((void*)argv[1]); + free((void*)argv[2]); +} + + +FilterIO::FilterIO(int argc, const char **argv, const char **envp) + : BDataIO() +{ + InitData(argc,argv,envp); +} + + +status_t +FilterIO::InitData(int argc, const char **argv, const char **envp) +{ + fStdIn = + fStdOut = + fStdErr = -1; + fInitErr = B_OK; + + fThreadId = PipeCommand(argc, argv, fStdIn, fStdOut, fStdErr, envp); + if (fThreadId < 0) + fInitErr = fThreadId; + + // lower the command priority since it is a background task. + set_thread_priority(fThreadId, B_LOW_PRIORITY); + resume_thread(fThreadId); + + return fInitErr; +} + + +FilterIO::~FilterIO() +{ + ::close(fStdIn); + ::close(fStdOut); + ::close(fStdErr); +} + + +ssize_t +FilterIO::Read(void *buffer, size_t size) +{ + return ::read(fStdOut, buffer, size); +} + + +ssize_t +FilterIO::Write(const void *buffer, size_t size) +{ + return ::write(fStdIn, buffer, size); +} + + +thread_id +FilterIO::PipeCommand(int argc, const char **argv, int &in, int &out, int &err, const char **envp) +{ + // This function written by Peter Folk + // and published in the BeDevTalk FAQ + // http://www.abisoft.com/faq/BeDevTalk_FAQ.html#FAQ-209 + + if (!envp) + envp = (const char**)environ; + + // Save current FDs + int old_in = dup(0); + int old_out = dup(1); + int old_err = dup(2); + + int filedes[2]; + + /* Create new pipe FDs as stdin, stdout, stderr */ + pipe(filedes); dup2(filedes[0], 0); close(filedes[0]); + in = filedes[1]; // Write to in, appears on cmd's stdin + pipe(filedes); dup2(filedes[1], 1); close(filedes[1]); + out = filedes[0]; // Read from out, taken from cmd's stdout + pipe(filedes); dup2(filedes[1], 2); close(filedes[1]); + err = filedes[0]; // Read from err, taken from cmd's stderr + + // "load" command. + thread_id ret = load_image(argc, argv, envp); + if (ret < B_OK) + goto cleanup; + + // thread ret is now suspended. + + setpgid(ret, ret); + +cleanup: + // Restore old FDs + close(0); dup(old_in); close(old_in); + close(1); dup(old_out); close(old_out); + close(2); dup(old_err); close(old_err); + + /* Theoretically I should do loads of error checking, but + the calls aren't very likely to fail, and that would + muddy up the example quite a bit. YMMV. */ + + return ret; +} diff --git a/src/add-ons/print/drivers/postscript/FilterIO.h b/src/add-ons/print/drivers/postscript/FilterIO.h new file mode 100644 index 0000000000..2d784337d6 --- /dev/null +++ b/src/add-ons/print/drivers/postscript/FilterIO.h @@ -0,0 +1,40 @@ +/* +* Copyright 2010, Haiku. All rights reserved. +* Distributed under the terms of the MIT License. +* +* Authors: +* Ithamar R. Adema +*/ + +#ifndef FILTERIO_H +#define FILTERIO_H + +#include +#include + +class BString; + +class FilterIO : public BDataIO +{ +public: + FilterIO(int argc, const char **argv, const char **envp = NULL); + FilterIO(const BString& cmdline); + ~FilterIO(); + + status_t InitCheck() const + { + return fInitErr; + } + + ssize_t Read(void *buffer, size_t size); + ssize_t Write(const void *buffer, size_t size); +private: + int fStdIn, fStdOut, fStdErr; + thread_id fThreadId; + status_t fInitErr; + + status_t InitData(int argc, const char **argv, const char **envp = NULL); + thread_id PipeCommand(int argc, const char **argv, int &in, int &out, int &err, const char **envp = NULL); +}; + +#endif /* FILTERIO_H */ diff --git a/src/add-ons/print/drivers/postscript/Jamfile b/src/add-ons/print/drivers/postscript/Jamfile index 1b121cf620..1292904d72 100644 --- a/src/add-ons/print/drivers/postscript/Jamfile +++ b/src/add-ons/print/drivers/postscript/Jamfile @@ -10,6 +10,10 @@ Addon PS\ Compatible : PSEntry.cpp PS.cpp PSCap.cpp + PSData.cpp + SelectPPDDlg.cpp + PPDParser.cpp + FilterIO.cpp : be libprint.a $(TARGET_LIBSTDC++) ; diff --git a/src/add-ons/print/drivers/postscript/PPDParser.cpp b/src/add-ons/print/drivers/postscript/PPDParser.cpp new file mode 100644 index 0000000000..716176d013 --- /dev/null +++ b/src/add-ons/print/drivers/postscript/PPDParser.cpp @@ -0,0 +1,93 @@ +/* +* Copyright 2010, Haiku. All rights reserved. +* Distributed under the terms of the MIT License. +* +* Authors: +* Ithamar R. Adema +*/ + +#include "PPDParser.h" + +#include +#include + + +PPDParser::PPDParser(BFile& file) +{ + InitData(file); +} + + +PPDParser::PPDParser(const BDirectory& dir, const char *fname) +{ + BFile file(&dir,fname, B_READ_ONLY); + InitData(file); +} + + +PPDParser::PPDParser(const BPath& path) +{ + BFile file(path.Path(), B_READ_ONLY); + InitData(file); +} + + +status_t +PPDParser::InitData(BFile& file) +{ + // Check if file exists... + if ((fInitErr=file.InitCheck()) != B_OK) + return fInitErr; + + // Read entire file into BString + ssize_t len; + char buffer[1025]; + while ((len=file.Read(buffer,sizeof(buffer)-1)) > 0) { + buffer[len] = '\0'; + fContent << buffer; + } + + // Convert DOS/Windows newlines to UNIX ones + fContent.ReplaceAll("\r\n", "\n"); + // Handle line continuation + fContent.ReplaceAll("&&\n", ""); + // Make sure file ends with newline + fContent << '\n'; + + return B_OK; +} + + +BString +PPDParser::GetParameter(const BString& param) +{ + BString result, line; + int32 pos = 0, next; + BString pattern; + + pattern << "*" << param << ":"; + + while ((next=fContent.FindFirst('\n', pos)) > 0) { + // Grab line (without newline) + fContent.CopyInto(line, pos, next-pos); + // Found our parameter? + if (line.Compare(pattern,pattern.Length()) == 0) { + // Copy result + line.CopyInto(result, pattern.Length(), line.Length() - pattern.Length()).Trim(); + // If result is quoted, remove quotes + if (result[0] == '"') { + result.Truncate(result.Length() -1); + result.Remove(0,1); + } + break; + } + pos = next +1; + } + + return result; +} + + +PPDParser::~PPDParser() +{ +} diff --git a/src/add-ons/print/drivers/postscript/PPDParser.h b/src/add-ons/print/drivers/postscript/PPDParser.h new file mode 100644 index 0000000000..34be281d31 --- /dev/null +++ b/src/add-ons/print/drivers/postscript/PPDParser.h @@ -0,0 +1,31 @@ +#ifndef PPDPARSER_H +#define PPDPARSER_H + +#include + +class BPath; +class BFile; +class BDirectory; + +class PPDParser +{ +public: + PPDParser(const BDirectory& dir, const char *fname); + PPDParser(const BPath& path); + PPDParser(BFile& file); + ~PPDParser(); + + status_t InitCheck() const + { + return fInitErr; + } + + BString GetParameter(const BString& param); +private: + status_t InitData(BFile& file); + + BString fContent; + status_t fInitErr; +}; + +#endif /* PPDPARSER_H */ diff --git a/src/add-ons/print/drivers/postscript/PS.cpp b/src/add-ons/print/drivers/postscript/PS.cpp index 8cca54d6a7..9100ddd013 100644 --- a/src/add-ons/print/drivers/postscript/PS.cpp +++ b/src/add-ons/print/drivers/postscript/PS.cpp @@ -2,13 +2,16 @@ * PS.cpp * Copyright 1999-2000 Y.Takagi. All Rights Reserved. * Copyright 2003 Michael Pfeiffer. + * Copyright 2010 Ithamar Adema. */ #include #include #include +#include #include #include +#include #include "PS.h" #include "UIDriver.h" #include "JobData.h" @@ -18,6 +21,9 @@ #include "Halftone.h" #include "ValidRect.h" #include "DbgMsg.h" +#include "PSData.h" +#include "FilterIO.h" +#include "PPDParser.h" #if (!__MWERKS__ || defined(MSIPL_USING_NAMESPACE)) @@ -26,16 +32,86 @@ using namespace std; #define std #endif + PSDriver::PSDriver(BMessage *msg, PrinterData *printer_data, const PrinterCap *printer_cap) : GraphicsDriver(msg, printer_data, printer_cap) { fPrintedPages = 0; fHalftone = NULL; + fFilterIO = NULL; } -bool PSDriver::startDoc() + +void +PSDriver::StartFilterIfNeeded() +{ + const PSData *data = dynamic_cast(getPrinterData()); + PPDParser parser(BPath(data->fPPD.String())); + if (parser.InitCheck() == B_OK) { + BString param = parser.GetParameter("FoomaticRIPCommandLine"); + char str[3] = "%?"; + // for now, we don't have any extra substitutions to do... + // (will be added once we support configuration options from the PPD) + for (str[1] = 'A'; str[1] <= 'Z'; str[1]++) + param.ReplaceAll(str, ""); + + if (param.Length()) + fFilterIO = new FilterIO(param); + + if (!fFilterIO || fFilterIO->InitCheck() != B_OK) { + delete fFilterIO; + fFilterIO = NULL; + } + } +} + + +void +PSDriver::FlushFilterIfNeeded() +{ + if (fFilterIO) { + char buffer[1024]; + ssize_t len; + + while ((len = fFilterIO->Read(buffer,sizeof(buffer))) > 0) + writeSpoolData(buffer, len); + } +} + + +void +PSDriver::writePSString(const char *format, ...) +{ + char str[256]; + va_list ap; + va_start(ap, format); + vsprintf(str, format, ap); + + if (fFilterIO) + fFilterIO->Write(str, strlen(str)); + else + writeSpoolData(str, strlen(str)); + + va_end(ap); +} + + +void +PSDriver::writePSData(const void *data, size_t size) +{ + if (fFilterIO) + fFilterIO->Write(data, size); + else + writeSpoolData(data,size); +} + + +bool +PSDriver::startDoc() { try { + StartFilterIfNeeded(); + jobStart(); fHalftone = new Halftone(getJobData()->getSurfaceType(), getJobData()->getGamma(), getJobData()->getInkDensity(), getJobData()->getDitherType()); return true; @@ -45,21 +121,28 @@ bool PSDriver::startDoc() } } -bool PSDriver::startPage(int page) + +bool +PSDriver::startPage(int page) { page ++; - writeSpoolString("%%%%Page: %d %d\n", page, page); - writeSpoolString("gsave\n"); + writePSString("%%%%Page: %d %d\n", page, page); + writePSString("gsave\n"); setupCTM(); return true; } -bool PSDriver::endPage(int) + +bool +PSDriver::endPage(int) { try { fPrintedPages ++; - writeSpoolString("grestore\n"); - writeSpoolString("showpage\n"); + writePSString("grestore\n"); + writePSString("showpage\n"); + + FlushFilterIfNeeded(); + return true; } catch (TransportException &err) { @@ -67,26 +150,31 @@ bool PSDriver::endPage(int) } } -void PSDriver::setupCTM() { + +void +PSDriver::setupCTM() +{ const float leftMargin = getJobData()->getPrintableRect().left; const float topMargin = getJobData()->getPrintableRect().top; if (getJobData()->getOrientation() == JobData::kPortrait) { // move origin from bottom left to top left // and set margin - writeSpoolString("%f %f translate\n", leftMargin, getJobData()->getPaperRect().Height()-topMargin); + writePSString("%f %f translate\n", leftMargin, getJobData()->getPaperRect().Height()-topMargin); } else { // landscape: // move origin from bottom left to margin top and left // and rotate page contents - writeSpoolString("%f %f translate\n", topMargin, leftMargin); - writeSpoolString("90 rotate\n"); + writePSString("%f %f translate\n", topMargin, leftMargin); + writePSString("90 rotate\n"); } // y values increase from top to bottom // units of measure is dpi - writeSpoolString("72 %d div 72 -%d div scale\n", getJobData()->getXres(), getJobData()->getYres()); + writePSString("72 %d div 72 -%d div scale\n", getJobData()->getXres(), getJobData()->getYres()); } -bool PSDriver::endDoc(bool) + +bool +PSDriver::endDoc(bool) { try { if (fHalftone) { @@ -100,13 +188,17 @@ bool PSDriver::endDoc(bool) } } -inline uchar hex_digit(uchar value) + +inline uchar +hex_digit(uchar value) { if (value <= 9) return '0'+value; else return 'a'+(value-10); } -bool PSDriver::nextBand(BBitmap *bitmap, BPoint *offset) + +bool +PSDriver::nextBand(BBitmap *bitmap, BPoint *offset) { DBGMSG(("> nextBand\n")); @@ -243,52 +335,60 @@ bool PSDriver::nextBand(BBitmap *bitmap, BPoint *offset) } } -void PSDriver::jobStart() + +void +PSDriver::jobStart() { // PostScript header - writeSpoolString("%%!PS-Adobe-3.0\n"); - writeSpoolString("%%%%LanguageLevel: 1\n"); - writeSpoolString("%%%%Title: %s\n", getSpoolMetaData()->getDescription().c_str()); - writeSpoolString("%%%%Creator: %s\n", getSpoolMetaData()->getMimeType().c_str()); - writeSpoolString("%%%%CreationDate: %s", getSpoolMetaData()->getCreationTime().c_str()); - writeSpoolString("%%%%DocumentMedia: Plain %d %d white 0 ( )\n", getJobData()->getPaperRect().IntegerWidth(), getJobData()->getPaperRect().IntegerHeight()); - writeSpoolString("%%%%Pages: (atend)\n"); - writeSpoolString("%%%%EndComments\n"); + writePSString("%%!PS-Adobe-3.0\n"); + writePSString("%%%%LanguageLevel: 1\n"); + writePSString("%%%%Title: %s\n", getSpoolMetaData()->getDescription().c_str()); + writePSString("%%%%Creator: %s\n", getSpoolMetaData()->getMimeType().c_str()); + writePSString("%%%%CreationDate: %s", getSpoolMetaData()->getCreationTime().c_str()); + writePSString("%%%%DocumentMedia: Plain %d %d white 0 ( )\n", getJobData()->getPaperRect().IntegerWidth(), getJobData()->getPaperRect().IntegerHeight()); + writePSString("%%%%Pages: (atend)\n"); + writePSString("%%%%EndComments\n"); - writeSpoolString("%%%%BeginDefaults\n"); - writeSpoolString("%%%%PageMedia: Plain\n"); - writeSpoolString("%%%%EndDefaults\n"); + writePSString("%%%%BeginDefaults\n"); + writePSString("%%%%PageMedia: Plain\n"); + writePSString("%%%%EndDefaults\n"); } -void PSDriver::startRasterGraphics(int x, int y, int width, int height, int widthByte) + +void +PSDriver::startRasterGraphics(int x, int y, int width, int height, int widthByte) { bool color = getJobData()->getColor() == JobData::kColor; fCompressionMethod = -1; - writeSpoolString("gsave\n"); - writeSpoolString("/s %d string def\n", widthByte); - writeSpoolString("%d %d translate\n", x, y); - writeSpoolString("%d %d scale\n", width, height); + writePSString("gsave\n"); + writePSString("/s %d string def\n", widthByte); + writePSString("%d %d translate\n", x, y); + writePSString("%d %d scale\n", width, height); if (color) { - writeSpoolString("%d %d 8\n", width, height); // 8 bpp + writePSString("%d %d 8\n", width, height); // 8 bpp } else { - writeSpoolString("%d %d 1\n", width, height); // 1 bpp + writePSString("%d %d 1\n", width, height); // 1 bpp } - writeSpoolString("[%d 0 0 %d 0 0]\n", width, height); - writeSpoolString("{ currentfile s readhexstring pop }\n"); + writePSString("[%d 0 0 %d 0 0]\n", width, height); + writePSString("{ currentfile s readhexstring pop }\n"); if (color) { - writeSpoolString("false 3\n"); // single data source, 3 color components - writeSpoolString("colorimage\n"); + writePSString("false 3\n"); // single data source, 3 color components + writePSString("colorimage\n"); } else { - writeSpoolString("image\n\n"); + writePSString("image\n\n"); } } -void PSDriver::endRasterGraphics() + +void +PSDriver::endRasterGraphics() { - writeSpoolString("grestore\n"); + writePSString("grestore\n"); } -void PSDriver::rasterGraphics( + +void +PSDriver::rasterGraphics( int compression_method, const uchar *buffer, int size) @@ -296,12 +396,16 @@ void PSDriver::rasterGraphics( if (fCompressionMethod != compression_method) { fCompressionMethod = compression_method; } - writeSpoolData(buffer, size); - writeSpoolString("\n"); + writePSData(buffer, size); + writePSString("\n"); } -void PSDriver::jobEnd() + +void +PSDriver::jobEnd() { - writeSpoolString("%%%%Pages: %d\n", fPrintedPages); - writeSpoolString("%%%%EOF\n"); + writePSString("%%%%Pages: %d\n", fPrintedPages); + writePSString("%%%%EOF\n"); + + FlushFilterIfNeeded(); } diff --git a/src/add-ons/print/drivers/postscript/PS.h b/src/add-ons/print/drivers/postscript/PS.h index 12caa535be..7201413016 100644 --- a/src/add-ons/print/drivers/postscript/PS.h +++ b/src/add-ons/print/drivers/postscript/PS.h @@ -8,8 +8,11 @@ #include "GraphicsDriver.h" + +class FilterIO; class Halftone; + class PSDriver : public GraphicsDriver { public: PSDriver(BMessage *msg, PrinterData *printer_data, const PrinterCap *printer_cap); @@ -32,9 +35,15 @@ private: int size); void jobEnd(); + void StartFilterIfNeeded(); + void FlushFilterIfNeeded(); + void writePSString(const char *format, ...); + void writePSData(const void *data, size_t size); + int fPrintedPages; int fCompressionMethod; Halftone *fHalftone; + FilterIO *fFilterIO; }; #endif /* __PS_H */ diff --git a/src/add-ons/print/drivers/postscript/PSData.cpp b/src/add-ons/print/drivers/postscript/PSData.cpp new file mode 100644 index 0000000000..82d7c8234b --- /dev/null +++ b/src/add-ons/print/drivers/postscript/PSData.cpp @@ -0,0 +1,27 @@ +/* +* Copyright 2010, Haiku. All rights reserved. +* Distributed under the terms of the MIT License. +* +* Authors: +* Ithamar R. Adema +*/ + +#include "PSData.h" + +#include + +#define PD_PPD_PATH "ps:ppd_path" + +void +PSData::load() +{ + PrinterData::load(); + fNode->ReadAttrString(PD_PPD_PATH, &fPPD); +} + +void +PSData::save() +{ + PrinterData::save(); + fNode->WriteAttrString(PD_PPD_PATH, &fPPD); +} diff --git a/src/add-ons/print/drivers/postscript/PSData.h b/src/add-ons/print/drivers/postscript/PSData.h new file mode 100644 index 0000000000..02403e2f64 --- /dev/null +++ b/src/add-ons/print/drivers/postscript/PSData.h @@ -0,0 +1,31 @@ +/* +* Copyright 2010, Haiku. All rights reserved. +* Distributed under the terms of the MIT License. +* +* Authors: +* Ithamar R. Adema +*/ + +#ifndef PSDATA_H +#define PSDATA_H + +#include "PrinterData.h" +#include + + +class BNode; + + +class PSData : public PrinterData { +public: + PSData(BNode *node) : PrinterData(node) {} + + // PrinterData overrides + virtual void load(); + virtual void save(); + + BString fPPD; +}; + + +#endif /* PSDATA_H */ diff --git a/src/add-ons/print/drivers/postscript/PSEntry.cpp b/src/add-ons/print/drivers/postscript/PSEntry.cpp index f71204fd5f..d54888da06 100644 --- a/src/add-ons/print/drivers/postscript/PSEntry.cpp +++ b/src/add-ons/print/drivers/postscript/PSEntry.cpp @@ -2,49 +2,75 @@ * PSEntry.cpp * Copyright 1999-2000 Y.Takagi. All Rights Reserved. * Copyright 2003 Michael Pfeiffer. + * Copyright 2010 Ithamar Adema. */ #include "PS.h" #include "PSCap.h" +#include "PSData.h" #include "PrinterDriver.h" +#include "SelectPPDDlg.h" -class PSPrinterDriver : public PrinterDriver -{ +#include +#include + +class PSPrinterDriver : public PrinterDriver { public: - PSPrinterDriver(BNode* printerFolder) : PrinterDriver(printerFolder) {} - - const char* GetSignature() const + PSPrinterDriver(BNode *printerFolder) : PrinterDriver(printerFolder) {} + + const char *GetSignature() const { - return "application/x-vnd.PS-compatible"; - } - - const char* GetDriverName() const - { - return "PS compatible"; - } - - const char* GetVersion() const - { - return "0.1"; - } - - const char* GetCopyright() const - { - return "PS driver Copyright © 2003,04 Michael Pfeiffer.\n"; + return "application/x-vnd.PS-compatible"; } - PrinterCap* InstantiatePrinterCap(PrinterData* printerData) + const char *GetDriverName() const + { + return "PS compatible"; + } + + const char *GetVersion() const + { + return "0.1"; + } + + const char *GetCopyright() const + { + return "PS driver Copyright © 2003,04 Michael Pfeiffer.\n"; + } + + char *AddPrinter(char *printerName) + { + BPath path; + if (find_directory(B_SYSTEM_DATA_DIRECTORY, &path) == B_OK + && path.Append("ppd") == B_OK + && BEntry(path.Path()).Exists()) { + SelectPPDDlg *dialog = new SelectPPDDlg(dynamic_cast(GetPrinterData())); + if (dialog->Go() != B_OK) + return NULL; + } + + return printerName; + } + + PrinterData *InstantiatePrinterData(BNode *node) + { + return new PSData(node); + } + + PrinterCap *InstantiatePrinterCap(PrinterData *printerData) { return new PSCap(printerData); } - - GraphicsDriver* InstantiateGraphicsDriver(BMessage* settings, PrinterData* printerData, PrinterCap* printerCap) + + GraphicsDriver *InstantiateGraphicsDriver(BMessage *settings, PrinterData *printerData, PrinterCap *printerCap) { return new PSDriver(settings, printerData, printerCap); } }; -PrinterDriver* instantiate_printer_driver(BNode* printerFolder) + +PrinterDriver * +instantiate_printer_driver(BNode *printerFolder) { return new PSPrinterDriver(printerFolder); } diff --git a/src/add-ons/print/drivers/postscript/SelectPPDDlg.cpp b/src/add-ons/print/drivers/postscript/SelectPPDDlg.cpp new file mode 100644 index 0000000000..556d3bcf6a --- /dev/null +++ b/src/add-ons/print/drivers/postscript/SelectPPDDlg.cpp @@ -0,0 +1,190 @@ +/* +* Copyright 2010, Haiku. All rights reserved. +* Distributed under the terms of the MIT License. +* +* Authors: +* Ithamar R. Adema +*/ + +#include "SelectPPDDlg.h" +#include "PPDParser.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +enum { + kMsgCancel = 'stop', + kMsgOK = 'okok', + + kMsgManuSelected = 'msel', + kMsgPrinterSelected = 'psel', +}; + + +class PPDStringItem : public BStringItem { +public: + PPDStringItem(const BString& text, const BString& path) + : BStringItem(text.String()), + fPPDPath(path) {} + + BString fPPDPath; +}; + + +SelectPPDDlg::SelectPPDDlg(PSData *data) + : DialogWindow(BRect(10, 10, 400, 400), + "Select PPD", B_TITLED_WINDOW_LOOK, B_MODAL_APP_WINDOW_FEEL, + B_NOT_MINIMIZABLE | B_NOT_ZOOMABLE | B_ASYNCHRONOUS_CONTROLS), + fPSData(data) +{ + SetResult(B_ERROR); + + BButton *ok, *cancel; + + ok = new BButton("btn:ok", "OK", new BMessage(kMsgOK)); + ok->MakeDefault(true); + ok->SetEnabled(false); + fOKButton = ok; + + cancel = new BButton("btn:cancel", "Cancel", new BMessage(kMsgCancel)); + + BScrollView *manuScroller, *printerScroller; + fManufacturersListView = new BListView("olv:manufacturers"); + manuScroller=new BScrollView("scr:manufacturers", fManufacturersListView, 0, false, true); + fPrintersListView = new BListView("olv:printers"); + printerScroller=new BScrollView("scr:printers", fPrintersListView, 0, false, true); + + fPrintersListView->SetSelectionMessage(new BMessage(kMsgPrinterSelected)); + fManufacturersListView->SetSelectionMessage(new BMessage(kMsgManuSelected)); + PopulateManufacturers(B_SYSTEM_DATA_DIRECTORY); + + // Build the layout + SetLayout(new BGroupLayout(B_VERTICAL)); + + AddChild(BGroupLayoutBuilder(B_VERTICAL, 10) + .AddGroup(B_HORIZONTAL, 5) + .Add(manuScroller) + .Add(printerScroller) + .End() + .AddGroup(B_HORIZONTAL, 5) + .AddGlue() + .Add(cancel) + .Add(ok) + .End() + .SetInsets(10, 10, 10, 10) + ); +} + + +void +SelectPPDDlg::PopulateManufacturers(directory_which data_dir) +{ + char name[1024]; + BDirectory dir; + BEntry entry; + BPath path; + + if (find_directory(data_dir, &path) == B_OK + && path.Append("ppd") == B_OK + && dir.SetTo(path.Path()) == B_OK) { + // Got the directory, now scan it + while(dir.GetNextEntry(&entry) == B_OK) + if (entry.IsDirectory() + && entry.GetName(name) == B_OK) + fManufacturersListView->AddItem(new BStringItem(name)); + } +} + +void +SelectPPDDlg::PopulatePrinters(directory_which data_dir) +{ + int32 idx = fManufacturersListView->CurrentSelection(); + char name[1024]; + BDirectory dir; + BString manu; + BEntry entry; + BPath path; + + // Bail out if no manufacturer is selected + if (idx < 0) + return; + + manu = ((BStringItem*)fManufacturersListView->ItemAt(idx))->Text(); + + if (find_directory(data_dir, &path) == B_OK + && path.Append("ppd") == B_OK + && path.Append(manu) == B_OK + && dir.SetTo(path.Path()) == B_OK) { + // Found manufacturer PPD directory, now fill our printer list + while(dir.GetNextEntry(&entry) == B_OK) + if (entry.GetName(name) == B_OK) { + PPDParser parser(dir,name); + if (parser.InitCheck() == B_OK) { + BString modelName = parser.GetParameter("ModelName"); + BPath ppdPath = path; + ppdPath.Append(name); + fPrintersListView->AddItem(new PPDStringItem(modelName, ppdPath.Path())); + } + } + } +} + +void +SelectPPDDlg::PrinterSelected() +{ + int32 idx = fPrintersListView->CurrentSelection(); + fOKButton->SetEnabled(idx >= 0); +} + +void +SelectPPDDlg::Save() +{ + BString ppdPath; + int32 idx; + + idx = fPrintersListView->CurrentSelection(); + if (idx >= 0) + ppdPath = dynamic_cast(fPrintersListView->ItemAt(idx))->fPPDPath; + + fPSData->fPPD = ppdPath; + fPSData->save(); +} + +void +SelectPPDDlg::MessageReceived(BMessage *msg) +{ + switch (msg->what) { + case kMsgManuSelected: + fPrintersListView->MakeEmpty(); + PopulatePrinters(B_SYSTEM_DATA_DIRECTORY); + break; + case kMsgPrinterSelected: + PrinterSelected(); + break; + case kMsgOK: + Save(); + SetResult(B_NO_ERROR); + PostMessage(B_QUIT_REQUESTED); + break; + + case kMsgCancel: + PostMessage(B_QUIT_REQUESTED); + break; + + default: + DialogWindow::MessageReceived(msg); + break; + } +} diff --git a/src/add-ons/print/drivers/postscript/SelectPPDDlg.h b/src/add-ons/print/drivers/postscript/SelectPPDDlg.h new file mode 100644 index 0000000000..b90689cf75 --- /dev/null +++ b/src/add-ons/print/drivers/postscript/SelectPPDDlg.h @@ -0,0 +1,30 @@ +#ifndef SELECTPPDDLG_H +#define SELECTPPDDLG_H + +#include "DialogWindow.h" +#include "PSData.h" + +#include + +class BListView; +class BButton; +class PSData; + +class SelectPPDDlg : public DialogWindow { +public: + SelectPPDDlg(PSData *data); + void MessageReceived(BMessage *msg); +private: + void PopulateManufacturers(directory_which data_dir); + void PopulatePrinters(directory_which data_dir); + void PrinterSelected(); + void Save(); + + BListView *fManufacturersListView; + BListView *fPrintersListView; + BButton *fOKButton; + + PSData *fPSData; +}; + +#endif /* SELECTPPDDLG_H */ diff --git a/src/libs/print/libprint/PrinterData.cpp b/src/libs/print/libprint/PrinterData.cpp index af81d17db1..31c06951c3 100644 --- a/src/libs/print/libprint/PrinterData.cpp +++ b/src/libs/print/libprint/PrinterData.cpp @@ -17,10 +17,9 @@ const char *PD_TRANSPORT = "transport"; const char *PD_PROTOCOL_CLASS = "libprint:protocolClass"; PrinterData::PrinterData(BNode *node) - : fProtocolClass(0) - , fNode(node) + : fNode(node), + fProtocolClass(0) { - load(); } PrinterData::~PrinterData() diff --git a/src/libs/print/libprint/PrinterDriver.cpp b/src/libs/print/libprint/PrinterDriver.cpp index 32369acdf7..ddaa02b486 100644 --- a/src/libs/print/libprint/PrinterDriver.cpp +++ b/src/libs/print/libprint/PrinterDriver.cpp @@ -49,9 +49,20 @@ PrinterDriver::~PrinterDriver() fPrinterData = NULL; } + +PrinterData* +PrinterDriver::InstantiatePrinterData(BNode* node) +{ + return new PrinterData(node); +} + void PrinterDriver::InitPrinterDataAndCap() { - fPrinterData = new PrinterData(fSpoolFolder); + fPrinterData = InstantiatePrinterData(fSpoolFolder); + fPrinterData->load(); + // NOTE: moved the load above from the constructor of PrinterData as + // we're inheriting from PrinterData and want our overridden versions + // of load to be called fPrinterCap = InstantiatePrinterCap(fPrinterData); }