From 9295cd647f7e9e3fbdea2355096b5d3c949a0d1c Mon Sep 17 00:00:00 2001 From: Michael Pfeiffer Date: Sat, 30 Oct 2010 18:05:09 +0000 Subject: [PATCH] * Added Gutenprint printer driver add-on to image. * This is still work in progress: Printing should work with the following restrictions: - Color printing is untested. - Some configuration options provided by Gutenprint are missing. - Error reporting is missing. - The page margins should at least to increased to 1 cm or 0.4 Inch. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@39216 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- build/jam/HaikuImage | 1 + src/add-ons/print/drivers/Jamfile | 1 + .../print/drivers/gutenprint/GPArray.cpp | 84 +++ .../print/drivers/gutenprint/GPArray.h | 34 ++ .../print/drivers/gutenprint/GPBand.cpp | 34 ++ src/add-ons/print/drivers/gutenprint/GPBand.h | 28 + .../print/drivers/gutenprint/GPBinding.cpp | 229 ++++++++ .../print/drivers/gutenprint/GPBinding.h | 63 +++ .../drivers/gutenprint/GPCapabilities.cpp | 124 +++++ .../print/drivers/gutenprint/GPCapabilities.h | 51 ++ .../gutenprint/GPCapabilityExtractor.cpp | 255 +++++++++ .../gutenprint/GPCapabilityExtractor.h | 63 +++ .../print/drivers/gutenprint/GPData.cpp | 32 ++ src/add-ons/print/drivers/gutenprint/GPData.h | 36 ++ .../print/drivers/gutenprint/GPDriver.cpp | 239 +++++++++ .../print/drivers/gutenprint/GPDriver.h | 43 ++ .../print/drivers/gutenprint/GPJob.cpp | 503 ++++++++++++++++++ src/add-ons/print/drivers/gutenprint/GPJob.h | 80 +++ .../drivers/gutenprint/GPJobConfiguration.cpp | 21 + .../drivers/gutenprint/GPJobConfiguration.h | 35 ++ .../drivers/gutenprint/GPParameterVisitor.cpp | 215 ++++++++ .../drivers/gutenprint/GPParameterVisitor.h | 67 +++ .../drivers/gutenprint/GPPrinterDriver.cpp | 82 +++ .../print/drivers/gutenprint/Gutenprint.rdef | 38 ++ src/add-ons/print/drivers/gutenprint/Jamfile | 25 + .../print/drivers/gutenprint/OutputStream.h | 22 + .../gutenprint/SelectPrinterDialog.cpp | 196 +++++++ .../drivers/gutenprint/SelectPrinterDialog.h | 35 ++ 28 files changed, 2636 insertions(+) create mode 100644 src/add-ons/print/drivers/gutenprint/GPArray.cpp create mode 100644 src/add-ons/print/drivers/gutenprint/GPArray.h create mode 100644 src/add-ons/print/drivers/gutenprint/GPBand.cpp create mode 100644 src/add-ons/print/drivers/gutenprint/GPBand.h create mode 100644 src/add-ons/print/drivers/gutenprint/GPBinding.cpp create mode 100644 src/add-ons/print/drivers/gutenprint/GPBinding.h create mode 100644 src/add-ons/print/drivers/gutenprint/GPCapabilities.cpp create mode 100644 src/add-ons/print/drivers/gutenprint/GPCapabilities.h create mode 100644 src/add-ons/print/drivers/gutenprint/GPCapabilityExtractor.cpp create mode 100644 src/add-ons/print/drivers/gutenprint/GPCapabilityExtractor.h create mode 100644 src/add-ons/print/drivers/gutenprint/GPData.cpp create mode 100644 src/add-ons/print/drivers/gutenprint/GPData.h create mode 100644 src/add-ons/print/drivers/gutenprint/GPDriver.cpp create mode 100644 src/add-ons/print/drivers/gutenprint/GPDriver.h create mode 100644 src/add-ons/print/drivers/gutenprint/GPJob.cpp create mode 100644 src/add-ons/print/drivers/gutenprint/GPJob.h create mode 100644 src/add-ons/print/drivers/gutenprint/GPJobConfiguration.cpp create mode 100644 src/add-ons/print/drivers/gutenprint/GPJobConfiguration.h create mode 100644 src/add-ons/print/drivers/gutenprint/GPParameterVisitor.cpp create mode 100644 src/add-ons/print/drivers/gutenprint/GPParameterVisitor.h create mode 100644 src/add-ons/print/drivers/gutenprint/GPPrinterDriver.cpp create mode 100644 src/add-ons/print/drivers/gutenprint/Gutenprint.rdef create mode 100644 src/add-ons/print/drivers/gutenprint/Jamfile create mode 100644 src/add-ons/print/drivers/gutenprint/OutputStream.h create mode 100644 src/add-ons/print/drivers/gutenprint/SelectPrinterDialog.cpp create mode 100644 src/add-ons/print/drivers/gutenprint/SelectPrinterDialog.h diff --git a/build/jam/HaikuImage b/build/jam/HaikuImage index c6ed374b72..63fc06f6f8 100644 --- a/build/jam/HaikuImage +++ b/build/jam/HaikuImage @@ -142,6 +142,7 @@ SYSTEM_ADD_ONS_MEDIA_PLUGINS = $(X86_ONLY)ffmpeg raw_decoder ; SYSTEM_ADD_ONS_PRINT = Canon\ LIPS3\ Compatible Canon\ LIPS4\ Compatible + Gutenprint PCL5\ Compatible PCL6\ Compatible PDF\ Writer diff --git a/src/add-ons/print/drivers/Jamfile b/src/add-ons/print/drivers/Jamfile index 9947457ac8..c78844ff1c 100644 --- a/src/add-ons/print/drivers/Jamfile +++ b/src/add-ons/print/drivers/Jamfile @@ -1,6 +1,7 @@ SubDir HAIKU_TOP src add-ons print drivers ; SubInclude HAIKU_TOP src add-ons print drivers canon_lips ; +SubInclude HAIKU_TOP src add-ons print drivers gutenprint ; SubInclude HAIKU_TOP src add-ons print drivers pcl5 ; SubInclude HAIKU_TOP src add-ons print drivers pcl6 ; SubInclude HAIKU_TOP src add-ons print drivers pdf ; diff --git a/src/add-ons/print/drivers/gutenprint/GPArray.cpp b/src/add-ons/print/drivers/gutenprint/GPArray.cpp new file mode 100644 index 0000000000..b991c5ad94 --- /dev/null +++ b/src/add-ons/print/drivers/gutenprint/GPArray.cpp @@ -0,0 +1,84 @@ +/* +* Copyright 2010, Haiku. All rights reserved. +* Distributed under the terms of the MIT License. +* +* Authors: +* Michael Pfeiffer +*/ +#include + +template +GPArray::GPArray() + : + fArray(NULL), + fSize(0) +{ + +} + +template +GPArray::~GPArray() +{ + if (fArray != NULL) { + for (int i = 0; i < fSize; i ++) + delete fArray[i]; + delete[] fArray; + fArray = NULL; + } +} + + +template +void +GPArray::SetSize(int size) +{ + ASSERT(fSize == NULL); + fArray = new PointerType[size]; + if (fArray == NULL) + return; + + fSize = size; + for (int i = 0; i < size; i ++) { + fArray[i] = NULL; + } +} + + +template +int +GPArray::Size() const +{ + return fSize; +} + + +template +void +GPArray::DecreaseSize() +{ + ASSERT(fArray != NULL); + ASSERT(fArray[fSize-1] == NULL); + fSize --; +} + +template +TYPE** +GPArray::Array() +{ + return fArray; +} + + +template +TYPE ** const +GPArray::Array() const +{ + return fArray; +} + +template +bool +GPArray::IsEmpty() const +{ + return fSize == 0; +} diff --git a/src/add-ons/print/drivers/gutenprint/GPArray.h b/src/add-ons/print/drivers/gutenprint/GPArray.h new file mode 100644 index 0000000000..b4830bb9f5 --- /dev/null +++ b/src/add-ons/print/drivers/gutenprint/GPArray.h @@ -0,0 +1,34 @@ +/* +* Copyright 2010, Haiku. All rights reserved. +* Distributed under the terms of the MIT License. +* +* Authors: +* Michael Pfeiffer +*/ +#ifndef GP_ARRAY_H +#define GP_ARRAY_H + +template +class GPArray +{ +public: + typedef TYPE* PointerType; + + GPArray(); + virtual ~GPArray(); + + void SetSize(int size); + int Size() const; + void DecreaseSize(); + TYPE** Array(); + TYPE** const Array() const; + bool IsEmpty() const; + +private: + TYPE** fArray; + int fSize; +}; + +#include "GPArray.cpp" + +#endif diff --git a/src/add-ons/print/drivers/gutenprint/GPBand.cpp b/src/add-ons/print/drivers/gutenprint/GPBand.cpp new file mode 100644 index 0000000000..218b7ea815 --- /dev/null +++ b/src/add-ons/print/drivers/gutenprint/GPBand.cpp @@ -0,0 +1,34 @@ +/* +* Copyright 2010, Haiku. All rights reserved. +* Distributed under the terms of the MIT License. +* +* Authors: +* Michael Pfeiffer +*/ +#include "GPBand.h" + +GPBand::GPBand(BBitmap* bitmap, BRect validRect, BPoint where) + : + fBitmap(*bitmap), + fValidRect(validRect), + fWhere(where) +{ + +} + + +BRect +GPBand::GetBoundingRectangle() const +{ + BRect rect = fValidRect; + rect.OffsetTo(fWhere); + return rect; +} + + +bool +GPBand::ContainsLine(int line) const +{ + int y = line - (int)fWhere.y; + return 0 <= y && y <= fValidRect.IntegerHeight(); +} diff --git a/src/add-ons/print/drivers/gutenprint/GPBand.h b/src/add-ons/print/drivers/gutenprint/GPBand.h new file mode 100644 index 0000000000..5a39174947 --- /dev/null +++ b/src/add-ons/print/drivers/gutenprint/GPBand.h @@ -0,0 +1,28 @@ +/* +* Copyright 2010, Haiku. All rights reserved. +* Distributed under the terms of the MIT License. +* +* Authors: +* Michael Pfeiffer +*/ +#ifndef GP_BAND_H +#define GP_BAND_H + + +#include + + +class GPBand +{ +public: + GPBand(BBitmap* bitmap, BRect validRect, BPoint where); + + BRect GetBoundingRectangle() const; + bool ContainsLine(int line) const; + + BBitmap fBitmap; + BRect fValidRect; + BPoint fWhere; +}; + +#endif diff --git a/src/add-ons/print/drivers/gutenprint/GPBinding.cpp b/src/add-ons/print/drivers/gutenprint/GPBinding.cpp new file mode 100644 index 0000000000..4f61f47203 --- /dev/null +++ b/src/add-ons/print/drivers/gutenprint/GPBinding.cpp @@ -0,0 +1,229 @@ +/* +* Copyright 2010, Haiku. All rights reserved. +* Distributed under the terms of the MIT License. +* +* Authors: +* Michael Pfeiffer +*/ +#include "GPBinding.h" + +#include +#include +#include + +#include + + +#include "GPCapabilityExtractor.h" + +using namespace std; + + +// printer manufacturer +static const char* kManufacturerId = "id"; +static const char* kManufacturerDisplayName = "name"; + +// printer model +static const char* kModelDisplayName = "model"; +static const char* kModelDriver = "driver"; + + +GPBinding::GPBinding() +: +fInitialized(false), +fOutputStream(NULL) +{ + +} + + +GPBinding::~GPBinding() +{ + DeleteBands(); +} + + +status_t +GPBinding::GetPrinterManufacturers(BMessage& manufacturers) +{ + InitGutenprint(); + + list ids; + set manufacturerSet; + + for (int i = 0; i < stp_printer_model_count(); i ++) { + const stp_printer_t* printer = stp_get_printer_by_index(i); + string manufacturer = stp_printer_get_manufacturer(printer); + + // ignore unnamed manufacturers + if (manufacturer == "") + continue; + + // add manufacturer only once + if (manufacturerSet.find(manufacturer) != manufacturerSet.end()) + continue; + + manufacturerSet.insert(manufacturer); + + ids.push_back(manufacturer); + } + + ids.sort(); + + list::iterator it = ids.begin(); + for (; it != ids.end(); it ++) { + string manufacturer = *it; + const char* id = manufacturer.c_str(); + const char* name = manufacturer.c_str(); + AddManufacturer(manufacturers, id, name); + } + return B_OK; +} + + +bool +GPBinding::ExtractManufacturer(const BMessage& manufacturers, int32 index, + BString& id, BString& displayName) +{ + if (manufacturers.FindString(kManufacturerId, index, &id) != B_OK) + return false; + if (manufacturers.FindString(kManufacturerDisplayName, index, &displayName) + != B_OK) + return false; + return true; +} + + +void +GPBinding::AddManufacturer(BMessage& manufacturers, const char* id, + const char* displayName) +{ + manufacturers.AddString(kManufacturerId, id); + manufacturers.AddString(kManufacturerDisplayName, displayName); +} + + +status_t +GPBinding::GetPrinterModels(const char* manufacturer, BMessage& models) +{ + for (int i = 0; i < stp_printer_model_count(); i ++) { + const stp_printer_t* printer = stp_get_printer_by_index(i); + if (strcmp(manufacturer, stp_printer_get_manufacturer(printer)) != 0) + continue; + + const char* displayName = stp_printer_get_long_name(printer); + const char* driver = stp_printer_get_driver(printer); + AddModel(models, displayName, driver); + } + return B_OK; +} + + +bool +GPBinding::ExtractModel(const BMessage& models, int32 index, BString& displayName, + BString& driver) +{ + if (models.FindString(kModelDisplayName, index, &displayName) != B_OK) + return false; + if (models.FindString(kModelDriver, index, &driver) != B_OK) + return false; + return true; +} + + +void +GPBinding::AddModel(BMessage& models, const char* displayName, const char* driver) +{ + models.AddString(kModelDisplayName, displayName); + models.AddString(kModelDriver, driver); +} + + +status_t +GPBinding::GetCapabilities(const char* driver, GPCapabilities* capabilities) +{ + InitGutenprint(); + const stp_printer_t* printer = stp_get_printer_by_driver(driver); + if (printer == NULL) + return B_ERROR; + + GPCapabilityExtractor extractor(capabilities); + extractor.Visit(printer); + return B_OK; +} + + +status_t +GPBinding::BeginJob(GPJobConfiguration* configuration, + OutputStream* outputStream) + throw(TransportException) +{ + fOutputStream = outputStream; + fJob.SetApplicationName("Gutenprint"); + fJob.SetConfiguration(configuration); + fJob.SetOutputStream(outputStream); + + return fJob.Begin(); +} + + +void +GPBinding::EndJob() throw(TransportException) +{ + fJob.End(); + fOutputStream = NULL; +} + + +void +GPBinding::BeginPage() throw(TransportException) +{ +} + + +void +GPBinding::EndPage() throw(TransportException) +{ + status_t status = fJob.PrintPage(fBands); + DeleteBands(); + if (status != B_OK) + throw TransportException("I/O Error"); +} + + +void +GPBinding::AddBitmapToPage(BBitmap* bitmap, BRect validRect, BPoint where) +{ + GPBand* band = new(nothrow) GPBand(bitmap, validRect, where); + if (band == NULL) { + // TODO report error + return; + } + + fBands.push_back(band); +} + + +void +GPBinding::InitGutenprint() +{ + if (fInitialized) + return; + fInitialized = true; + // TODO make sure this creates no memory leaks, + // as there is no "destroy" counter part + stp_init(); + stp_set_output_codeset("UTF-8"); +} + + +void +GPBinding::DeleteBands() +{ + list::iterator it = fBands.begin(); + for (; it != fBands.end(); it ++) { + GPBand* band = *it; + delete band; + } + fBands.clear(); +} diff --git a/src/add-ons/print/drivers/gutenprint/GPBinding.h b/src/add-ons/print/drivers/gutenprint/GPBinding.h new file mode 100644 index 0000000000..2d8ce46eab --- /dev/null +++ b/src/add-ons/print/drivers/gutenprint/GPBinding.h @@ -0,0 +1,63 @@ +/* +* Copyright 2010, Haiku. All rights reserved. +* Distributed under the terms of the MIT License. +* +* Authors: +* Michael Pfeiffer +*/ +#ifndef GP_BINDING_H +#define GP_BINDING_H + + +#include +#include + +#include + +#include "GPBand.h" +#include "GPJob.h" +#include "GPJobConfiguration.h" +#include "OutputStream.h" +#include "ValidRect.h" + +class GPCapabilities; + +class GPBinding +{ +public: + GPBinding(); + ~GPBinding(); + + status_t GetPrinterManufacturers(BMessage& manufacturers); + bool ExtractManufacturer(const BMessage& manufacturers, int32 index, + BString& id, BString& displayName); + void AddManufacturer(BMessage& manufacturers, const char* id, + const char* name); + + status_t GetPrinterModels(const char* manufacturer, BMessage& models); + bool ExtractModel(const BMessage& models, int32 index, + BString& displayName, BString& driver); + void AddModel(BMessage& models, const char* displayName, + const char* driver); + + status_t GetCapabilities(const char* driver, + GPCapabilities* capabilities); + + status_t BeginJob(GPJobConfiguration* configuration, + OutputStream* outputStream) throw(TransportException); + void EndJob() throw(TransportException); + void BeginPage() throw(TransportException); + void EndPage() throw(TransportException); + void AddBitmapToPage(BBitmap* bitmap, BRect validRect, BPoint where); + +private: + void InitGutenprint(); + void DeleteBands(); + + bool fInitialized; + OutputStream* fOutputStream; + list fBands; + GPJob fJob; +}; + +#endif diff --git a/src/add-ons/print/drivers/gutenprint/GPCapabilities.cpp b/src/add-ons/print/drivers/gutenprint/GPCapabilities.cpp new file mode 100644 index 0000000000..a63f51f23f --- /dev/null +++ b/src/add-ons/print/drivers/gutenprint/GPCapabilities.cpp @@ -0,0 +1,124 @@ +/* +* Copyright 1999-2000 Y.Takagi. All Rights Reserved. +* +* Copyright 2010, Haiku. All rights reserved. +* Distributed under the terms of the MIT License. +* +* Authors: +* Michael Pfeiffer +*/ + + +#include "GPCapabilities.h" + +#include "GPBinding.h" +#include "GPData.h" +#include "PrinterData.h" + + +GPCapabilities::GPCapabilities(const PrinterData* printer_data) + : + PrinterCap(printer_data) +{ + InitCapabilitiesFromGutenprint(); +} + + +GPCapabilities::~GPCapabilities() +{ +} + +int +GPCapabilities::countCap(CapID category) const +{ + const GPArray* capabilities; + + switch (category) { + case kPaper: + return fPageSizes.Size(); + case kPaperSource: + return fInputSlots.Size(); + case kResolution: + return fResolutions.Size(); + case kColor: + return fPrintingModes.Size(); + case kDriverSpecificCapabilities: + return fDriverSpecificCategories.Size(); + + default: + capabilities = DriverSpecificCapabilities(category); + if (capabilities == NULL) + return 0; + return capabilities->Size(); + } +} + + +const BaseCap** +GPCapabilities::enumCap(CapID category) const +{ + typedef const BaseCap** ArrayType; + const GPArray* capabilities; + + switch (category) { + case kPaper: + return (ArrayType)fPageSizes.Array(); + case kPaperSource: + return (ArrayType)fInputSlots.Array(); + case kResolution: + return (ArrayType)fResolutions.Array(); + case kColor: + return (ArrayType)fPrintingModes.Array(); + case kDriverSpecificCapabilities: + return (ArrayType)fDriverSpecificCategories.Array(); + + default: + capabilities = DriverSpecificCapabilities(category); + if (capabilities == NULL) + return NULL; + return (ArrayType)capabilities->Array(); + } +} + + +bool +GPCapabilities::isSupport(CapID category) const +{ + switch (category) { + case kPaper: + case kPaperSource: + case kResolution: + case kColor: + return true; + + default: + return countCap(category) > 0; + } +} + +void +GPCapabilities::InitCapabilitiesFromGutenprint() +{ + const GPData* data = dynamic_cast(getPrinterData()); + ASSERT(data != NULL); + // capabilities are available only after printer model + // has been selected + if (data->fGutenprintDriverName == "") + return; + + + GPBinding binding; + binding.GetCapabilities(data->fGutenprintDriverName.String(), this); +} + + +const GPArray* +GPCapabilities::DriverSpecificCapabilities(int32 category) const +{ + DriverSpecificCapabilitiesType::const_iterator it = + fDriverSpecificCapabilities.find(category); + if (it == fDriverSpecificCapabilities.end()) + return NULL; + return &it->second; +} + diff --git a/src/add-ons/print/drivers/gutenprint/GPCapabilities.h b/src/add-ons/print/drivers/gutenprint/GPCapabilities.h new file mode 100644 index 0000000000..d3173f0ceb --- /dev/null +++ b/src/add-ons/print/drivers/gutenprint/GPCapabilities.h @@ -0,0 +1,51 @@ +/* +* Copyright 1999-2000 Y.Takagi. All Rights Reserved. +* +* Copyright 2010, Haiku. All rights reserved. +* Distributed under the terms of the MIT License. +* +* Authors: +* Michael Pfeiffer +* +*/ +#ifndef GP_CAPABILITIES_H +#define GP_CAPABILITIES_H + + +#include "PrinterCap.h" + +#include "GPArray.h" + +#include + +class GPCapabilityExtractor; + +class GPCapabilities : public PrinterCap { +public: + GPCapabilities(const PrinterData* printer_data); + ~GPCapabilities(); + + virtual int countCap(CapID) const; + virtual bool isSupport(CapID) const; + virtual const BaseCap **enumCap(CapID) const; + +private: + void InitCapabilitiesFromGutenprint(); + const GPArray* + DriverSpecificCapabilities(int32 category) const; + + GPArray fPageSizes; + GPArray fResolutions; + GPArray fInputSlots; + GPArray fPrintingModes; + + GPArray fDriverSpecificCategories; + + typedef map > DriverSpecificCapabilitiesType; + DriverSpecificCapabilitiesType fDriverSpecificCapabilities; + + friend class GPCapabilityExtractor; +}; + + +#endif diff --git a/src/add-ons/print/drivers/gutenprint/GPCapabilityExtractor.cpp b/src/add-ons/print/drivers/gutenprint/GPCapabilityExtractor.cpp new file mode 100644 index 0000000000..9e1057729f --- /dev/null +++ b/src/add-ons/print/drivers/gutenprint/GPCapabilityExtractor.cpp @@ -0,0 +1,255 @@ +/* +* Copyright 2010, Haiku. All rights reserved. +* Distributed under the terms of the MIT License. +* +* Authors: +* Michael Pfeiffer +*/ +#include "GPCapabilityExtractor.h" + +#include "PrinterCap.h" + + +const char* kInputSlot = "InputSlot"; + + +#if 1 +#define GP_PRINT(...) \ + fprintf(stderr, __VA_ARGS__) +#else +#define GP_PRINT(...) \ + {} +#endif + +GPCapabilityExtractor::GPCapabilityExtractor(GPCapabilities* capabilities) + : + fState(kIgnoreParameter), + fCapabilities(capabilities), + fIndex(0), + fNextDriverSpecificCategoryID(PrinterCap::kDriverSpecificCapabilitiesBegin) +{ + +} + + +bool +GPCapabilityExtractor::BeginParameter(const char* name, const char* displayName, + stp_parameter_class_t parameterClass) +{ + fState = kIgnoreParameter; + if (strcmp(kPageSize, name) == 0) { + GP_PRINT("Supported parameter: %s\n", name); + fState = kExtractPageSizeParameter; + } else if (strcmp(kResolution, name) == 0) { + GP_PRINT("Supported parameter: %s\n", name); + fState = kExtractResolutionParameter; + } else if (strcmp(kInputSlot, name) == 0) { + GP_PRINT("Supported parameter: %s\n", name); + fState = kExtractInputSlotParameter; + } else if (strcmp(kPrintingMode, name) == 0) { + GP_PRINT("Supported parameter: %s\n", name); + fState = kExtractPrintingModeParameter; + } else { + GP_PRINT("Parameter: %s - %s\n", name, displayName); + bool recordParameter = parameterClass == STP_PARAMETER_CLASS_FEATURE || + parameterClass == STP_PARAMETER_CLASS_OUTPUT; + if (!recordParameter) + return false; + + fState = kExtractParameter; + DriverSpecificCap* capability = new DriverSpecificCap(displayName, + fNextDriverSpecificCategoryID, DriverSpecificCap::kList); + capability->fKey = name; + + fDriverSpecificCategories.push_back(capability); + } + return true; +} + + +void +GPCapabilityExtractor::DefaultStringParameter(const char* name, + const char* key) +{ + if (key == NULL) + fDefaultKey = ""; + else + fDefaultKey = key; +} + + +void +GPCapabilityExtractor::StringParameterSize(const char* name, int size) +{ + fIndex = 0; + + switch (fState) { + case kExtractPageSizeParameter: + fCapabilities->fPageSizes.SetSize(size); + break; + + case kExtractResolutionParameter: + fCapabilities->fResolutions.SetSize(size); + break; + + case kExtractInputSlotParameter: + fCapabilities->fInputSlots.SetSize(size); + break; + + case kExtractPrintingModeParameter: + fCapabilities->fPrintingModes.SetSize(size); + break; + + case kExtractParameter: + fState = kExtractListParameter; + fCapabilities->fDriverSpecificCapabilities[ + fNextDriverSpecificCategoryID].SetSize(size); + break; + + default: + break; + } +} + + +void +GPCapabilityExtractor::StringParameter(const char* name, const char* key, + const char* displayName) +{ + bool isDefault = fDefaultKey == key; + BaseCap* capability; + + switch (fState) { + case kExtractResolutionParameter: + GP_PRINT("GPCapabilityExtractor: ResolutionParameter expected\n"); + break; + + case kExtractInputSlotParameter: + capability = new PaperSourceCap(displayName, isDefault, + static_cast(fIndex)); + AddCapability(fCapabilities->fInputSlots, capability, key); + break; + + case kExtractPrintingModeParameter: + capability = new ColorCap(displayName, isDefault, + static_cast(fIndex)); + AddCapability(fCapabilities->fPrintingModes, capability, key); + break; + + case kExtractListParameter: + capability = new ListItemCap(displayName, isDefault, fIndex); + AddCapability(fCapabilities->fDriverSpecificCapabilities[ + fNextDriverSpecificCategoryID], capability, key); + break; + + default: + break; + } + +} + + +void +GPCapabilityExtractor::ResolutionParameter(const char* name, const char* key, + const char* displayName, int x, int y) +{ + bool isDefault = fDefaultKey == key; + BaseCap* capability; + + switch (fState) { + case kExtractResolutionParameter: + if (x <= 0 || y <= 0) { + // usually this is the entry for the "Default" resolution + // if we want to show this in the UI, we need a way to + // determine the resolution (x and y) for it, because + // libprint needs it for rasterization + fCapabilities->fResolutions.DecreaseSize(); + break; + } + + capability = new ResolutionCap(displayName, isDefault, fIndex, + x, y); + AddCapability(fCapabilities->fResolutions, capability, key); + break; + + default: + break; + } +} + + +void +GPCapabilityExtractor::PageSizeParameter(const char* name, const char* key, + const char* displayName, BSize pageSize, BRect imageableArea) +{ + bool isDefault = fDefaultKey == key; + BaseCap* capability; + + switch (fState) { + case kExtractPageSizeParameter: + capability = new PaperCap(displayName, isDefault, + static_cast(fIndex), + BRect(0, 0, pageSize.width, pageSize.height), + imageableArea); + AddCapability(fCapabilities->fPageSizes, capability, key); + break; + + default: + break; + } +} + + +void +GPCapabilityExtractor::EndParameter(const char* name) +{ + if (fState == kExtractListParameter) { + fNextDriverSpecificCategoryID ++; + } +} + + +void +GPCapabilityExtractor::EndVisit() +{ + if (fCapabilities->fInputSlots.Size() == 0) + AddDefaultInputSlot(); + SetDriverSpecificCategories(); +} + + +void +GPCapabilityExtractor::AddDefaultInputSlot() +{ + BeginParameter(kInputSlot, "Input Slot", STP_PARAMETER_CLASS_FEATURE); + DefaultStringParameter(kInputSlot, ""); + StringParameterSize(kInputSlot, 1); + StringParameter(kInputSlot, "", "Default"); + EndParameter(kInputSlot); +} + + +void +GPCapabilityExtractor::SetDriverSpecificCategories() +{ + int size = fDriverSpecificCategories.size(); + if (size == 0) + return; + + fCapabilities->fDriverSpecificCategories.SetSize(size); + struct BaseCap** array = fCapabilities->fDriverSpecificCategories.Array(); + list::iterator it = fDriverSpecificCategories.begin(); + for (int index = 0; it != fDriverSpecificCategories.end(); it ++, + index ++) { + array[index] = *it; + } +} + +void +GPCapabilityExtractor::AddCapability(GPArray& array, + BaseCap* capability, const char* key) +{ + capability->fKey = key; + array.Array()[fIndex] = capability; + fIndex ++; +} diff --git a/src/add-ons/print/drivers/gutenprint/GPCapabilityExtractor.h b/src/add-ons/print/drivers/gutenprint/GPCapabilityExtractor.h new file mode 100644 index 0000000000..6d1e254a55 --- /dev/null +++ b/src/add-ons/print/drivers/gutenprint/GPCapabilityExtractor.h @@ -0,0 +1,63 @@ +/* +* Copyright 2010, Haiku. All rights reserved. +* Distributed under the terms of the MIT License. +* +* Authors: +* Michael Pfeiffer +*/ +#ifndef GP_CAPABILITY_EXTRACTOR_H +#define GP_CAPABILITY_EXTRACTOR_H + +#include "GPParameterVisitor.h" + +#include + +#include "GPCapabilities.h" + +enum GPCapabilityExtractorState { + kIgnoreParameter, + kExtractPageSizeParameter, + kExtractResolutionParameter, + kExtractInputSlotParameter, + kExtractPrintingModeParameter, + kExtractParameter, + kExtractListParameter, + +}; + +class GPCapabilityExtractor : public GPParameterVisitor +{ +public: + GPCapabilityExtractor(GPCapabilities* cap); + + bool BeginParameter(const char* name, const char* displayName, + stp_parameter_class_t parameterClass); + void DefaultStringParameter(const char* name, + const char* key); + void StringParameterSize(const char* name, int size); + void StringParameter(const char* name, const char* key, + const char* displayName); + void ResolutionParameter(const char* name, const char* key, + const char* displayName, int x, int y); + void PageSizeParameter(const char* name, const char* key, + const char* displayName, BSize pageSize, BRect imageableArea); + void EndParameter(const char* name); + void EndVisit(); + +protected: + void AddDefaultInputSlot(); + void SetDriverSpecificCategories(); + void AddCapability(GPArray& array, BaseCap* capability, + const char* key); + +private: + GPCapabilityExtractorState fState; + GPCapabilities* fCapabilities; + int fIndex; + BString fDefaultKey; + + list fDriverSpecificCategories; + int32 fNextDriverSpecificCategoryID; +}; + +#endif diff --git a/src/add-ons/print/drivers/gutenprint/GPData.cpp b/src/add-ons/print/drivers/gutenprint/GPData.cpp new file mode 100644 index 0000000000..9f9f616b97 --- /dev/null +++ b/src/add-ons/print/drivers/gutenprint/GPData.cpp @@ -0,0 +1,32 @@ +/* +* Copyright 2010, Haiku. All rights reserved. +* Distributed under the terms of the MIT License. +* +* Authors: +* Ithamar R. Adema +*/ + + +#include "GPData.h" + +#include + +#define PD_PRINTER_DRIVER_ATTRIBUTE "gutenprint:driver-name" + + +void +GPData::load() +{ + PrinterData::load(); + fNode->ReadAttrString(PD_PRINTER_DRIVER_ATTRIBUTE, + &fGutenprintDriverName); +} + + +void +GPData::save() +{ + PrinterData::save(); + fNode->WriteAttrString(PD_PRINTER_DRIVER_ATTRIBUTE, + &fGutenprintDriverName); +} diff --git a/src/add-ons/print/drivers/gutenprint/GPData.h b/src/add-ons/print/drivers/gutenprint/GPData.h new file mode 100644 index 0000000000..1c59e08888 --- /dev/null +++ b/src/add-ons/print/drivers/gutenprint/GPData.h @@ -0,0 +1,36 @@ +/* +* Copyright 2010, Haiku. All rights reserved. +* Distributed under the terms of the MIT License. +* +* Authors: +* Ithamar R. Adema +* Michael Pfeiffer +*/ +#ifndef GP_DATA_H +#define GP_DATA_H + + +#include "PrinterData.h" + +#include + + +class BNode; + + +class GPData : public PrinterData { +public: + GPData(BNode* node) + : + PrinterData(node) + { + } + + // PrinterData overrides + virtual void load(); + virtual void save(); + + BString fGutenprintDriverName; +}; + +#endif // PSDATA_H diff --git a/src/add-ons/print/drivers/gutenprint/GPDriver.cpp b/src/add-ons/print/drivers/gutenprint/GPDriver.cpp new file mode 100644 index 0000000000..b0204fee6c --- /dev/null +++ b/src/add-ons/print/drivers/gutenprint/GPDriver.cpp @@ -0,0 +1,239 @@ +/* + * GP.cpp + * Copyright 1999-2000 Y.Takagi. All Rights Reserved. + * Copyright 2010 Michael Pfeiffer. + */ + + +#include "GPDriver.h" + +#include + +#include +#include +#include +#include + +#include "DbgMsg.h" +#include "Halftone.h" +#include "JobData.h" +#include "PackBits.h" +#include "GPCapabilities.h" +#include "GPData.h" +#include "PrinterData.h" +#include "UIDriver.h" +#include "ValidRect.h" + + +using namespace std; + + +GPDriver::GPDriver(BMessage* msg, PrinterData* printer_data, + const PrinterCap* printer_cap) + : + GraphicsDriver(msg, printer_data, printer_cap) +{ +} + +void +GPDriver::Write(const void *buffer, size_t size) + throw(TransportException) +{ + writeSpoolData(buffer, size); +} + +bool +GPDriver::startDoc() +{ + try { + const GPData* data = dynamic_cast(getPrinterData()); + ASSERT(data != NULL); + fConfiguration.fDriver = data->fGutenprintDriverName; + + SetParameter(fConfiguration.fPageSize, PrinterCap::kPaper, + getJobData()->getPaper()); + + SetParameter(fConfiguration.fResolution, PrinterCap::kResolution, + getJobData()->getResolutionID()); + + fConfiguration.fXDPI = getJobData()->getXres(); + fConfiguration.fYDPI = getJobData()->getYres(); + + SetParameter(fConfiguration.fInputSlot, PrinterCap::kPaperSource, + getJobData()->getPaperSource()); + + SetParameter(fConfiguration.fPrintingMode, PrinterCap::kColor, + getJobData()->getColor()); + + if (getPrinterCap()->isSupport(PrinterCap::kDriverSpecificCapabilities)) + SetDriverSpecificSettings(); + + fprintf(stderr, "Driver: %s\n", fConfiguration.fDriver.String()); + fprintf(stderr, "PageSize %s\n", fConfiguration.fPageSize.String()); + fprintf(stderr, "Resolution %s\n", fConfiguration.fResolution.String()); + fprintf(stderr, "InputSlot %s\n", fConfiguration.fInputSlot.String()); + fprintf(stderr, "PrintingMode %s\n", fConfiguration.fPrintingMode.String()); + + return fBinding.BeginJob(&fConfiguration, this) == B_OK; + } + catch (TransportException& err) { + return false; + } +} + + +void +GPDriver::SetParameter(BString& parameter, PrinterCap::CapID category, + int value) +{ + const BaseCap* capability; + capability = getPrinterCap()->findCap(category, value); + if (capability != NULL && capability->fKey != "") + parameter = capability->Key(); +} + + +void +GPDriver::SetDriverSpecificSettings() +{ + PrinterCap::CapID category = PrinterCap::kDriverSpecificCapabilities; + int count = getPrinterCap()->countCap(category); + const BaseCap** capabilities = getPrinterCap()->enumCap(category); + for (int i = 0; i < count; i++) { + const BaseCap* capability = capabilities[i]; + PrinterCap::CapID id = static_cast(capability->ID()); + AddDriverSpecificSetting(id, capability->fKey.c_str()); + } +} + + +void +GPDriver::AddDriverSpecificSetting(PrinterCap::CapID category, const char* key) { + const BaseCap* capability = NULL; + if (getJobData()->HasDriverSpecificSetting(key)) + { + const string& value = getJobData()->DriverSpecificSetting(key); + capability = getPrinterCap()->findCapWithKey(category, value.c_str()); + } + + if (capability == NULL) { + // job data should contain a value; + // try to use the default value anyway + capability = getPrinterCap()->getDefaultCap(category); + } + + if (capability == NULL) { + // should not reach here! + return; + } + + fConfiguration.fDriverSpecificSettings[key] = capability->fKey; +} + + +bool +GPDriver::startPage(int) +{ + fBinding.BeginPage(); + return true; +} + + +bool +GPDriver::endPage(int) +{ + try { + fBinding.EndPage(); + return true; + } + catch (TransportException& err) { + return false; + } +} + + +bool +GPDriver::endDoc(bool) +{ + try { + fBinding.EndJob(); + return true; + } + catch (TransportException& err) { + return false; + } +} + + +bool +GPDriver::nextBand(BBitmap* bitmap, BPoint* offset) +{ + DBGMSG(("> nextBand\n")); + try { + BRect bounds = bitmap->Bounds(); + + RECT rc; + rc.left = (int)bounds.left; + rc.top = (int)bounds.top; + rc.right = (int)bounds.right; + rc.bottom = (int)bounds.bottom; + + int height = rc.bottom - rc.top + 1; + + int x = (int)offset->x; + int y = (int)offset->y; + + int page_height = getPageHeight(); + + if (y + height > page_height) + height = page_height - y; + + rc.bottom = height - 1; + + DBGMSG(("height = %d\n", height)); + DBGMSG(("x = %d\n", x)); + DBGMSG(("y = %d\n", y)); + + if (get_valid_rect(bitmap, &rc)) { + + DBGMSG(("validate rect = %d, %d, %d, %d\n", + rc.left, rc.top, rc.right, rc.bottom)); + + x = rc.left; + y += rc.top; +/* + int width = rc.right - rc.left + 1; + int height = rc.bottom - rc.top + 1; + int delta = bitmap->BytesPerRow(); + + DBGMSG(("width = %d\n", width)); + DBGMSG(("height = %d\n", height)); + DBGMSG(("delta = %d\n", delta)); + DBGMSG(("renderobj->get_pixel_depth() = %d\n", fHalftone->getPixelDepth())); +*/ + int width = rc.right - rc.left + 1; + int height = rc.bottom - rc.top + 1; + fprintf(stderr, "GPDriver nextBand x %d, y %d, width %d," + " height %d\n", + x, y, width, height); + BRect imageRect(rc.left, rc.top, rc.right, rc.bottom); + fBinding.AddBitmapToPage(bitmap, imageRect, BPoint(x, y)); + } else { + DBGMSG(("band bitmap is clean.\n")); + } + + if (y >= page_height) { + offset->x = -1.0; + offset->y = -1.0; + } else + offset->y += height; + + DBGMSG(("< nextBand\n")); + return true; + } + catch (TransportException& err) { + BAlert* alert = new BAlert("", err.what(), "OK"); + alert->Go(); + return false; + } +} diff --git a/src/add-ons/print/drivers/gutenprint/GPDriver.h b/src/add-ons/print/drivers/gutenprint/GPDriver.h new file mode 100644 index 0000000000..336d22f049 --- /dev/null +++ b/src/add-ons/print/drivers/gutenprint/GPDriver.h @@ -0,0 +1,43 @@ +/* + * GP.h + * Copyright 1999-2000 Y.Takagi. All Rights Reserved. + */ +#ifndef __GP_H +#define __GP_H + + +#include "GPBinding.h" +#include "GPCapabilities.h" +#include "GraphicsDriver.h" +#include "OutputStream.h" + +class Halftone; + + +class GPDriver : public GraphicsDriver, public OutputStream +{ +public: + GPDriver(BMessage* msg, PrinterData* printer_data, + const PrinterCap* printer_cap); + + void Write(const void *buffer, size_t size) + throw(TransportException); + +protected: + bool startDoc(); + void SetParameter(BString& parameter, PrinterCap::CapID category, + int value); + void SetDriverSpecificSettings(); + void AddDriverSpecificSetting(PrinterCap::CapID category, + const char* key); + bool startPage(int page); + bool nextBand(BBitmap* bitmap, BPoint* offset); + bool endPage(int page); + bool endDoc(bool success); + +private: + GPBinding fBinding; + GPJobConfiguration fConfiguration; +}; + +#endif // __GP_H diff --git a/src/add-ons/print/drivers/gutenprint/GPJob.cpp b/src/add-ons/print/drivers/gutenprint/GPJob.cpp new file mode 100644 index 0000000000..48cb53904a --- /dev/null +++ b/src/add-ons/print/drivers/gutenprint/GPJob.cpp @@ -0,0 +1,503 @@ +/* +* Copyright 2010, Haiku. All rights reserved. +* Distributed under the terms of the MIT License. +* +* Authors: +* Michael Pfeiffer +*/ +#include "GPJob.h" + +#include + + +GPJob::GPJob() + : + fApplicationName(), + fOutputStream(NULL), + fConfiguration(NULL), + fFirstPage(true), + fVariables(NULL), + fBands(NULL), + fCachedBand(NULL), + fWriteError(B_OK) +{ + fImage.init = ImageInit; + fImage.reset = ImageReset; + fImage.width = ImageWidth; + fImage.height = ImageHeight; + fImage.get_row = ImageGetRow; + fImage.get_appname = ImageGetAppname; + fImage.conclude = ImageConclude; + fImage.rep = this; +} + + +GPJob::~GPJob() +{ +} + + +void +GPJob::SetApplicationName(const BString& applicationName) +{ + fApplicationName = applicationName; +} + + +void +GPJob::SetConfiguration(GPJobConfiguration* configuration) +{ + fConfiguration = configuration; +} + + +void +GPJob::SetOutputStream(OutputStream* outputStream) +{ + fOutputStream = outputStream; +} + + +status_t +GPJob::Begin() +{ + fWriteError = B_OK; + + stp_init(); + + fPrinter = stp_get_printer_by_driver(fConfiguration->fDriver); + if (fPrinter == NULL) { + fprintf(stderr, "GPJob Begin: driver %s not found!\n", + fConfiguration->fDriver.String()); + return B_ERROR; + } + + fVariables = stp_vars_create(); + if (fVariables == NULL) { + fprintf(stderr, "GPJob Begin: out of memory\n"); + return B_NO_MEMORY; + } + stp_set_printer_defaults(fVariables, fPrinter); + + stp_set_outfunc(fVariables, OutputFunction); + stp_set_errfunc(fVariables, ErrorFunction); + stp_set_outdata(fVariables, this); + stp_set_errdata(fVariables, this); + + stp_set_string_parameter(fVariables, "PageSize", + fConfiguration->fPageSize); + + if (fConfiguration->fResolution != "") + stp_set_string_parameter(fVariables, "Resolution", + fConfiguration->fResolution); + + stp_set_string_parameter(fVariables, "InputSlot", + fConfiguration->fInputSlot); + + stp_set_string_parameter(fVariables, "PrintingMode", + fConfiguration->fPrintingMode); + + map::iterator it = fConfiguration->fDriverSpecificSettings. + begin(); + for (; it != fConfiguration->fDriverSpecificSettings.end(); it ++) { + stp_set_string_parameter(fVariables, it->first.c_str(), + it->second.c_str()); + } + + stp_set_string_parameter(fVariables, "InputImageType", + "RGB"); + stp_set_string_parameter(fVariables, "ChannelBitDepth", + "8"); + stp_set_float_parameter(fVariables, "Density", + 1.0f); + stp_set_string_parameter(fVariables, "JobMode", "Job"); + + stp_set_printer_defaults_soft(fVariables, fPrinter); + + return B_OK; +} + + +void +GPJob::End() +{ + if (fVariables == NULL) + return; + + if (!fFirstPage) + stp_end_job(fVariables, &fImage); + + stp_vars_destroy(fVariables); + fVariables = NULL; +} + + +static int +gcd(int a, int b) +{ + // Euclidean algorithm for greatest common divisor + while (b != 0) { + int t = b; + b = a % b; + a = t; + } + return a; +} + + +static int +to72dpiFloor(int value, int fromUnit) { + // proper rounding is important in this formula + // do not "optimize" + const int toUnit = 72; + int g = gcd(toUnit, fromUnit); + int n = toUnit / g; + int m = fromUnit / g; + return (value / m) * n; +} + + +static int +to72dpiCeiling(int value, int fromUnit) { + // proper rounding is important in this formula + // do not "optimize" + const int toUnit = 72; + int g = gcd(toUnit, fromUnit); + int n = toUnit / g; + int m = fromUnit / g; + return ((value + m - 1) / m) * n; +} + + +static int +from72dpi(int value, int toUnit) +{ + const int fromUnit = 72; + return value * toUnit / fromUnit; +} + + +status_t +GPJob::PrintPage(list& bands) { + if (fWriteError != B_OK) + return fWriteError; + + fPrintRect = GetPrintRectangle(bands); + fBands = &bands; + fCachedBand = NULL; + + { + int left; + int top; + int right; + int bottom; + stp_get_imageable_area(fVariables, &left, &right, &bottom, &top); + fprintf(stderr, "GPJob imageable area left %d, top %d, right %d, " + "bottom %d\n", + left, top, right, bottom); + + } + + { + int left = (int)fPrintRect.left; + int top = (int)fPrintRect.top; + int width = fPrintRect.IntegerWidth() + 1; + int height = fPrintRect.IntegerHeight() + 1; + + fprintf(stderr, "GPJob raw image dimensions left %d, top %d, width %d, height %d\n", + left, top, width, height); + } + + int xDPI = fConfiguration->fXDPI; + int yDPI = fConfiguration->fYDPI; + + // left, top of the image on the page in 1/72 Inches + int left = static_cast(fPrintRect.left); + left = to72dpiFloor(left, xDPI); + int top = static_cast(fPrintRect.top); + top = to72dpiFloor(top, yDPI); + + // because of rounding in the previous step, + // now the image left, top has to be synchronized + fPrintRect.left = from72dpi(left, xDPI); + fPrintRect.top = from72dpi(top, yDPI); + + // width and height of the image on the page in 1/72 Inches + int width = fPrintRect.IntegerWidth() + 1; + width = to72dpiCeiling(width, xDPI); + int height = fPrintRect.IntegerHeight() + 1; + height = to72dpiCeiling(height, yDPI); + + // synchronize image right and bottom too + fPrintRect.right = fPrintRect.left + from72dpi(width, xDPI); + fPrintRect.bottom = fPrintRect.top + from72dpi(height, yDPI); + + { + int left = (int)fPrintRect.left; + int top = (int)fPrintRect.top; + int width = fPrintRect.IntegerWidth() + 1; + int height = fPrintRect.IntegerHeight() + 1; + + fprintf(stderr, "GPJob image dimensions left %d, top %d, width %d, height %d\n", + left, top, width, height); + } + + fprintf(stderr, "GPJob image dimensions in 1/72 Inches:\n" + "left %d, top %d, width %d, height %d\n", + left, top, width, height); + + stp_set_width(fVariables, width); + stp_set_height(fVariables, height); + stp_set_left(fVariables, left); + stp_set_top(fVariables, top); + + stp_merge_printvars(fVariables, stp_printer_get_defaults(fPrinter)); + + if (!stp_verify(fVariables)) { + // TODO report error + fprintf(stderr, "GPJob PrintPage: invalid variables\n"); + return B_ERROR; + } + + if (fFirstPage) { + fFirstPage = false; + stp_start_job(fVariables, &fImage); + } + + stp_print(fVariables, &fImage); + + return fWriteError; +} + + +BRect +GPJob::GetPrintRectangle(list& bands) +{ + list::iterator it = bands.begin(); + if (it == bands.end()) + return BRect(0, 0, 0, 0); + + GPBand* first = *it; + BRect rect = first->GetBoundingRectangle(); + for (it ++; it != bands.end(); it ++) { + GPBand* band = *it; + rect = rect | band->GetBoundingRectangle(); + } + return rect; +} + + +void +GPJob::Init() +{ + +} + + +void +GPJob::Reset() +{ + +} + + +int +GPJob::Width() +{ + return static_cast(fPrintRect.IntegerWidth() + 1); +} + + +int +GPJob::Height() +{ + return static_cast(fPrintRect.IntegerHeight() + 1); +} + + +stp_image_status_t +GPJob::GetRow(unsigned char* data, size_t size, int row) +{ + if (fWriteError != B_OK) + return STP_IMAGE_STATUS_ABORT; + + // row is relative to left, top of image + // convert it to absolute value + int line = static_cast(fPrintRect.top) + row; + + FillWhite(data, size); + + GPBand* band = FindBand(line); + if (band != NULL) + FillRow(band, data, size, line); + + return STP_IMAGE_STATUS_OK; +} + + +GPBand* +GPJob::FindBand(int line) +{ + if (fCachedBand != NULL && fCachedBand->ContainsLine(line)) + return fCachedBand; + + list::iterator it = fBands->begin(); + for (; it != fBands->end(); it ++) { + GPBand* band = *it; + if (band->ContainsLine(line)) { + fCachedBand = band; + return band; + } + } + + fCachedBand = NULL; + return NULL; +} + + +void +GPJob::FillRow(GPBand* band, unsigned char* data, size_t size, int line) +{ + int imageTop = line - static_cast(band->fWhere.y - + band->fValidRect.top); + int imageLeft = static_cast(band->fValidRect.left); + + const int sourceDelta = band->fBitmap.BytesPerRow(); + const int kSourceBytesPerPixel = 4; // BGRA + const unsigned char* source = + static_cast(band->fBitmap.Bits()) + + imageTop * sourceDelta + + imageLeft * kSourceBytesPerPixel; + + int dataLeft = static_cast(band->fWhere.x - fPrintRect.left); + + const int kTargetBytesPerPixel = 3; // RGB + unsigned char* target = &data[dataLeft * kTargetBytesPerPixel]; + + const int width = band->fValidRect.IntegerWidth() + 1; + ASSERT(0 <= imageTop && imageTop <= band->fValidRect.IntegerHeight()); + ASSERT((dataLeft + width) * kTargetBytesPerPixel <= size); + + for (int i = 0; i < width; i ++) { + target[0] = source[2]; + target[1] = source[1]; + target[2] = source[0]; + target += kTargetBytesPerPixel; + source += kSourceBytesPerPixel; + } +} + + +void +GPJob::FillWhite(unsigned char* data, size_t size) +{ + for (size_t i = 0; i < size; i ++) + data[i] = 0xff; +} + + +const char* +GPJob::GetAppname() +{ + return fApplicationName.String(); +} + + +void +GPJob::Conclude() +{ + // nothing to do +} + + +void +GPJob::Write(const char* data, size_t size) +{ + try { + fOutputStream->Write(data, size); + } catch (TransportException e) { + fWriteError = B_IO_ERROR; + } +} + + +void +GPJob::ReportError(const char* data, size_t size) +{ + // TODO report error in printer add-on + fprintf(stderr, "GPJob Gutenprint Error: %*s\n", (int)size, data); +} + + +void +GPJob::ImageInit(stp_image_t* image) +{ + GPJob* job = static_cast(image->rep); + job->Init(); +} + + +void +GPJob::ImageReset(stp_image_t* image) +{ + GPJob* job = static_cast(image->rep); + job->Reset(); +} + + +int +GPJob::ImageWidth(stp_image_t* image) +{ + GPJob* job = static_cast(image->rep); + return job->Width(); +} + + +int +GPJob::ImageHeight(stp_image_t *image) +{ + GPJob* job = static_cast(image->rep); + return job->Height(); +} + + +stp_image_status_t +GPJob::ImageGetRow(stp_image_t* image, unsigned char* data, size_t size, + int row) +{ + GPJob* job = static_cast(image->rep); + return job->GetRow(data, size, row); +} + + +const char* +GPJob::ImageGetAppname(stp_image_t* image) +{ + GPJob* job = static_cast(image->rep); + return job->GetAppname(); +} + + +void +GPJob::ImageConclude(stp_image_t *image) +{ + GPJob* job = static_cast(image->rep); + job->Conclude(); +} + + +void +GPJob::OutputFunction(void *cookie, const char *data, size_t size) +{ + GPJob* job = static_cast(cookie); + job->Write(data, size); +} + + +void +GPJob::ErrorFunction(void *cookie, const char *data, size_t size) +{ + GPJob* job = static_cast(cookie); + job->ReportError(data, size); +} + diff --git a/src/add-ons/print/drivers/gutenprint/GPJob.h b/src/add-ons/print/drivers/gutenprint/GPJob.h new file mode 100644 index 0000000000..b7f369aafd --- /dev/null +++ b/src/add-ons/print/drivers/gutenprint/GPJob.h @@ -0,0 +1,80 @@ +/* +* Copyright 2010, Haiku. All rights reserved. +* Distributed under the terms of the MIT License. +* +* Authors: +* Michael Pfeiffer +*/ +#ifndef GP_JOB_H +#define GP_JOB_H + +#include + +#include + +#include + +#include "GPBand.h" +#include "GPJobConfiguration.h" +#include "OutputStream.h" + + +class GPJob +{ +public: + GPJob(); + ~GPJob(); + + void SetApplicationName(const BString& applicationName); + void SetConfiguration(GPJobConfiguration* configuration); + void SetOutputStream(OutputStream* outputStream); + + status_t Begin(); + void End(); + + status_t PrintPage(list& bands); + +private: + BRect GetPrintRectangle(list& bands); + GPBand* FindBand(int line); + void FillRow(GPBand* band, unsigned char* data, size_t size, + int line); + void FillWhite(unsigned char* data, size_t size); + + void Init(); + void Reset(); + int Width(); + int Height(); + stp_image_status_t GetRow(unsigned char* data, size_t size, int row); + const char* GetAppname(); + void Conclude(); + void Write(const char* data, size_t size); + void ReportError(const char* data, size_t size); + + static void ImageInit(stp_image_t* image); + static void ImageReset(stp_image_t* image); + static int ImageWidth(stp_image_t* image); + static int ImageHeight(stp_image_t *image); + static stp_image_status_t ImageGetRow(stp_image_t* image, + unsigned char* data, size_t size, int row); + static const char* ImageGetAppname(stp_image_t* image); + static void ImageConclude(stp_image_t *image); + static void OutputFunction(void *cookie, const char *data, + size_t size); + static void ErrorFunction(void *cookie, const char *data, + size_t size); + + BString fApplicationName; + OutputStream* fOutputStream; + GPJobConfiguration* fConfiguration; + + bool fFirstPage; + stp_image_t fImage; + stp_vars_t* fVariables; + const stp_printer_t* fPrinter; + BRect fPrintRect; + list* fBands; + GPBand* fCachedBand; + status_t fWriteError; +}; +#endif diff --git a/src/add-ons/print/drivers/gutenprint/GPJobConfiguration.cpp b/src/add-ons/print/drivers/gutenprint/GPJobConfiguration.cpp new file mode 100644 index 0000000000..00314c6843 --- /dev/null +++ b/src/add-ons/print/drivers/gutenprint/GPJobConfiguration.cpp @@ -0,0 +1,21 @@ +/* +* Copyright 2010, Haiku. All rights reserved. +* Distributed under the terms of the MIT License. +* +* Authors: +* Michael Pfeiffer +*/ +#include "GPJobConfiguration.h" + +GPJobConfiguration::GPJobConfiguration() + : + fDriver(), + fPageSize(), + fResolution(), + fInputSlot(), + fPrintingMode(), + fXDPI(600), + fYDPI(600) +{ +} + diff --git a/src/add-ons/print/drivers/gutenprint/GPJobConfiguration.h b/src/add-ons/print/drivers/gutenprint/GPJobConfiguration.h new file mode 100644 index 0000000000..e40eaa6c8f --- /dev/null +++ b/src/add-ons/print/drivers/gutenprint/GPJobConfiguration.h @@ -0,0 +1,35 @@ +/* +* Copyright 2010, Haiku. All rights reserved. +* Distributed under the terms of the MIT License. +* +* Authors: +* Michael Pfeiffer +*/ +#ifndef GP_JOB_CONFIGURATION_H +#define GP_JOB_CONFIGURATION_H + +#include + +#include +#include + +using namespace std; + +class GPJobConfiguration +{ +public: + GPJobConfiguration(); + + BString fDriver; + BString fPageSize; + BString fResolution; + BString fInputSlot; + BString fPrintingMode; + + int fXDPI; + int fYDPI; + + map fDriverSpecificSettings; +}; + +#endif diff --git a/src/add-ons/print/drivers/gutenprint/GPParameterVisitor.cpp b/src/add-ons/print/drivers/gutenprint/GPParameterVisitor.cpp new file mode 100644 index 0000000000..3bda236f01 --- /dev/null +++ b/src/add-ons/print/drivers/gutenprint/GPParameterVisitor.cpp @@ -0,0 +1,215 @@ +/* +* Copyright 2010, Haiku. All rights reserved. +* Distributed under the terms of the MIT License. +* +* Authors: +* Michael Pfeiffer +*/ +#include "GPParameterVisitor.h" + +#include + + +const char* kJobMode = "JobMode"; +const char* kJob = "Job"; + +const char* kPrintingMode = "PrintingMode"; +const char* kColor = "Color"; +const char* kBlackAndWhite = "BW"; + +const char* kResolution = "Resolution"; +const char* kFakeResolutionKey = ""; + +const char* kPageSize = "PageSize"; + +const char* kChannelBitDepth = "ChannelBitDepth"; + + +GPParameterVisitor::GPParameterVisitor() + : + fVariables(NULL), + fHasResolutionParameter(false) +{ +} + + +GPParameterVisitor::~GPParameterVisitor() +{ +} + + +void +GPParameterVisitor::Visit(const stp_printer_t* printer) +{ + // this code is based on Gutenprint printer_options.c + const stp_vars_t* defaultVariables = stp_printer_get_defaults(printer); + stp_vars_t* variables = stp_vars_create_copy(defaultVariables); + fVariables = variables; + + stp_set_string_parameter(variables, kJobMode, kJob); + + stp_parameter_t printingMode; + stp_describe_parameter(variables, kPrintingMode, &printingMode); + bool isColorPrinter = stp_string_list_is_present(printingMode.bounds.str, + kColor) != 0; + stp_parameter_description_destroy(&printingMode); + + if (isColorPrinter) + stp_set_string_parameter(variables, kPrintingMode, kColor); + else + stp_set_string_parameter(variables, kPrintingMode, kBlackAndWhite); + + stp_set_string_parameter(variables, kChannelBitDepth, "8"); + + stp_parameter_list_t list = stp_get_parameter_list(variables); + int size = stp_parameter_list_count(list); + + for (int i = 0; i < size; i ++) { + const stp_parameter_t* parameter = stp_parameter_list_param(list, i); + stp_parameter_t description; + stp_describe_parameter(fVariables, parameter->name, &description); + VisitParameter(list, parameter, &description); + stp_parameter_description_destroy(&description); + } + + // TODO check if this can really happen + if (!fHasResolutionParameter) { + AddMissingResolution(); + } + + EndVisit(); + + stp_parameter_list_destroy(list); + stp_vars_destroy(variables); + fVariables = NULL; +} + + +void +GPParameterVisitor::AddMissingResolution() +{ + // some printer definitions don't have resolution parameter + // however "libprint" needs to know it for rasterization + + // TODO find out if other parameters influence the resolution + // e.g. color vs black and white + int x, y; + stp_describe_resolution(fVariables, &x, &y); + + BeginParameter(kResolution, "Resolution", STP_PARAMETER_CLASS_FEATURE); + DefaultStringParameter(kResolution, kFakeResolutionKey); + StringParameterSize(kResolution, 1); + + if (x <= 0 || y <= 0) { + // TODO decide if more resolutions (150, 600) should be possible + x = 300; + y = 300; + } + + BString displayName; + if (x != y) + displayName << x << " x " << y << " DPI"; + else + displayName << x << " DPI"; + + ResolutionParameter(kResolution, kFakeResolutionKey, displayName.String(), + x, y); + + EndParameter(kResolution); +} + + +void +GPParameterVisitor::VisitParameter(stp_parameter_list_t list, + const stp_parameter_t* parameter, stp_parameter_t* description) +{ + // TODO decide which parameters should be revealed to user + // e.g. up to STP_PARAMETER_LEVEL_ADVANCED4; + const stp_parameter_level_t kMaxLevel = STP_PARAMETER_LEVEL_BASIC; + stp_parameter_class_t parameterClass = parameter->p_class; + if (parameter->read_only || + (parameter->p_level > kMaxLevel + && strcmp(parameter->name, kResolution) != 0) + || parameterClass != STP_PARAMETER_CLASS_OUTPUT + && parameterClass != STP_PARAMETER_CLASS_CORE + && parameterClass != STP_PARAMETER_CLASS_FEATURE) + return; + + if (!description->is_active) + return; + + switch (description->p_type) { + case STP_PARAMETER_TYPE_STRING_LIST: + if (!BeginParameter(description->name, description->text, + parameterClass)) + return; + VisitStringList(description); + EndParameter(description->name); + break; + + case STP_PARAMETER_TYPE_BOOLEAN: + break; + + case STP_PARAMETER_TYPE_DOUBLE: + break; + + case STP_PARAMETER_TYPE_INT: + break; + + case STP_PARAMETER_TYPE_DIMENSION: + break; + + default: + break; + } + +} + + +void +GPParameterVisitor::VisitStringList(stp_parameter_t* parameter) +{ + stp_string_list_t* list = parameter->bounds.str; + int count = stp_string_list_count(list); + if (count <= 0) + return; + + const char* name = parameter->name; + if (parameter->is_mandatory) + DefaultStringParameter(name, parameter->deflt.str); + else + DefaultStringParameter(name, NULL); + + StringParameterSize(name, count); + + for (int i = 0; i < count; i ++) { + const stp_param_string_t* entry = stp_string_list_param(list, i); + const char* key = entry->name; + const char* displayName = entry->text; + if (strcmp(name, kResolution) == 0) { + stp_set_string_parameter(fVariables, kResolution, key); + + int x, y; + stp_describe_resolution(fVariables, &x, &y); + + ResolutionParameter(name, key, displayName, x, y); + + fHasResolutionParameter = true; + } else if (strcmp(name, kPageSize) == 0) { + stp_set_string_parameter(fVariables, kPageSize, key); + + int width; + int height; + stp_get_media_size(fVariables, &width, &height); + BSize pageSize(width, height); + + int left, right, top, bottom; + stp_get_imageable_area(fVariables, &left, &right, &bottom, &top); + BRect imageableArea(left, top, right, bottom); + + PageSizeParameter(name, key, displayName, pageSize, imageableArea); + } else { + StringParameter(name, key, displayName); + } + } +} diff --git a/src/add-ons/print/drivers/gutenprint/GPParameterVisitor.h b/src/add-ons/print/drivers/gutenprint/GPParameterVisitor.h new file mode 100644 index 0000000000..a9ee90f1a5 --- /dev/null +++ b/src/add-ons/print/drivers/gutenprint/GPParameterVisitor.h @@ -0,0 +1,67 @@ +/* +* Copyright 2010, Haiku. All rights reserved. +* Distributed under the terms of the MIT License. +* +* Authors: +* Michael Pfeiffer +*/ +#ifndef GP_PARAMETER_VISITOR_H +#define GP_PARAMETER_VISITOR_H + +#include + +#include +#include + + +extern const char* kJobMode; +extern const char* kJob; + +extern const char* kPrintingMode; +extern const char* kColor; +extern const char* kBlackAndWhite; + +extern const char* kResolution; +extern const char* kFakeResolutionKey; + +extern const char* kPageSize; + +extern const char* kChannelBitDepth; + + +class GPParameterVisitor +{ +public: + GPParameterVisitor(); + virtual ~GPParameterVisitor(); + + void Visit(const stp_printer_t* printer); + void VisitParameter(stp_parameter_list_t list, + const stp_parameter_t* parameter, stp_parameter_t* description); + void VisitStringList(stp_parameter_t* parameter); + + virtual bool BeginParameter(const char* name, const char* displayName, + stp_parameter_class_t parameterClass) = 0; + // key is null if there is no default value + virtual void DefaultStringParameter(const char* name, + const char* key) = 0; + virtual void StringParameterSize(const char* name, int size) = 0; + virtual void StringParameter(const char* name, const char* key, + const char* displayName) = 0; + virtual void ResolutionParameter(const char* name, const char* key, + const char* displayName, int x, int y) = 0; + virtual void PageSizeParameter(const char* name, const char* key, + const char* displayName, BSize pageSize, + BRect imageableArea) = 0; + virtual void EndParameter(const char* name) = 0; + virtual void EndVisit() = 0; + +private: + void AddMissingResolution(); + + stp_vars_t* fVariables; + bool fHasResolutionParameter; +}; + + +#endif diff --git a/src/add-ons/print/drivers/gutenprint/GPPrinterDriver.cpp b/src/add-ons/print/drivers/gutenprint/GPPrinterDriver.cpp new file mode 100644 index 0000000000..7d237cacc3 --- /dev/null +++ b/src/add-ons/print/drivers/gutenprint/GPPrinterDriver.cpp @@ -0,0 +1,82 @@ +/* + * GPEntry.cpp + * Copyright 1999-2000 Y.Takagi. All Rights Reserved. + * Copyright 2010 Michael Pfeiffer. + */ + + +#include + +#include "GPDriver.h" +#include "GPCapabilities.h" +#include "GPData.h" +#include "PrinterDriver.h" +#include "SelectPrinterDialog.h" + + +class GPPrinterDriver : public PrinterDriver +{ +public: + GPPrinterDriver(BNode* printerFolder) + : + PrinterDriver(printerFolder) + { + } + + const char* GetSignature() const + { + return "application/x-vnd.gutenprint"; + } + + const char* GetDriverName() const + { + return "Gutenprint"; + } + + const char* GetVersion() const + { + return "1.0"; + } + + const char* GetCopyright() const + { + return "Gutenprint driver " + "Copyright © 2010 Michael Pfeiffer.\n"; + } + + char* AddPrinter(char *printerName) + { + GPData* data = dynamic_cast(GetPrinterData()); + ASSERT(data != NULL); + + SelectPrinterDialog* dialog = + new SelectPrinterDialog(data); + + if (dialog->Go() != B_OK) + return NULL; + + return printerName; + } + + PrinterData* InstantiatePrinterData(BNode* node) + { + return new GPData(node); + } + + PrinterCap* InstantiatePrinterCap(PrinterData* printerData) + { + return new GPCapabilities(printerData); + } + + GraphicsDriver* InstantiateGraphicsDriver(BMessage* settings, + PrinterData* printerData, PrinterCap* printerCap) + { + return new GPDriver(settings, printerData, printerCap); + } +}; + + +PrinterDriver* instantiate_printer_driver(BNode* printerFolder) +{ + return new GPPrinterDriver(printerFolder); +} diff --git a/src/add-ons/print/drivers/gutenprint/Gutenprint.rdef b/src/add-ons/print/drivers/gutenprint/Gutenprint.rdef new file mode 100644 index 0000000000..a588edede2 --- /dev/null +++ b/src/add-ons/print/drivers/gutenprint/Gutenprint.rdef @@ -0,0 +1,38 @@ + +resource app_signature "application/x-vnd.gutenprint"; + +resource app_flags B_SINGLE_LAUNCH; + +resource app_version { + major = 0, + middle = 0, + minor = 1, + + variety = B_APPV_DEVELOPMENT, + internal = 0, + + short_info = "Gutenprint add-on", + long_info = "Gutenprint add-on for Haiku\nCopyright 1999 Y.Takagi\nCopyright 2010 Michael Pfeiffer\nAll Rights Reserved." +}; + +resource vector_icon { + $"6E6369660B050002001602B76E71BBF8593D1210B8A7674742A04ABEFB00AEFF" + $"E1053802001603373333B9333339333337333348E54F4B555400FFBFE5FF9B02" + $"00160336C6F3B9284239E397376BB94A71BE484A25005346B5FFFF02001602B5" + $"00003A6000BA6000B500004A2E244AB9D001C0FF9A020116023AA41339C70ABC" + $"27003D026E4ACAB74AC8AB0183FFAD020106023600000000000000003700004A" + $"10004AB0000035FF06FB1E9303020106023600000000000000003700004A1000" + $"4AB00000FFE3E3FFDD05050101000073020116023E1E41BC9E393B21B93C88A6" + $"4824E3485D850090FF3C0B0606BE023A5F485C46584C5E5656525A5656604C58" + $"483A0608EFB6302E302E25372248223A2248465A4A59485B4A59584B41573E58" + $"3F563D543C0608AAFF503A4E3C3231342F302E302E25372248223A2248465A46" + $"5A464C543C4A46543C0606FF06573E583F563D543C543C4A46465A464C465A4A" + $"59485B4A59584B410604DB4A594A4F4A59584B41563F563F4E470A0426484256" + $"4252264406057A0322513A5E42543C58425452B77BC262B77BC262254A080228" + $"5038580A06542A3C22353135324C3B4C3A0202404A3E4C4248434D454B414F02" + $"0332332B3332334B3E4B3E453E3547444E26400F0A090100000A000301060810" + $"01178400040A010102000A0001051001178200040A020105000A030106000A04" + $"0108000A050103000A060104000A08010920251C0A0701092022210A00010730" + $"241C01178100040A00010730221E01178100040A0001071815FF01178100040A" + $"0A010A00" +}; diff --git a/src/add-ons/print/drivers/gutenprint/Jamfile b/src/add-ons/print/drivers/gutenprint/Jamfile new file mode 100644 index 0000000000..e9b76a0f01 --- /dev/null +++ b/src/add-ons/print/drivers/gutenprint/Jamfile @@ -0,0 +1,25 @@ +SubDir HAIKU_TOP src add-ons print drivers gutenprint ; + +SubDirSysHdrs [ FDirName $(HAIKU_TOP) src libs print libgutenprint include ] ; +SubDirHdrs [ FDirName $(HAIKU_TOP) headers libs print libprint ] ; + +AddResources Gutenprint : Gutenprint.rdef ; + +Addon Gutenprint : + GPBand.cpp + GPBinding.cpp + GPCapabilities.cpp + GPCapabilityExtractor.cpp + GPData.cpp + GPDriver.cpp + GPJob.cpp + GPJobConfiguration.cpp + GPParameterVisitor.cpp + GPPrinterDriver.cpp + SelectPrinterDialog.cpp + : + be + libgutenprint.a + libprint.a + $(TARGET_LIBSTDC++) +; diff --git a/src/add-ons/print/drivers/gutenprint/OutputStream.h b/src/add-ons/print/drivers/gutenprint/OutputStream.h new file mode 100644 index 0000000000..f46b81d379 --- /dev/null +++ b/src/add-ons/print/drivers/gutenprint/OutputStream.h @@ -0,0 +1,22 @@ +/* +* Copyright 2010, Haiku. All rights reserved. +* Distributed under the terms of the MIT License. +* +* Authors: +* Michael Pfeiffer +*/ +#ifndef OUTPUT_STREAM_H +#define OUTPUT_STREAM_H + +#include "Transport.h" + + +class OutputStream +{ +public: + virtual void Write(const void *buffer, size_t size) + throw(TransportException) = 0; +}; + + +#endif diff --git a/src/add-ons/print/drivers/gutenprint/SelectPrinterDialog.cpp b/src/add-ons/print/drivers/gutenprint/SelectPrinterDialog.cpp new file mode 100644 index 0000000000..c7e8e7bf41 --- /dev/null +++ b/src/add-ons/print/drivers/gutenprint/SelectPrinterDialog.cpp @@ -0,0 +1,196 @@ +/* +* Copyright 2010, Haiku. All rights reserved. +* Distributed under the terms of the MIT License. +* +* Authors: +* Ithamar R. Adema +* Michael Pfeiffer +*/ + + +#include "SelectPrinterDialog.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "GPBinding.h" + + +enum { + kMsgCancel = 'stop', + kMsgOK = 'okok', + + kMsgManufacturerSelected = 'msel', + kMsgPrinterSelected = 'psel', +}; + + +class StringValueItem : public BStringItem { +public: + StringValueItem(const BString& text, const BString& value) + : + BStringItem(text.String()), + fValue(value) + { + } + + BString fValue; +}; + + +SelectPrinterDialog::SelectPrinterDialog(GPData* data) + : + DialogWindow(BRect(10, 10, 400, 400), + "Select Printer", B_TITLED_WINDOW_LOOK, B_MODAL_APP_WINDOW_FEEL, + B_NOT_MINIMIZABLE | B_NOT_ZOOMABLE | B_ASYNCHRONOUS_CONTROLS), + fData(data) +{ + SetResult(B_ERROR); + + BButton* ok; + BButton* 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(kMsgManufacturerSelected)); + PopulateManufacturers(); + + // Build the layout + SetLayout(new BGroupLayout(B_VERTICAL)); + + AddChild(BGroupLayoutBuilder(B_VERTICAL, 10) + .AddGroup(B_HORIZONTAL, 5, 1.0f) + .Add(manuScroller) + .Add(printerScroller) + .End() + .AddGroup(B_HORIZONTAL, 5, 2.0f) + .AddGlue() + .Add(cancel) + .Add(ok) + .End() + .SetInsets(10, 10, 10, 10) + ); +} + + +void +SelectPrinterDialog::PopulateManufacturers() +{ + BMessage manufacturers; + GPBinding binding; + binding.GetPrinterManufacturers(manufacturers); + + BString id; + BString displayName; + for (int32 index = 0; binding.ExtractManufacturer(manufacturers, index, id, + displayName); index ++) { + fManufacturersListView->AddItem(new StringValueItem(id, displayName)); + } +} + + +void +SelectPrinterDialog::PopulatePrinters() +{ + BString manufacturer = GetSelectedItemValue(fManufacturersListView).String(); + if (manufacturer.Length() == 0) + return; + + BMessage models; + GPBinding binding; + binding.GetPrinterModels(manufacturer, models); + + BString displayName; + BString driver; + for (int32 index = 0; binding.ExtractModel(models, index, displayName, driver); + index ++) { + StringValueItem* item = new StringValueItem(displayName, driver); + fPrintersListView->AddItem(item); + } +} + + +BString +SelectPrinterDialog::GetSelectedItemValue(BListView* listView) +{ + int32 index = listView->CurrentSelection(); + + // Bail out if no manufacturer is selected + if (index < 0) + return ""; + BListItem* item = listView->ItemAt(index); + StringValueItem* valueItem = dynamic_cast(item); + ASSERT(valueItem != NULL); + + return valueItem->fValue; +} + +void +SelectPrinterDialog::PrinterSelected() +{ + int32 index = fPrintersListView->CurrentSelection(); + fOKButton->SetEnabled(index >= 0); +} + + +void +SelectPrinterDialog::Save() +{ + BString driverName = GetSelectedItemValue(fPrintersListView); + fData->fGutenprintDriverName = driverName; + fData->save(); +} + + +void +SelectPrinterDialog::MessageReceived(BMessage* msg) +{ + switch (msg->what) { + case kMsgManufacturerSelected: + fPrintersListView->MakeEmpty(); + PopulatePrinters(); + PrinterSelected(); + 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/gutenprint/SelectPrinterDialog.h b/src/add-ons/print/drivers/gutenprint/SelectPrinterDialog.h new file mode 100644 index 0000000000..b083f028e2 --- /dev/null +++ b/src/add-ons/print/drivers/gutenprint/SelectPrinterDialog.h @@ -0,0 +1,35 @@ +#ifndef SELECT_PRINTER_DIALOG_H +#define SELECT_PRINTER_DIALOG_H + + +#include + +#include "DialogWindow.h" +#include "GPData.h" + + +class BListView; +class BButton; +class PSData; + + +class SelectPrinterDialog : public DialogWindow { +public: + SelectPrinterDialog(GPData* data); + + void MessageReceived(BMessage* msg); +private: + void PopulateManufacturers(); + void PopulatePrinters(); + BString GetSelectedItemValue(BListView* listView); + void PrinterSelected(); + void Save(); + + BListView* fManufacturersListView; + BListView* fPrintersListView; + BButton* fOKButton; + + GPData* fData; +}; + +#endif // SELECTPPDDLG_H