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); }