1/*
2 * GP.cpp
3 * Copyright 1999-2000 Y.Takagi. All Rights Reserved.
4 * Copyright 2010 Michael Pfeiffer.
5 */
6
7
8#include "GPDriver.h"
9
10#include <memory>
11
12#include <Alert.h>
13#include <Bitmap.h>
14#include <Debug.h>
15#include <File.h>
16
17#include "DbgMsg.h"
18#include "Halftone.h"
19#include "JobData.h"
20#include "PackBits.h"
21#include "GPCapabilities.h"
22#include "GPData.h"
23#include "PrinterData.h"
24#include "UIDriver.h"
25#include "ValidRect.h"
26
27
28using namespace std;
29
30
31GPDriver::GPDriver(BMessage* message, PrinterData* printerData,
32	const PrinterCap* printerCap)
33	:
34	GraphicsDriver(message, printerData, printerCap)
35{
36}
37
38void
39GPDriver::Write(const void* buffer, size_t size)
40{
41	WriteSpoolData(buffer, size);
42}
43
44bool
45GPDriver::StartDocument()
46{
47	try {
48		const GPData* data = dynamic_cast<const GPData*>(GetPrinterData());
49		ASSERT(data != NULL);
50		fConfiguration.fDriver = data->fGutenprintDriverName;
51
52		SetParameter(fConfiguration.fPageSize, PrinterCap::kPaper,
53			GetJobData()->GetPaper());
54
55		SetParameter(fConfiguration.fResolution, PrinterCap::kResolution,
56			GetJobData()->GetResolutionID());
57
58		fConfiguration.fXDPI = GetJobData()->GetXres();
59		fConfiguration.fYDPI = GetJobData()->GetYres();
60
61		SetParameter(fConfiguration.fInputSlot, PrinterCap::kPaperSource,
62			GetJobData()->GetPaperSource());
63
64		SetParameter(fConfiguration.fPrintingMode, PrinterCap::kColor,
65			GetJobData()->GetColor());
66
67		if (GetPrinterCap()->Supports(PrinterCap::kDriverSpecificCapabilities))
68			SetDriverSpecificSettings();
69
70		fprintf(stderr, "Driver: %s\n", fConfiguration.fDriver.String());
71		fprintf(stderr, "PageSize %s\n", fConfiguration.fPageSize.String());
72		fprintf(stderr, "Resolution %s\n", fConfiguration.fResolution.String());
73		fprintf(stderr, "InputSlot %s\n", fConfiguration.fInputSlot.String());
74		fprintf(stderr, "PrintingMode %s\n", fConfiguration.fPrintingMode.String());
75
76		return fBinding.BeginJob(&fConfiguration, this) == B_OK;
77	}
78	catch (TransportException& err) {
79		return false;
80	}
81}
82
83
84void
85GPDriver::SetParameter(BString& parameter, PrinterCap::CapID category,
86	int value)
87{
88	const EnumCap* capability;
89	capability = GetPrinterCap()->FindCap(category, value);
90	if (capability != NULL && capability->fKey != "")
91		parameter = capability->Key();
92}
93
94
95void
96GPDriver::SetDriverSpecificSettings()
97{
98	PrinterCap::CapID category = PrinterCap::kDriverSpecificCapabilities;
99	int count = GetPrinterCap()->CountCap(category);
100	const BaseCap** capabilities = GetPrinterCap()->GetCaps(category);
101	for (int i = 0; i < count; i++) {
102		const DriverSpecificCap* capability =
103			dynamic_cast<const DriverSpecificCap*>(capabilities[i]);
104		if (capability == NULL) {
105			fprintf(stderr, "Internal error: DriverSpecificCap name='%s' "
106				"has wrong type!\n", capabilities[i]->Label());
107			continue;
108		}
109
110		PrinterCap::CapID id = static_cast<PrinterCap::CapID>(capability->ID());
111		const char* key = capability->fKey.c_str();
112		switch (capability->fType) {
113			case DriverSpecificCap::kList:
114				AddDriverSpecificSetting(id, key);
115				break;
116			case DriverSpecificCap::kBoolean:
117				AddDriverSpecificBooleanSetting(id, key);
118				break;
119			case DriverSpecificCap::kIntRange:
120				AddDriverSpecificIntSetting(id, key);
121				break;
122			case DriverSpecificCap::kIntDimension:
123				AddDriverSpecificDimensionSetting(id, key);
124				break;
125			case DriverSpecificCap::kDoubleRange:
126				AddDriverSpecificDoubleSetting(id, key);
127				break;
128		}
129	}
130}
131
132
133void
134GPDriver::AddDriverSpecificSetting(PrinterCap::CapID category, const char* key) {
135	const EnumCap* capability = NULL;
136	if (GetJobData()->Settings().HasString(key))
137	{
138		const string& value = GetJobData()->Settings().GetString(key);
139		capability = GetPrinterCap()->FindCapWithKey(category, value.c_str());
140	}
141
142	if (capability == NULL) {
143		// job data should contain a value;
144		// try to use the default value anyway
145		capability = GetPrinterCap()->GetDefaultCap(category);
146	}
147
148	if (capability == NULL) {
149		// should not reach here!
150		return;
151	}
152
153	fConfiguration.fStringSettings[key] = capability->fKey;
154}
155
156
157void
158GPDriver::AddDriverSpecificBooleanSetting(PrinterCap::CapID category,
159	const char* key) {
160	if (GetJobData()->Settings().HasBoolean(key))
161		fConfiguration.fBooleanSettings[key] =
162			GetJobData()->Settings().GetBoolean(key);
163}
164
165
166void
167GPDriver::AddDriverSpecificIntSetting(PrinterCap::CapID category,
168	const char* key) {
169	if (GetJobData()->Settings().HasInt(key))
170		fConfiguration.fIntSettings[key] =
171			GetJobData()->Settings().GetInt(key);
172}
173
174
175void
176GPDriver::AddDriverSpecificDimensionSetting(PrinterCap::CapID category,
177	const char* key) {
178	if (GetJobData()->Settings().HasInt(key))
179		fConfiguration.fDimensionSettings[key] =
180			GetJobData()->Settings().GetInt(key);
181}
182
183
184void
185GPDriver::AddDriverSpecificDoubleSetting(PrinterCap::CapID category,
186	const char* key) {
187	if (GetJobData()->Settings().HasDouble(key))
188		fConfiguration.fDoubleSettings[key] =
189			GetJobData()->Settings().GetDouble(key);
190}
191
192
193bool
194GPDriver::StartPage(int)
195{
196	fBinding.BeginPage();
197	return true;
198}
199
200
201bool
202GPDriver::EndPage(int)
203{
204	try {
205		fBinding.EndPage();
206		return true;
207	}
208	catch (TransportException& err) {
209		ShowError(err.What());
210		return false;
211	}
212}
213
214
215bool
216GPDriver::EndDocument(bool)
217{
218	try {
219		fBinding.EndJob();
220		return true;
221	}
222	catch (TransportException& err) {
223		ShowError(err.What());
224		return false;
225	}
226}
227
228
229bool
230GPDriver::NextBand(BBitmap* bitmap, BPoint* offset)
231{
232	DBGMSG(("> nextBand\n"));
233	try {
234		BRect bounds = bitmap->Bounds();
235
236		RECT rc;
237		rc.left = (int)bounds.left;
238		rc.top = (int)bounds.top;
239		rc.right = (int)bounds.right;
240		rc.bottom = (int)bounds.bottom;
241
242		int height = rc.bottom - rc.top + 1;
243
244		int x = (int)offset->x;
245		int y = (int)offset->y;
246
247		int pageHeight = GetPageHeight();
248
249		if (y + height > pageHeight)
250			height = pageHeight - y;
251
252		rc.bottom = height - 1;
253
254		DBGMSG(("height = %d\n", height));
255		DBGMSG(("x = %d\n", x));
256		DBGMSG(("y = %d\n", y));
257
258		if (get_valid_rect(bitmap, &rc)) {
259
260			DBGMSG(("validate rect = %d, %d, %d, %d\n",
261				rc.left, rc.top, rc.right, rc.bottom));
262
263			x = rc.left;
264			y += rc.top;
265
266			int width = rc.right - rc.left + 1;
267			int height = rc.bottom - rc.top + 1;
268			fprintf(stderr, "GPDriver nextBand x %d, y %d, width %d,"
269				" height %d\n",
270				x, y, width, height);
271			BRect imageRect(rc.left, rc.top, rc.right, rc.bottom);
272			status_t status;
273			status = fBinding.AddBitmapToPage(bitmap, imageRect, BPoint(x, y));
274			if (status == B_NO_MEMORY) {
275				ShowError("Out of memory");
276				return false;
277			} else if (status != B_OK) {
278				ShowError("Unknown error");
279				return false;
280			}
281
282		} else {
283			DBGMSG(("band bitmap is empty.\n"));
284		}
285
286		if (y >= pageHeight) {
287			offset->x = -1.0;
288			offset->y = -1.0;
289		} else
290			offset->y += height;
291
292		DBGMSG(("< nextBand\n"));
293		return true;
294	}
295	catch (TransportException& err) {
296		ShowError(err.What());
297		return false;
298	}
299}
300
301
302void
303GPDriver::ShowError(const char* message)
304{
305	BString text;
306	text << "An error occurred attempting to print with Gutenprint:";
307	text << "\n";
308	text << message;
309	BAlert* alert = new BAlert("", text.String(), "OK");
310	alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
311	alert->Go();
312}
313