1/*
2* Copyright 2010, Haiku. All rights reserved.
3* Distributed under the terms of the MIT License.
4*
5* Authors:
6*		Michael Pfeiffer
7*/
8#include "GPBinding.h"
9
10#include <list>
11#include <set>
12#include <string>
13
14#include <gutenprint/gutenprint.h>
15
16
17#include "GPCapabilityExtractor.h"
18
19using namespace std;
20
21
22// printer manufacturer
23static const char* kManufacturerId = "id";
24static const char* kManufacturerDisplayName = "name";
25
26// printer model
27static const char* kModelDisplayName = "model";
28static const char* kModelDriver = "driver";
29
30
31GPBinding::GPBinding()
32:
33fInitialized(false),
34fOutputStream(NULL)
35{
36
37}
38
39
40GPBinding::~GPBinding()
41{
42	DeleteBands();
43}
44
45
46status_t
47GPBinding::GetPrinterManufacturers(BMessage& manufacturers)
48{
49	InitGutenprint();
50
51	list<string> ids;
52	set<string> manufacturerSet;
53
54	for (int i = 0; i < stp_printer_model_count(); i ++) {
55		const stp_printer_t* printer = stp_get_printer_by_index(i);
56		string manufacturer = stp_printer_get_manufacturer(printer);
57
58		// ignore unnamed manufacturers
59		if (manufacturer == "")
60			continue;
61
62		// add manufacturer only once
63		if (manufacturerSet.find(manufacturer) != manufacturerSet.end())
64			continue;
65
66		manufacturerSet.insert(manufacturer);
67
68		ids.push_back(manufacturer);
69	}
70
71	ids.sort();
72
73	list<string>::iterator it = ids.begin();
74	for (; it != ids.end(); it ++) {
75		string manufacturer = *it;
76		const char* id = manufacturer.c_str();
77		const char* name = manufacturer.c_str();
78		AddManufacturer(manufacturers, id, name);
79	}
80	return B_OK;
81}
82
83
84bool
85GPBinding::ExtractManufacturer(const BMessage& manufacturers, int32 index,
86	BString& id, BString& displayName)
87{
88	if (manufacturers.FindString(kManufacturerId, index, &id) != B_OK)
89		return false;
90	if (manufacturers.FindString(kManufacturerDisplayName, index, &displayName)
91		!= B_OK)
92		return false;
93	return true;
94}
95
96
97void
98GPBinding::AddManufacturer(BMessage& manufacturers, const char* id,
99	const char* displayName)
100{
101	manufacturers.AddString(kManufacturerId, id);
102	manufacturers.AddString(kManufacturerDisplayName, displayName);
103}
104
105
106status_t
107GPBinding::GetPrinterModels(const char* manufacturer, BMessage& models)
108{
109	for (int i = 0; i < stp_printer_model_count(); i ++) {
110		const stp_printer_t* printer = stp_get_printer_by_index(i);
111		if (strcmp(manufacturer, stp_printer_get_manufacturer(printer)) != 0)
112			continue;
113
114		const char* displayName = stp_printer_get_long_name(printer);
115		const char* driver = stp_printer_get_driver(printer);
116		AddModel(models, displayName, driver);
117	}
118	return B_OK;
119}
120
121
122bool
123GPBinding::ExtractModel(const BMessage& models, int32 index, BString& displayName,
124	BString& driver)
125{
126	if (models.FindString(kModelDisplayName, index, &displayName) != B_OK)
127		return false;
128	if (models.FindString(kModelDriver, index, &driver) != B_OK)
129		return false;
130	return true;
131}
132
133
134void
135GPBinding::AddModel(BMessage& models, const char* displayName,	const char* driver)
136{
137	models.AddString(kModelDisplayName, displayName);
138	models.AddString(kModelDriver, driver);
139}
140
141
142status_t
143GPBinding::GetCapabilities(const char* driver, GPCapabilities* capabilities)
144{
145	InitGutenprint();
146	const stp_printer_t* printer = stp_get_printer_by_driver(driver);
147	if (printer == NULL)
148		return B_ERROR;
149
150	GPCapabilityExtractor extractor(capabilities);
151	extractor.Visit(printer);
152	return B_OK;
153}
154
155
156status_t
157GPBinding::BeginJob(GPJobConfiguration* configuration,
158	OutputStream* outputStream)
159{
160	fOutputStream = outputStream;
161	fJob.SetApplicationName("Gutenprint");
162	fJob.SetConfiguration(configuration);
163	fJob.SetOutputStream(outputStream);
164
165	return fJob.Begin();
166}
167
168
169void
170GPBinding::EndJob()
171{
172	fJob.End();
173	fOutputStream = NULL;
174}
175
176
177void
178GPBinding::BeginPage()
179{
180}
181
182
183void
184GPBinding::EndPage()
185{
186	status_t status = fJob.PrintPage(fBands);
187	DeleteBands();
188	if (status == B_IO_ERROR)
189		throw TransportException("I/O Error");
190	if (status == B_ERROR) {
191		BString message;
192		fJob.GetErrorMessage(message);
193		throw TransportException(message.String());
194	}
195}
196
197
198status_t
199GPBinding::AddBitmapToPage(BBitmap* bitmap, BRect validRect, BPoint where)
200{
201	GPBand* band = new(nothrow) GPBand(bitmap, validRect, where);
202	if (band == NULL) {
203		return B_NO_MEMORY;
204	}
205
206	fBands.push_back(band);
207	return B_OK;
208}
209
210
211void
212GPBinding::InitGutenprint()
213{
214	if (fInitialized)
215		return;
216	fInitialized = true;
217	// there is no "destroy" counter part so this creates memory leaks
218	// this is no problem because the print server loads printer add-ons
219	// in a new application instance that is terminated when not used anymore
220	stp_init();
221	stp_set_output_codeset("UTF-8");
222}
223
224
225void
226GPBinding::DeleteBands()
227{
228	list<GPBand*>::iterator it = fBands.begin();
229	for (; it != fBands.end(); it ++) {
230		GPBand* band = *it;
231		delete band;
232	}
233	fBands.clear();
234}
235