xref: /haiku/src/libs/print/libprint/JobSetupDlg.cpp (revision a7dde370f552f5376edbf25046ec9cf2ba8bbd1a)
1 /*
2  * JobSetupDlg.cpp
3  * Copyright 1999-2000 Y.Takagi. All Rights Reserved.
4  */
5 
6 #include <cstdio>
7 #include <cstring>
8 #include <cstdlib>
9 #include <string>
10 #include <fcntl.h>
11 #include <unistd.h>
12 #include <sys/stat.h>
13 #include <math.h>
14 
15 #include <Alert.h>
16 #include <Bitmap.h>
17 #include <Box.h>
18 #include <Button.h>
19 #include <CheckBox.h>
20 #include <GridView.h>
21 #include <GroupLayout.h>
22 #include <GroupLayoutBuilder.h>
23 #include <Looper.h>
24 #include <MessageFilter.h>
25 #include <MenuField.h>
26 #include <MenuItem.h>
27 #include <Message.h>
28 #include <Point.h>
29 #include <PopUpMenu.h>
30 #include <PrintJob.h>
31 #include <RadioButton.h>
32 #include <Rect.h>
33 #include <Slider.h>
34 #include <String.h>
35 #include <TextControl.h>
36 #include <TextView.h>
37 #include <View.h>
38 
39 #include "HalftoneView.h"
40 #include "JobSetupDlg.h"
41 #include "JobData.h"
42 #include "JSDSlider.h"
43 #include "PagesView.h"
44 #include "PrinterData.h"
45 #include "PrinterCap.h"
46 #include "DbgMsg.h"
47 
48 
49 using namespace std;
50 
51 
52 struct NupCap : public BaseCap {
53 	NupCap(const string &label, bool isDefault, int nup)
54 		:
55 		BaseCap(label, isDefault),
56 		fNup(nup)
57 	{}
58 
59 	int	fNup;
60 };
61 
62 
63 struct DitherCap : public BaseCap {
64 	DitherCap(const string &label, bool isDefault,
65 		Halftone::DitherType ditherType)
66 		:
67 		BaseCap(label, isDefault),
68 		fDitherType(ditherType)
69 	{}
70 
71 	Halftone::DitherType fDitherType;
72 };
73 
74 
75 static const NupCap gNup1("1", true,  1);
76 static const NupCap gNup2("2",   false, 2);
77 static const NupCap gNup4("4",   false, 4);
78 static const NupCap gNup8("8",   false, 8);
79 static const NupCap gNup9("9",   false, 9);
80 static const NupCap gNup16("16", false, 16);
81 static const NupCap gNup25("25", false, 25);
82 static const NupCap gNup32("32", false, 32);
83 static const NupCap gNup36("36", false, 36);
84 
85 
86 static const DitherCap gDitherType1("Crosshatch", false, Halftone::kType1);
87 static const DitherCap gDitherType2("Grid", false, Halftone::kType2);
88 static const DitherCap gDitherType3("Stipple", false, Halftone::kType3);
89 static const DitherCap gDitherFloydSteinberg("Floyd-Steinberg", false,
90 	Halftone::kTypeFloydSteinberg);
91 
92 
93 const NupCap *gNups[] = {
94 	&gNup1,
95 	&gNup2,
96 	&gNup4,
97 	&gNup8,
98 	&gNup9,
99 	&gNup16,
100 	&gNup25,
101 	&gNup32,
102 	&gNup36
103 };
104 
105 
106 const DitherCap *gDitherTypes[] = {
107 	&gDitherType1,
108 	&gDitherType2,
109 	&gDitherType3,
110 	&gDitherFloydSteinberg
111 };
112 
113 
114 enum {
115 	kMsgRangeAll = 'JSdl',
116 	kMsgRangeSelection,
117 	kMsgPreview,
118 	kMsgCancel,
119 	kMsgOK,
120 	kMsgQuality,
121 	kMsgCollateChanged,
122 	kMsgReverseChanged,
123 	kMsgDuplexChanged,
124 };
125 
126 
127 JobSetupView::JobSetupView(JobData *job_data, PrinterData *printer_data,
128 	const PrinterCap *printer_cap)
129 	:
130 	BView("jobSetup", B_WILL_DRAW),
131 	fJobData(job_data),
132 	fPrinterData(printer_data),
133 	fPrinterCap(printer_cap)
134 {
135 	SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
136 }
137 
138 
139 BRadioButton*
140 JobSetupView::CreatePageSelectionItem(const char* name, const char* label,
141 	JobData::PageSelection pageSelection)
142 {
143 	BRadioButton* button = new BRadioButton(name, label, NULL);
144 	if (fJobData->getPageSelection() == pageSelection) {
145 		button->SetValue(B_CONTROL_ON);
146 	}
147 	return button;
148 }
149 
150 
151 void
152 JobSetupView::AllowOnlyDigits(BTextView* textView, int maxDigits)
153 {
154 	int num;
155 	for (num = 0; num <= 255; num++) {
156 		textView->DisallowChar(num);
157 	}
158 	for (num = 0; num <= 9; num++) {
159 		textView->AllowChar('0' + num);
160 	}
161 	textView->SetMaxBytes(maxDigits);
162 }
163 
164 
165 void
166 JobSetupView::AttachedToWindow()
167 {
168 	// quality
169 	BBox* qualityBox = new BBox("quality");
170 	qualityBox->SetLabel("Quality");
171 
172 	// color
173 	fColorType = new BPopUpMenu("color");
174 	fColorType->SetRadioMode(true);
175 
176 	int count = fPrinterCap->countCap(PrinterCap::kColor);
177 	const ColorCap **color_cap = (const ColorCap **)fPrinterCap->enumCap(
178 		PrinterCap::kColor);
179 	bool marked = false;
180 	BMenuItem* item = NULL;
181 	while (count--) {
182 		item = new BMenuItem((*color_cap)->fLabel.c_str(),
183 			new BMessage(kMsgQuality));
184 		fColorType->AddItem(item);
185 		if ((*color_cap)->fColor == fJobData->getColor()) {
186 			item->SetMarked(true);
187 			marked = true;
188 		}
189 		color_cap++;
190 	}
191 	if (!marked && item)
192 		item->SetMarked(true);
193 
194 	BMenuField* colorMenuField = new BMenuField("color", "Color:", fColorType);
195 	fColorType->SetTargetForItems(this);
196 
197 	// dither type
198 	fDitherType = new BPopUpMenu("");
199 	fDitherType->SetRadioMode(true);
200 
201 	count = sizeof(gDitherTypes) / sizeof(gDitherTypes[0]);
202 	const DitherCap **dither_cap = gDitherTypes;
203 	marked = false;
204 	item = NULL;
205 	while (count--) {
206 		item = new BMenuItem((*dither_cap)->fLabel.c_str(),
207 			new BMessage(kMsgQuality));
208 		fDitherType->AddItem(item);
209 		if ((*dither_cap)->fDitherType == fJobData->getDitherType()) {
210 			item->SetMarked(true);
211 			marked = true;
212 		}
213 		dither_cap++;
214 	}
215 	if (!marked && item)
216 		item->SetMarked(true);
217 	BMenuField* ditherMenuField = new BMenuField("dithering", "Dot Pattern:",
218 		fDitherType);
219 	fDitherType->SetTargetForItems(this);
220 
221 	// halftone preview view
222 	BBox* halftoneBox = new BBox("halftoneBox");
223 	halftoneBox->SetBorder(B_PLAIN_BORDER);
224 
225 	// TODO make layout compatible
226 	BSize size(240, 14 * 4);
227 	BRect rect(0, 0, size.width, size.height);
228 	fHalftone = new HalftoneView(rect, "halftone",
229 		B_FOLLOW_ALL, B_WILL_DRAW);
230 	fHalftone->SetExplicitMinSize(size);
231 	fHalftone->SetExplicitMaxSize(size);
232 
233 	// gamma
234 	fGamma = new JSDSlider("gamma", "Gamma", new BMessage(kMsgQuality),
235 		-300, 300);
236 
237 	fGamma->SetLimitLabels("Lighter", "Darker");
238 	fGamma->SetValue((int32)(100 * log(fJobData->getGamma()) / log(2.0)));
239 	fGamma->SetHashMarks(B_HASH_MARKS_BOTH);
240 	fGamma->SetHashMarkCount(7);
241 	fGamma->SetModificationMessage(new BMessage(kMsgQuality));
242 	fGamma->SetTarget(this);
243 
244 	// ink density
245 	fInkDensity = new JSDSlider("inkDensity", "Ink Usage",
246 		new BMessage(kMsgQuality), 0, 127);
247 
248 	fInkDensity->SetLimitLabels("Min", "Max");
249 	fInkDensity->SetValue((int32)fJobData->getInkDensity());
250 	fInkDensity->SetHashMarks(B_HASH_MARKS_BOTH);
251 	fInkDensity->SetHashMarkCount(10);
252 	fInkDensity->SetModificationMessage(new BMessage(kMsgQuality));
253 	fInkDensity->SetTarget(this);
254 
255 	// page range
256 
257 	BBox* pageRangeBox = new BBox("pageRange");
258 	pageRangeBox->SetLabel("Page Range");
259 
260 	fAll = new BRadioButton("all", "Print all Pages", new BMessage(kMsgRangeAll));
261 
262 	BRadioButton *range = new BRadioButton("selection", "Print selected Pages:",
263 		new BMessage(kMsgRangeSelection));
264 
265 	fFromPage = new BTextControl("from", "From:", "", NULL);
266 	fFromPage->SetAlignment(B_ALIGN_LEFT, B_ALIGN_RIGHT);
267 	AllowOnlyDigits(fFromPage->TextView(), 6);
268 
269 	fToPage = new BTextControl("to", "To:", "", NULL);
270 	fToPage->SetAlignment(B_ALIGN_LEFT, B_ALIGN_RIGHT);
271 	AllowOnlyDigits(fToPage->TextView(), 6);
272 
273 	int first_page = fJobData->getFirstPage();
274 	int last_page  = fJobData->getLastPage();
275 
276 	if (first_page <= 1 && last_page <= 0) {
277 		fAll->SetValue(B_CONTROL_ON);
278 	} else {
279 		range->SetValue(B_CONTROL_ON);
280 		if (first_page < 1)
281 			first_page = 1;
282 		if (first_page > last_page)
283 			last_page = -1;
284 
285 		BString oss1;
286 		oss1 << first_page;
287 		fFromPage->SetText(oss1.String());
288 
289 		BString oss2;
290 		oss2 << last_page;
291 		fToPage->SetText(oss2.String());
292 	}
293 
294 	fAll->SetTarget(this);
295 	range->SetTarget(this);
296 
297 	// paper source
298 	fPaperFeed = new BPopUpMenu("");
299 	fPaperFeed->SetRadioMode(true);
300 	count = fPrinterCap->countCap(PrinterCap::kPaperSource);
301 	const PaperSourceCap **paper_source_cap =
302 		(const PaperSourceCap **)fPrinterCap->enumCap(PrinterCap::kPaperSource);
303 	marked = false;
304 	item = NULL;
305 	while (count--) {
306 		item = new BMenuItem((*paper_source_cap)->fLabel.c_str(), NULL);
307 		fPaperFeed->AddItem(item);
308 		if ((*paper_source_cap)->fPaperSource == fJobData->getPaperSource()) {
309 			item->SetMarked(true);
310 			marked = true;
311 		}
312 		paper_source_cap++;
313 	}
314 	if (!marked)
315 		item->SetMarked(true);
316 	BMenuField* paperSourceMenufield = new BMenuField("paperSource",
317 		"Paper Source:", fPaperFeed);
318 
319 	// Pages per sheet
320 	fNup = new BPopUpMenu("");
321 	fNup->SetRadioMode(true);
322 	count = sizeof(gNups) / sizeof(gNups[0]);
323 	const NupCap **nup_cap = gNups;
324 	marked = false;
325 	item = NULL;
326 	while (count--) {
327 		item = new BMenuItem((*nup_cap)->fLabel.c_str(), NULL);
328 		fNup->AddItem(item);
329 		if ((*nup_cap)->fNup == fJobData->getNup()) {
330 			item->SetMarked(true);
331 			marked = true;
332 		}
333 		nup_cap++;
334 	}
335 	if (!marked)
336 		item->SetMarked(true);
337 	BMenuField* pagesPerSheet = new BMenuField("pagesPerSheet",
338 		"Pages Per Sheet:", fNup);
339 
340 	// duplex
341 	if (fPrinterCap->isSupport(PrinterCap::kPrintStyle)) {
342 		fDuplex = new BCheckBox("duplex", "Duplex",
343 			new BMessage(kMsgDuplexChanged));
344 		if (fJobData->getPrintStyle() != JobData::kSimplex) {
345 			fDuplex->SetValue(B_CONTROL_ON);
346 		}
347 		fDuplex->SetTarget(this);
348 	} else {
349 		fDuplex = NULL;
350 	}
351 
352 	// copies
353 	fCopies = new BTextControl("copies", "Number of Copies:", "", NULL);
354 	AllowOnlyDigits(fCopies->TextView(), 3);
355 
356 	BString copies;
357 	copies << fJobData->getCopies();
358 	fCopies->SetText(copies.String());
359 
360 	// collate
361 	fCollate = new BCheckBox("collate", "Collate",
362 		new BMessage(kMsgCollateChanged));
363 	if (fJobData->getCollate()) {
364 		fCollate->SetValue(B_CONTROL_ON);
365 	}
366 	fCollate->SetTarget(this);
367 
368 	// reverse
369 	fReverse = new BCheckBox("reverse", "Reverse Order",
370 		new BMessage(kMsgReverseChanged));
371 	if (fJobData->getReverse()) {
372 		fReverse->SetValue(B_CONTROL_ON);
373 	}
374 	fReverse->SetTarget(this);
375 
376 	// pages view
377 	// TODO make layout API compatible
378 	fPages = new PagesView(BRect(0, 0, 150, 40), "pages", B_FOLLOW_ALL,
379 		B_WILL_DRAW);
380 	fPages->setCollate(fJobData->getCollate());
381 	fPages->setReverse(fJobData->getReverse());
382 	fPages->SetExplicitMinSize(BSize(150, 40));
383 	fPages->SetExplicitMaxSize(BSize(150, 40));
384 
385 	// page selection
386 	BBox* pageSelectionBox = new BBox("pageSelection");
387 	pageSelectionBox->SetLabel("Page Selection");
388 
389 	fAllPages = CreatePageSelectionItem("allPages", "All Pages",
390 		JobData::kAllPages);
391 	fOddNumberedPages = CreatePageSelectionItem("oddPages",
392 		"Odd-Numbered Pages", JobData::kOddNumberedPages);
393 	fEvenNumberedPages = CreatePageSelectionItem("evenPages",
394 		"Even-Numbered Pages", JobData::kEvenNumberedPages);
395 
396 	// separator line
397 	BBox *separator = new BBox("separator");
398 	separator->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, 1));
399 
400 	// buttons
401 	BButton* preview = new BButton("preview", "Preview" B_UTF8_ELLIPSIS,
402 		new BMessage(kMsgPreview));
403 	BButton* cancel = new BButton("cancel", "Cancel",
404 		new BMessage(kMsgCancel));
405 	BButton* ok = new BButton("ok", "OK", new BMessage(kMsgOK));
406 	ok->MakeDefault(true);
407 
408 	BGroupView* halftoneGroup = new BGroupView(B_VERTICAL, 0);
409 	BGroupLayout* halftoneLayout = halftoneGroup->GroupLayout();
410 	halftoneLayout->AddView(fHalftone);
411 	halftoneBox->AddChild(halftoneGroup);
412 
413 	BGridView* qualityGrid = new BGridView();
414 	BGridLayout* qualityGridLayout = qualityGrid->GridLayout();
415 	qualityGridLayout->AddItem(colorMenuField->CreateLabelLayoutItem(), 0, 0);
416 	qualityGridLayout->AddItem(colorMenuField->CreateMenuBarLayoutItem(), 1, 0);
417 	qualityGridLayout->AddItem(ditherMenuField->CreateLabelLayoutItem(), 0, 1);
418 	qualityGridLayout->AddItem(ditherMenuField->CreateMenuBarLayoutItem(), 1,
419 		1);
420 	qualityGridLayout->AddView(fGamma, 0, 2, 2);
421 	qualityGridLayout->AddView(fInkDensity, 0, 3, 2);
422 	qualityGridLayout->AddView(halftoneBox, 0, 4, 2);
423 	qualityGridLayout->SetSpacing(0, 0);
424 	qualityGridLayout->SetInsets(5, 5, 5, 5);
425 	qualityBox->AddChild(qualityGrid);
426 
427 	BGridView* pageRangeGrid = new BGridView();
428 	BGridLayout* pageRangeLayout = pageRangeGrid->GridLayout();
429 	pageRangeLayout->AddItem(fFromPage->CreateLabelLayoutItem(), 0, 0);
430 	pageRangeLayout->AddItem(fFromPage->CreateTextViewLayoutItem(), 1, 0);
431 	pageRangeLayout->AddItem(fToPage->CreateLabelLayoutItem(), 0, 1);
432 	pageRangeLayout->AddItem(fToPage->CreateTextViewLayoutItem(), 1, 1);
433 	pageRangeLayout->SetInsets(0, 0, 0, 0);
434 	pageRangeLayout->SetSpacing(0, 0);
435 
436 	BGroupView* pageRangeGroup = new BGroupView(B_VERTICAL, 0);
437 	BGroupLayout* pageRangeGroupLayout = pageRangeGroup->GroupLayout();
438 	pageRangeGroupLayout->AddView(fAll);
439 	pageRangeGroupLayout->AddView(range);
440 	pageRangeGroupLayout->AddView(pageRangeGrid);
441 	pageRangeGroupLayout->SetInsets(5, 5, 5, 5);
442 	pageRangeBox->AddChild(pageRangeGroup);
443 
444 	BGridView* settings = new BGridView();
445 	BGridLayout* settingsLayout = settings->GridLayout();
446 	settingsLayout->AddItem(paperSourceMenufield->CreateLabelLayoutItem(), 0,
447 		0);
448 	settingsLayout->AddItem(paperSourceMenufield->CreateMenuBarLayoutItem(), 1,
449 		0);
450 	settingsLayout->AddItem(pagesPerSheet->CreateLabelLayoutItem(), 0, 1);
451 	settingsLayout->AddItem(pagesPerSheet->CreateMenuBarLayoutItem(), 1, 1);
452 	int row = 2;
453 	if (fDuplex != NULL) {
454 		settingsLayout->AddView(fDuplex, 0, row, 2);
455 		row ++;
456 	}
457 	settingsLayout->AddItem(fCopies->CreateLabelLayoutItem(), 0, row);
458 	settingsLayout->AddItem(fCopies->CreateTextViewLayoutItem(), 1, row);
459 	settingsLayout->SetSpacing(0, 0);
460 
461 
462 	BGroupView* pageSelectionGroup = new BGroupView(B_VERTICAL, 0);
463 	BGroupLayout* groupLayout = pageSelectionGroup->GroupLayout();
464 	groupLayout->AddView(fAllPages);
465 	groupLayout->AddView(fOddNumberedPages);
466 	groupLayout->AddView(fEvenNumberedPages);
467 	groupLayout->SetInsets(5, 5, 5, 5);
468 	pageSelectionBox->AddChild(pageSelectionGroup);
469 
470 	SetLayout(new BGroupLayout(B_VERTICAL));
471 	AddChild(BGroupLayoutBuilder(B_VERTICAL, 0)
472 		.AddGroup(B_HORIZONTAL, 10, 1.0f)
473 			.AddGroup(B_VERTICAL, 10, 1.0f)
474 				.Add(qualityBox)
475 				.Add(pageRangeBox)
476 				.AddGlue()
477 			.End()
478 			.AddGroup(B_VERTICAL, 0, 1.0f)
479 				.Add(settings)
480 				.AddStrut(5)
481 				.Add(fCollate)
482 				.Add(fReverse)
483 				.Add(fPages)
484 				.AddStrut(5)
485 				.Add(pageSelectionBox)
486 				.AddGlue()
487 			.End()
488 		.End()
489 		.AddGlue()
490 		.Add(separator)
491 		.AddGroup(B_HORIZONTAL, 10, 1.0f)
492 			.AddGlue()
493 			.Add(cancel)
494 			.Add(preview)
495 			.Add(ok)
496 		.End()
497 		.SetInsets(0, 0, 0, 0)
498 	);
499 
500 	fHalftone->preview(fJobData->getGamma(), fJobData->getInkDensity(),
501 		fJobData->getDitherType(), fJobData->getColor() != JobData::kMonochrome);
502 
503 	UpdateButtonEnabledState();
504 }
505 
506 
507 void
508 JobSetupView::UpdateButtonEnabledState()
509 {
510 	bool pageRangeEnabled = fAll->Value() != B_CONTROL_ON;
511 	fFromPage->SetEnabled(pageRangeEnabled);
512 	fToPage->SetEnabled(pageRangeEnabled);
513 
514 	bool pageSelectionEnabled = fDuplex == NULL ||
515 		fDuplex->Value() != B_CONTROL_ON;
516 	fAllPages->SetEnabled(pageSelectionEnabled);
517 	fOddNumberedPages->SetEnabled(pageSelectionEnabled);
518 	fEvenNumberedPages->SetEnabled(pageSelectionEnabled);
519 }
520 
521 
522 void
523 JobSetupView::MessageReceived(BMessage *msg)
524 {
525 	switch (msg->what) {
526 	case kMsgRangeAll:
527 	case kMsgRangeSelection:
528 	case kMsgDuplexChanged:
529 		UpdateButtonEnabledState();
530 		break;
531 
532 	case kMsgQuality:
533 		fHalftone->preview(getGamma(), getInkDensity(), getDitherType(), getColor() != JobData::kMonochrome);
534 		break;
535 
536 	case kMsgCollateChanged:
537 		fPages->setCollate(fCollate->Value() == B_CONTROL_ON);
538 		break;
539 
540 	case kMsgReverseChanged:
541 		fPages->setReverse(fReverse->Value() == B_CONTROL_ON);
542 		break;
543 	}
544 }
545 
546 
547 JobData::Color
548 JobSetupView::getColor()
549 {
550 	int count = fPrinterCap->countCap(PrinterCap::kColor);
551 	const ColorCap **color_cap = (const ColorCap**)fPrinterCap->enumCap(PrinterCap::kColor);
552 	const char *color_label = fColorType->FindMarked()->Label();
553 	while (count--) {
554 		if (!strcmp((*color_cap)->fLabel.c_str(), color_label)) {
555 			return (*color_cap)->fColor;
556 		}
557 		color_cap++;
558 	}
559 	return JobData::kMonochrome;
560 }
561 
562 
563 Halftone::DitherType
564 JobSetupView::getDitherType()
565 {
566 	int count = sizeof(gDitherTypes) / sizeof(gDitherTypes[0]);
567 	const DitherCap **dither_cap = gDitherTypes;
568 	const char *dithering_label = fDitherType->FindMarked()->Label();
569 	while (count --) {
570 		if (strcmp((*dither_cap)->fLabel.c_str(), dithering_label) == 0) {
571 			return (*dither_cap)->fDitherType;
572 		}
573 		dither_cap ++;
574 	}
575 	return Halftone::kTypeFloydSteinberg;
576 }
577 
578 float
579 JobSetupView::getGamma()
580 {
581 	const float value = (float)fGamma->Value();
582 	return pow(2.0, value / 100.0);
583 }
584 
585 
586 float
587 JobSetupView::getInkDensity()
588 {
589 	const float value = (float)(127 - fInkDensity->Value());
590 	return value;
591 }
592 
593 
594 bool
595 JobSetupView::UpdateJobData(bool showPreview)
596 {
597 	int count;
598 
599 	fJobData->setShowPreview(showPreview);
600 	fJobData->setColor(getColor());
601 	fJobData->setGamma(getGamma());
602 	fJobData->setInkDensity(getInkDensity());
603 	fJobData->setDitherType(getDitherType());
604 
605 	int first_page;
606 	int last_page;
607 
608 	if (B_CONTROL_ON == fAll->Value()) {
609 		first_page = 1;
610 		last_page  = -1;
611 	} else {
612 		first_page = atoi(fFromPage->Text());
613 		last_page  = atoi(fToPage->Text());
614 	}
615 
616 	fJobData->setFirstPage(first_page);
617 	fJobData->setLastPage(last_page);
618 
619 	count = fPrinterCap->countCap(PrinterCap::kPaperSource);
620 	const PaperSourceCap **paper_source_cap = (const PaperSourceCap **)fPrinterCap->enumCap(PrinterCap::kPaperSource);
621 	const char *paper_source_label = fPaperFeed->FindMarked()->Label();
622 	while (count--) {
623 		if (!strcmp((*paper_source_cap)->fLabel.c_str(), paper_source_label)) {
624 			fJobData->setPaperSource((*paper_source_cap)->fPaperSource);
625 			break;
626 		}
627 		paper_source_cap++;
628 	}
629 
630 	count = sizeof(gNups) / sizeof(gNups[0]);
631 	const NupCap **nup_cap = gNups;
632 	const char *nup_label = fNup->FindMarked()->Label();
633 	while (count--) {
634 		if (!strcmp((*nup_cap)->fLabel.c_str(), nup_label)) {
635 			fJobData->setNup((*nup_cap)->fNup);
636 			break;
637 		}
638 		nup_cap++;
639 	}
640 
641 	if (fPrinterCap->isSupport(PrinterCap::kPrintStyle)) {
642 		fJobData->setPrintStyle((B_CONTROL_ON == fDuplex->Value()) ? JobData::kDuplex : JobData::kSimplex);
643 	}
644 
645 	fJobData->setCopies(atoi(fCopies->Text()));
646 
647 	fJobData->setCollate((B_CONTROL_ON == fCollate->Value()) ? true : false);
648 	fJobData->setReverse((B_CONTROL_ON == fReverse->Value()) ? true : false);
649 
650 	JobData::PageSelection pageSelection = JobData::kAllPages;
651 	if (fOddNumberedPages->Value() == B_CONTROL_ON)
652 		pageSelection = JobData::kOddNumberedPages;
653 	if (fEvenNumberedPages->Value() == B_CONTROL_ON)
654 		pageSelection = JobData::kEvenNumberedPages;
655 	fJobData->setPageSelection(pageSelection);
656 
657 	fJobData->save();
658 	return true;
659 }
660 
661 
662 JobSetupDlg::JobSetupDlg(JobData *job_data, PrinterData *printer_data,
663 	const PrinterCap *printer_cap)
664 	:
665 	DialogWindow(BRect(100, 100, 200, 200), "PrintJob Setup",
666 		B_TITLED_WINDOW_LOOK, B_MODAL_APP_WINDOW_FEEL,
667 		B_NOT_RESIZABLE | B_NOT_MINIMIZABLE | B_NOT_ZOOMABLE
668 			| B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS)
669 {
670 	SetResult(B_ERROR);
671 	AddShortcut('W', B_COMMAND_KEY, new BMessage(B_QUIT_REQUESTED));
672 
673 	fJobSetup = new JobSetupView(job_data, printer_data, printer_cap);
674 	SetLayout(new BGroupLayout(B_VERTICAL));
675 	AddChild(BGroupLayoutBuilder(B_VERTICAL, 0)
676 		.Add(fJobSetup)
677 		.SetInsets(10, 10, 10, 10)
678 	);
679 }
680 
681 
682 void
683 JobSetupDlg::MessageReceived(BMessage *msg)
684 {
685 	switch (msg->what) {
686 	case kMsgOK:
687 	case kMsgPreview:
688 		fJobSetup->UpdateJobData(msg->what == kMsgPreview);
689 		SetResult(B_NO_ERROR);
690 		PostMessage(B_QUIT_REQUESTED);
691 		break;
692 
693 	case kMsgCancel:
694 		PostMessage(B_QUIT_REQUESTED);
695 		break;
696 
697 	default:
698 		DialogWindow::MessageReceived(msg);
699 		break;
700 	}
701 }
702