vfs: check userland buffers before reading them.
[haiku.git] / src / libs / print / libprint / JobSetupDlg.cpp
blobecc95f04b6179a87488f609a7d959a1a7e43bfce
1 /*
2 * JobSetupDlg.cpp
3 * Copyright 1999-2000 Y.Takagi. All Rights Reserved.
4 */
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>
15 #include <Alert.h>
16 #include <Bitmap.h>
17 #include <Box.h>
18 #include <Button.h>
19 #include <CheckBox.h>
20 #include <Debug.h>
21 #include <GridView.h>
22 #include <GroupLayout.h>
23 #include <GroupLayoutBuilder.h>
24 #include <Looper.h>
25 #include <MessageFilter.h>
26 #include <MenuField.h>
27 #include <MenuItem.h>
28 #include <Message.h>
29 #include <Point.h>
30 #include <PopUpMenu.h>
31 #include <PrintJob.h>
32 #include <RadioButton.h>
33 #include <Rect.h>
34 #include <Slider.h>
35 #include <String.h>
36 #include <TextControl.h>
37 #include <TextView.h>
38 #include <View.h>
40 #include "HalftoneView.h"
41 #include "JobSetupDlg.h"
42 #include "JobData.h"
43 #include "JSDSlider.h"
44 #include "PagesView.h"
45 #include "PrinterData.h"
46 #include "PrinterCap.h"
47 #include "DbgMsg.h"
50 using namespace std;
53 struct NupCap : public EnumCap {
54 NupCap(const string &label, bool isDefault, int nup)
56 EnumCap(label, isDefault),
57 fNup(nup)
60 int32 ID() const { return fNup; }
62 int fNup;
66 struct DitherCap : public EnumCap {
67 DitherCap(const string &label, bool isDefault,
68 Halftone::DitherType ditherType)
70 EnumCap(label, isDefault),
71 fDitherType(ditherType)
74 int32 ID() const { return fDitherType; }
76 Halftone::DitherType fDitherType;
80 static const NupCap gNup1("1", true, 1);
81 static const NupCap gNup2("2", false, 2);
82 static const NupCap gNup4("4", false, 4);
83 static const NupCap gNup8("8", false, 8);
84 static const NupCap gNup9("9", false, 9);
85 static const NupCap gNup16("16", false, 16);
86 static const NupCap gNup25("25", false, 25);
87 static const NupCap gNup32("32", false, 32);
88 static const NupCap gNup36("36", false, 36);
91 static const DitherCap gDitherType1("Crosshatch", false, Halftone::kType1);
92 static const DitherCap gDitherType2("Grid", false, Halftone::kType2);
93 static const DitherCap gDitherType3("Stipple", false, Halftone::kType3);
94 static const DitherCap gDitherFloydSteinberg("Floyd-Steinberg", false,
95 Halftone::kTypeFloydSteinberg);
98 const BaseCap *gNups[] = {
99 &gNup1,
100 &gNup2,
101 &gNup4,
102 &gNup8,
103 &gNup9,
104 &gNup16,
105 &gNup25,
106 &gNup32,
107 &gNup36
111 const BaseCap *gDitherTypes[] = {
112 &gDitherType1,
113 &gDitherType2,
114 &gDitherType3,
115 &gDitherFloydSteinberg
119 static const char* kCategoryID = "id";
122 enum {
123 kMsgRangeAll = 'JSdl',
124 kMsgRangeSelection,
125 kMsgCancel,
126 kMsgOK,
127 kMsgQuality,
128 kMsgCollateChanged,
129 kMsgReverseChanged,
130 kMsgDuplexChanged,
131 kMsgIntSliderChanged,
132 kMsgDoubleSliderChanged,
133 kMsgNone = 0
137 JobSetupView::JobSetupView(JobData* jobData, PrinterData* printerData,
138 const PrinterCap *printerCap)
140 BView("jobSetup", B_WILL_DRAW),
141 fCopies(NULL),
142 fFromPage(NULL),
143 fToPage(NULL),
144 fJobData(jobData),
145 fPrinterData(printerData),
146 fPrinterCap(printerCap),
147 fColorType(NULL),
148 fDitherType(NULL),
149 fGamma(NULL),
150 fInkDensity(NULL),
151 fHalftone(NULL),
152 fAll(NULL),
153 fCollate(NULL),
154 fReverse(NULL),
155 fPages(NULL),
156 fPaperFeed(NULL),
157 fDuplex(NULL),
158 fNup(NULL),
159 fAllPages(NULL),
160 fOddNumberedPages(NULL),
161 fEvenNumberedPages(NULL)
163 SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
167 BRadioButton*
168 JobSetupView::CreatePageSelectionItem(const char* name, const char* label,
169 JobData::PageSelection pageSelection)
171 BRadioButton* button = new BRadioButton(name, label, NULL);
172 if (fJobData->GetPageSelection() == pageSelection) {
173 button->SetValue(B_CONTROL_ON);
175 return button;
179 void
180 JobSetupView::AllowOnlyDigits(BTextView* textView, int maxDigits)
182 int num;
183 for (num = 0; num <= 255; num++) {
184 textView->DisallowChar(num);
186 for (num = 0; num <= 9; num++) {
187 textView->AllowChar('0' + num);
189 textView->SetMaxBytes(maxDigits);
193 void
194 JobSetupView::AttachedToWindow()
196 // quality
197 BBox* qualityBox = new BBox("quality");
198 qualityBox->SetLabel("Quality");
200 // color
201 fColorType = new BPopUpMenu("color");
202 fColorType->SetRadioMode(true);
203 FillCapabilityMenu(fColorType, kMsgQuality, PrinterCap::kColor,
204 fJobData->GetColor());
205 BMenuField* colorMenuField = new BMenuField("color", "Color:", fColorType);
206 fColorType->SetTargetForItems(this);
208 if (IsHalftoneConfigurationNeeded())
209 CreateHalftoneConfigurationUI();
211 // page range
213 BBox* pageRangeBox = new BBox("pageRange");
214 pageRangeBox->SetLabel("Page range");
216 fAll = new BRadioButton("all", "Print all Pages", new BMessage(kMsgRangeAll));
218 BRadioButton *range = new BRadioButton("selection", "Print selected Pages:",
219 new BMessage(kMsgRangeSelection));
221 fFromPage = new BTextControl("from", "From:", "", NULL);
222 fFromPage->SetAlignment(B_ALIGN_LEFT, B_ALIGN_RIGHT);
223 AllowOnlyDigits(fFromPage->TextView(), 6);
225 fToPage = new BTextControl("to", "To:", "", NULL);
226 fToPage->SetAlignment(B_ALIGN_LEFT, B_ALIGN_RIGHT);
227 AllowOnlyDigits(fToPage->TextView(), 6);
229 int first_page = fJobData->GetFirstPage();
230 int last_page = fJobData->GetLastPage();
232 if (first_page <= 1 && last_page <= 0) {
233 fAll->SetValue(B_CONTROL_ON);
234 } else {
235 range->SetValue(B_CONTROL_ON);
236 if (first_page < 1)
237 first_page = 1;
238 if (first_page > last_page)
239 last_page = -1;
241 BString oss1;
242 oss1 << first_page;
243 fFromPage->SetText(oss1.String());
245 BString oss2;
246 oss2 << last_page;
247 fToPage->SetText(oss2.String());
250 fAll->SetTarget(this);
251 range->SetTarget(this);
253 // paper source
254 fPaperFeed = new BPopUpMenu("");
255 fPaperFeed->SetRadioMode(true);
256 FillCapabilityMenu(fPaperFeed, kMsgNone, PrinterCap::kPaperSource,
257 fJobData->GetPaperSource());
258 BMenuField* paperSourceMenufield = new BMenuField("paperSource",
259 "Paper source:", fPaperFeed);
261 // Pages per sheet
262 fNup = new BPopUpMenu("");
263 fNup->SetRadioMode(true);
264 FillCapabilityMenu(fNup, kMsgNone, gNups,
265 sizeof(gNups) / sizeof(gNups[0]), (int)fJobData->GetNup());
266 BMenuField* pagesPerSheet = new BMenuField("pagesPerSheet",
267 "Pages per sheet:", fNup);
269 // duplex
270 if (fPrinterCap->Supports(PrinterCap::kPrintStyle)) {
271 fDuplex = new BCheckBox("duplex", "Duplex",
272 new BMessage(kMsgDuplexChanged));
273 if (fJobData->GetPrintStyle() != JobData::kSimplex) {
274 fDuplex->SetValue(B_CONTROL_ON);
276 fDuplex->SetTarget(this);
277 } else {
278 fDuplex = NULL;
281 // copies
282 fCopies = new BTextControl("copies", "Number of copies:", "", NULL);
283 AllowOnlyDigits(fCopies->TextView(), 3);
285 BString copies;
286 copies << fJobData->GetCopies();
287 fCopies->SetText(copies.String());
289 // collate
290 fCollate = new BCheckBox("collate", "Collate",
291 new BMessage(kMsgCollateChanged));
292 if (fJobData->GetCollate()) {
293 fCollate->SetValue(B_CONTROL_ON);
295 fCollate->SetTarget(this);
297 // reverse
298 fReverse = new BCheckBox("reverse", "Reverse order",
299 new BMessage(kMsgReverseChanged));
300 if (fJobData->GetReverse()) {
301 fReverse->SetValue(B_CONTROL_ON);
303 fReverse->SetTarget(this);
305 // pages view
306 // TODO make layout API compatible
307 fPages = new PagesView(BRect(0, 0, 150, 40), "pages", B_FOLLOW_ALL,
308 B_WILL_DRAW);
309 fPages->SetCollate(fJobData->GetCollate());
310 fPages->SetReverse(fJobData->GetReverse());
311 fPages->SetExplicitMinSize(BSize(150, 40));
312 fPages->SetExplicitMaxSize(BSize(150, 40));
314 // page selection
315 BBox* pageSelectionBox = new BBox("pageSelection");
316 pageSelectionBox->SetLabel("Page selection");
318 fAllPages = CreatePageSelectionItem("allPages", "All pages",
319 JobData::kAllPages);
320 fOddNumberedPages = CreatePageSelectionItem("oddPages",
321 "Odd-numbered pages", JobData::kOddNumberedPages);
322 fEvenNumberedPages = CreatePageSelectionItem("evenPages",
323 "Even-numbered pages", JobData::kEvenNumberedPages);
325 fPreview = new BCheckBox("preview", "Show preview before printing", NULL);
326 if (fJobData->GetShowPreview())
327 fPreview->SetValue(B_CONTROL_ON);
329 // separator line
330 BBox *separator = new BBox("separator");
331 separator->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, 1));
333 // buttons
334 BButton* cancel = new BButton("cancel", "Cancel",
335 new BMessage(kMsgCancel));
336 BButton* ok = new BButton("ok", "OK", new BMessage(kMsgOK));
337 ok->MakeDefault(true);
339 if (IsHalftoneConfigurationNeeded()) {
340 BGroupView* halftoneGroup = new BGroupView(B_VERTICAL, 0);
341 BGroupLayout* halftoneLayout = halftoneGroup->GroupLayout();
342 halftoneLayout->AddView(fHalftone);
343 fHalftoneBox->AddChild(halftoneGroup);
346 BGridView* qualityGrid = new BGridView();
347 BGridLayout* qualityGridLayout = qualityGrid->GridLayout();
348 qualityGridLayout->AddItem(colorMenuField->CreateLabelLayoutItem(), 0, 0);
349 qualityGridLayout->AddItem(colorMenuField->CreateMenuBarLayoutItem(), 1, 0);
350 if (IsHalftoneConfigurationNeeded()) {
351 qualityGridLayout->AddItem(fDitherMenuField->CreateLabelLayoutItem(),
352 0, 1);
353 qualityGridLayout->AddItem(fDitherMenuField->CreateMenuBarLayoutItem(),
354 1, 1);
355 qualityGridLayout->AddView(fGamma, 0, 2, 2);
356 qualityGridLayout->AddView(fInkDensity, 0, 3, 2);
357 qualityGridLayout->AddView(fHalftoneBox, 0, 4, 2);
358 } else {
359 AddDriverSpecificSettings(qualityGridLayout, 1);
361 qualityGridLayout->SetSpacing(0, 0);
362 qualityGridLayout->SetInsets(5, 5, 5, 5);
363 qualityBox->AddChild(qualityGrid);
364 // TODO put qualityGrid in a scroll view
365 // the layout of the box surrounding the scroll view using the following
366 // code is not correct; the box still has the size of the qualityGird;
367 // and the scroll view is vertically centered inside the box!
368 //BScrollView* qualityScroller = new BScrollView("qualityScroller",
369 // qualityGrid, 0, false, true);
370 //qualityScroller->SetExplicitMaxSize(BSize(500, 500));
371 //qualityBox->AddChild(qualityScroller);
373 BGridView* pageRangeGrid = new BGridView();
374 BGridLayout* pageRangeLayout = pageRangeGrid->GridLayout();
375 pageRangeLayout->AddItem(fFromPage->CreateLabelLayoutItem(), 0, 0);
376 pageRangeLayout->AddItem(fFromPage->CreateTextViewLayoutItem(), 1, 0);
377 pageRangeLayout->AddItem(fToPage->CreateLabelLayoutItem(), 0, 1);
378 pageRangeLayout->AddItem(fToPage->CreateTextViewLayoutItem(), 1, 1);
379 pageRangeLayout->SetInsets(0, 0, 0, 0);
380 pageRangeLayout->SetSpacing(0, 0);
382 BGroupView* pageRangeGroup = new BGroupView(B_VERTICAL, 0);
383 BGroupLayout* pageRangeGroupLayout = pageRangeGroup->GroupLayout();
384 pageRangeGroupLayout->AddView(fAll);
385 pageRangeGroupLayout->AddView(range);
386 pageRangeGroupLayout->AddView(pageRangeGrid);
387 pageRangeGroupLayout->SetInsets(5, 5, 5, 5);
388 pageRangeBox->AddChild(pageRangeGroup);
390 BGridView* settings = new BGridView();
391 BGridLayout* settingsLayout = settings->GridLayout();
392 settingsLayout->AddItem(paperSourceMenufield->CreateLabelLayoutItem(), 0,
394 settingsLayout->AddItem(paperSourceMenufield->CreateMenuBarLayoutItem(), 1,
396 settingsLayout->AddItem(pagesPerSheet->CreateLabelLayoutItem(), 0, 1);
397 settingsLayout->AddItem(pagesPerSheet->CreateMenuBarLayoutItem(), 1, 1);
398 int row = 2;
399 if (fDuplex != NULL) {
400 settingsLayout->AddView(fDuplex, 0, row, 2);
401 row ++;
403 settingsLayout->AddItem(fCopies->CreateLabelLayoutItem(), 0, row);
404 settingsLayout->AddItem(fCopies->CreateTextViewLayoutItem(), 1, row);
405 settingsLayout->SetSpacing(0, 0);
408 BGroupView* pageSelectionGroup = new BGroupView(B_VERTICAL, 0);
409 BGroupLayout* groupLayout = pageSelectionGroup->GroupLayout();
410 groupLayout->AddView(fAllPages);
411 groupLayout->AddView(fOddNumberedPages);
412 groupLayout->AddView(fEvenNumberedPages);
413 groupLayout->SetInsets(5, 5, 5, 5);
414 pageSelectionBox->AddChild(pageSelectionGroup);
416 SetLayout(new BGroupLayout(B_VERTICAL));
417 AddChild(BGroupLayoutBuilder(B_VERTICAL, 0)
418 .AddGroup(B_HORIZONTAL, 10, 1.0f)
419 .AddGroup(B_VERTICAL, 10, 1.0f)
420 .Add(qualityBox)
421 .Add(pageRangeBox)
422 .AddGlue()
423 .End()
424 .AddGroup(B_VERTICAL, 0, 1.0f)
425 .Add(settings)
426 .AddStrut(5)
427 .Add(fCollate)
428 .Add(fReverse)
429 .Add(fPages)
430 .AddStrut(5)
431 .Add(pageSelectionBox)
432 .AddGlue()
433 .End()
434 .End()
435 .Add(fPreview)
436 .AddGlue()
437 .Add(separator)
438 .AddGroup(B_HORIZONTAL, 10, 1.0f)
439 .AddGlue()
440 .Add(cancel)
441 .Add(ok)
442 .End()
443 .SetInsets(0, 0, 0, 0)
446 UpdateHalftonePreview();
448 UpdateButtonEnabledState();
452 bool
453 JobSetupView::IsHalftoneConfigurationNeeded()
455 return fPrinterCap->Supports(PrinterCap::kHalftone);
459 void
460 JobSetupView::CreateHalftoneConfigurationUI()
462 // dither type
463 fDitherType = new BPopUpMenu("");
464 fDitherType->SetRadioMode(true);
465 FillCapabilityMenu(fDitherType, kMsgQuality, gDitherTypes,
466 sizeof(gDitherTypes) / sizeof(gDitherTypes[0]),
467 (int)fJobData->GetDitherType());
468 fDitherMenuField = new BMenuField("dithering", "Dot Pattern:",
469 fDitherType);
470 fDitherType->SetTargetForItems(this);
472 // halftone preview view
473 fHalftoneBox = new BBox("halftoneBox");
474 fHalftoneBox->SetBorder(B_PLAIN_BORDER);
476 // TODO make layout compatible
477 BSize size(240, 14 * 4);
478 BRect rect(0, 0, size.width, size.height);
479 fHalftone = new HalftoneView(rect, "halftone",
480 B_FOLLOW_ALL, B_WILL_DRAW);
481 fHalftone->SetExplicitMinSize(size);
482 fHalftone->SetExplicitMaxSize(size);
484 // gamma
485 fGamma = new JSDSlider("gamma", "Gamma", new BMessage(kMsgQuality),
486 -300, 300);
488 fGamma->SetLimitLabels("Lighter", "Darker");
489 fGamma->SetValue((int32)(100 * log(fJobData->GetGamma()) / log(2.0)));
490 fGamma->SetHashMarks(B_HASH_MARKS_BOTH);
491 fGamma->SetHashMarkCount(7);
492 fGamma->SetModificationMessage(new BMessage(kMsgQuality));
493 fGamma->SetTarget(this);
495 // ink density
496 fInkDensity = new JSDSlider("inkDensity", "Ink usage",
497 new BMessage(kMsgQuality), 0, 127);
499 fInkDensity->SetLimitLabels("Min", "Max");
500 fInkDensity->SetValue((int32)fJobData->GetInkDensity());
501 fInkDensity->SetHashMarks(B_HASH_MARKS_BOTH);
502 fInkDensity->SetHashMarkCount(10);
503 fInkDensity->SetModificationMessage(new BMessage(kMsgQuality));
504 fInkDensity->SetTarget(this);
508 void
509 JobSetupView::AddDriverSpecificSettings(BGridLayout* gridLayout, int row)
511 if (!fPrinterCap->Supports(PrinterCap::kDriverSpecificCapabilities))
512 return;
514 int count = fPrinterCap->CountCap(PrinterCap::kDriverSpecificCapabilities);
515 const BaseCap** capabilities = fPrinterCap->GetCaps(
516 PrinterCap::kDriverSpecificCapabilities);
518 for (int i = 0; i < count; i ++) {
519 const DriverSpecificCap* capability =
520 static_cast<const DriverSpecificCap*>(capabilities[i]);
522 switch (capability->fType) {
523 case DriverSpecificCap::kList:
524 AddPopUpMenu(capability, gridLayout, row);
525 break;
526 case DriverSpecificCap::kBoolean:
527 AddCheckBox(capability, gridLayout, row);
528 break;
529 case DriverSpecificCap::kIntRange:
530 case DriverSpecificCap::kIntDimension:
531 AddIntSlider(capability, gridLayout, row);
532 break;
533 case DriverSpecificCap::kDoubleRange:
534 AddDoubleSlider(capability, gridLayout, row);
535 break;
542 void
543 JobSetupView::AddPopUpMenu(const DriverSpecificCap* capability,
544 BGridLayout* gridLayout, int& row)
546 const char* label = capability->fLabel.c_str();
547 BPopUpMenu* popUpMenu = new BPopUpMenu(label);
548 popUpMenu->SetRadioMode(true);
550 PrinterCap::CapID category = static_cast<PrinterCap::CapID>(
551 capability->ID());
553 const BaseCap** categoryCapabilities = fPrinterCap->GetCaps(category);
555 int categoryCount = fPrinterCap->CountCap(category);
557 string value = GetDriverSpecificValue(category, capability->Key());
558 PrinterCap::KeyPredicate predicate(value.c_str());
560 FillCapabilityMenu(popUpMenu, kMsgNone, categoryCapabilities,
561 categoryCount, predicate);
563 BString menuLabel = label;
564 menuLabel << ":";
565 BMenuField* menuField = new BMenuField(label, menuLabel.String(),
566 popUpMenu);
567 popUpMenu->SetTargetForItems(this);
569 gridLayout->AddItem(menuField->CreateLabelLayoutItem(),
570 0, row);
571 gridLayout->AddItem(menuField->CreateMenuBarLayoutItem(),
572 1, row);
573 row ++;
575 fDriverSpecificPopUpMenus[category] = popUpMenu;
579 void
580 JobSetupView::AddCheckBox(const DriverSpecificCap* capability,
581 BGridLayout* gridLayout, int& row)
583 PrinterCap::CapID category = static_cast<PrinterCap::CapID>(
584 capability->ID());
585 const BooleanCap* booleanCap = fPrinterCap->FindBooleanCap(category);
586 if (booleanCap == NULL) {
587 fprintf(stderr, "Internal error: BooleanCap for '%s' not found!\n",
588 capability->Label());
589 return;
592 const char* key = capability->Key();
593 BString name;
594 name << "pds_" << key;
595 BCheckBox* checkBox = new BCheckBox(name.String(), capability->Label(),
596 NULL);
598 bool value = booleanCap->DefaultValue();
599 if (fJobData->Settings().HasBoolean(key))
600 value = fJobData->Settings().GetBoolean(key);
601 if (value)
602 checkBox->SetValue(B_CONTROL_ON);
604 gridLayout->AddView(checkBox, 0, row, 2);
605 row ++;
607 fDriverSpecificCheckBoxes[capability->Key()] = checkBox;
611 void
612 JobSetupView::AddIntSlider(const DriverSpecificCap* capability,
613 BGridLayout* gridLayout, int& row)
615 PrinterCap::CapID category = static_cast<PrinterCap::CapID>(
616 capability->ID());
617 const IntRangeCap* range = fPrinterCap->FindIntRangeCap(category);
618 if (range == NULL) {
619 fprintf(stderr, "Internal error: IntRangeCap for '%s' not found!\n",
620 capability->Label());
621 return;
624 const char* label = capability->Label();
625 const char* key = capability->Key();
626 BString name;
627 name << "pds_" << key;
628 BMessage* message = new BMessage(kMsgIntSliderChanged);
629 message->AddInt32(kCategoryID, category);
630 BSlider* slider = new BSlider(name.String(), label,
631 message, 0, 1000, B_HORIZONTAL);
632 slider->SetModificationMessage(new BMessage(*message));
633 slider->SetTarget(this);
635 int32 value = range->DefaultValue();
636 if (fJobData->Settings().HasInt(key))
637 value = fJobData->Settings().GetInt(key);
638 float position = (value - range->Lower()) /
639 (range->Upper() - range->Lower());
640 slider->SetPosition(position);
642 gridLayout->AddView(slider, 0, row, 2);
643 row ++;
645 IntRange intRange(label, key, range, slider);
646 fDriverSpecificIntSliders[category] = intRange;
647 intRange.UpdateLabel();
651 void
652 JobSetupView::AddDoubleSlider(const DriverSpecificCap* capability,
653 BGridLayout* gridLayout, int& row)
655 PrinterCap::CapID category = static_cast<PrinterCap::CapID>(
656 capability->ID());
657 const DoubleRangeCap* range = fPrinterCap->FindDoubleRangeCap(category);
658 if (range == NULL) {
659 fprintf(stderr, "Internal error: DoubleRangeCap for '%s' not found!\n",
660 capability->Label());
661 return;
664 const char* label = capability->Label();
665 const char* key = capability->Key();
666 BString name;
667 name << "pds_" << key;
668 BMessage* message = new BMessage(kMsgDoubleSliderChanged);
669 message->AddInt32(kCategoryID, category);
670 BSlider* slider = new BSlider(name.String(), label,
671 message, 0, 1000, B_HORIZONTAL);
672 slider->SetModificationMessage(new BMessage(*message));
673 slider->SetTarget(this);
675 double value = range->DefaultValue();
676 if (fJobData->Settings().HasDouble(key))
677 value = fJobData->Settings().GetDouble(key);
678 float position = static_cast<float>((value - range->Lower()) /
679 (range->Upper() - range->Lower()));
680 slider->SetPosition(position);
682 gridLayout->AddView(slider, 0, row, 2);
683 row ++;
685 DoubleRange doubleRange(label, key, range, slider);
686 fDriverSpecificDoubleSliders[category] = doubleRange;
687 doubleRange.UpdateLabel();
691 string
692 JobSetupView::GetDriverSpecificValue(PrinterCap::CapID category,
693 const char* key)
695 if (fJobData->Settings().HasString(key))
696 return fJobData->Settings().GetString(key);
698 const EnumCap* defaultCapability = fPrinterCap->GetDefaultCap(category);
699 return defaultCapability->fKey;
703 template<typename Predicate>
704 void
705 JobSetupView::FillCapabilityMenu(BPopUpMenu* menu, uint32 message,
706 const BaseCap** capabilities, int count, Predicate& predicate)
708 bool marked = false;
710 BMenuItem* firstItem = NULL;
711 BMenuItem* defaultItem = NULL;
712 BMenuItem* item = NULL;
713 while (count--) {
714 const EnumCap* capability = dynamic_cast<const EnumCap*>(*capabilities);
715 if (message != kMsgNone)
716 item = new BMenuItem(capability->fLabel.c_str(),
717 new BMessage(message));
718 else
719 item = new BMenuItem(capability->fLabel.c_str(), NULL);
721 menu->AddItem(item);
723 if (firstItem == NULL)
724 firstItem = item;
726 if (capability->fIsDefault)
727 defaultItem = item;
730 if (predicate(capability)) {
731 item->SetMarked(true);
732 marked = true;
735 capabilities++;
738 if (marked)
739 return;
741 if (defaultItem != NULL)
742 defaultItem->SetMarked(true);
743 else if (firstItem != NULL)
744 firstItem->SetMarked(true);
748 void
749 JobSetupView::FillCapabilityMenu(BPopUpMenu* menu, uint32 message,
750 PrinterCap::CapID category, int id)
752 PrinterCap::IDPredicate predicate(id);
753 int count = fPrinterCap->CountCap(category);
754 const BaseCap **capabilities = fPrinterCap->GetCaps(category);
755 FillCapabilityMenu(menu, message, capabilities, count, predicate);
759 void
760 JobSetupView::FillCapabilityMenu(BPopUpMenu* menu, uint32 message,
761 const BaseCap** capabilities, int count, int id)
763 PrinterCap::IDPredicate predicate(id);
764 FillCapabilityMenu(menu, message, capabilities, count, predicate);
769 JobSetupView::GetID(const BaseCap** capabilities, int count, const char* label,
770 int defaultValue)
772 while (count--) {
773 const EnumCap* capability =
774 dynamic_cast<const EnumCap*>(*capabilities);
775 if (capability == NULL)
776 break;
778 if (capability->fLabel == label)
779 return capability->ID();
781 return defaultValue;
785 void
786 JobSetupView::UpdateButtonEnabledState()
788 bool pageRangeEnabled = fAll->Value() != B_CONTROL_ON;
789 fFromPage->SetEnabled(pageRangeEnabled);
790 fToPage->SetEnabled(pageRangeEnabled);
792 bool pageSelectionEnabled = fDuplex == NULL ||
793 fDuplex->Value() != B_CONTROL_ON;
794 fAllPages->SetEnabled(pageSelectionEnabled);
795 fOddNumberedPages->SetEnabled(pageSelectionEnabled);
796 fEvenNumberedPages->SetEnabled(pageSelectionEnabled);
800 void
801 JobSetupView::MessageReceived(BMessage* message)
803 switch (message->what) {
804 case kMsgRangeAll:
805 case kMsgRangeSelection:
806 case kMsgDuplexChanged:
807 UpdateButtonEnabledState();
808 break;
810 case kMsgQuality:
811 UpdateHalftonePreview();
812 break;
814 case kMsgCollateChanged:
815 fPages->SetCollate(fCollate->Value() == B_CONTROL_ON);
816 break;
818 case kMsgReverseChanged:
819 fPages->SetReverse(fReverse->Value() == B_CONTROL_ON);
820 break;
822 case kMsgIntSliderChanged:
823 UpdateIntSlider(message);
824 break;
826 case kMsgDoubleSliderChanged:
827 UpdateDoubleSlider(message);
828 break;
833 void
834 JobSetupView::UpdateHalftonePreview()
836 if (!IsHalftoneConfigurationNeeded())
837 return;
839 fHalftone->Preview(Gamma(), InkDensity(), DitherType(),
840 Color() != JobData::kMonochrome);
844 void
845 JobSetupView::UpdateIntSlider(BMessage* message)
847 int32 id;
848 if (message->FindInt32(kCategoryID, &id) != B_OK)
849 return;
850 PrinterCap::CapID capID = static_cast<PrinterCap::CapID>(id);
851 fDriverSpecificIntSliders[capID].UpdateLabel();
855 void
856 JobSetupView::UpdateDoubleSlider(BMessage* message)
858 int32 id;
859 if (message->FindInt32(kCategoryID, &id) != B_OK)
860 return;
861 PrinterCap::CapID capID = static_cast<PrinterCap::CapID>(id);
862 fDriverSpecificDoubleSliders[capID].UpdateLabel();
866 JobData::Color
867 JobSetupView::Color()
869 const char *label = fColorType->FindMarked()->Label();
870 const BaseCap* capability = fPrinterCap->FindCap(PrinterCap::kColor, label);
871 if (capability == NULL)
872 return JobData::kMonochrome;
874 const ColorCap* colorCap = static_cast<const ColorCap*>(capability);
875 return colorCap->fColor;
879 Halftone::DitherType
880 JobSetupView::DitherType()
882 const char *label = fDitherType->FindMarked()->Label();
883 int id = GetID(gDitherTypes, sizeof(gDitherTypes) / sizeof(gDitherTypes[0]),
884 label, Halftone::kTypeFloydSteinberg);
885 return static_cast<Halftone::DitherType>(id);
888 float
889 JobSetupView::Gamma()
891 const float value = (float)fGamma->Value();
892 return pow(2.0, value / 100.0);
896 float
897 JobSetupView::InkDensity()
899 const float value = (float)(127 - fInkDensity->Value());
900 return value;
904 JobData::PaperSource
905 JobSetupView::PaperSource()
907 const char *label = fPaperFeed->FindMarked()->Label();
908 const BaseCap* capability = fPrinterCap->FindCap(PrinterCap::kPaperSource,
909 label);
911 if (capability == NULL)
912 capability = fPrinterCap->GetDefaultCap(PrinterCap::kPaperSource);
913 return static_cast<const PaperSourceCap*>(capability)->fPaperSource;
917 bool
918 JobSetupView::UpdateJobData()
920 fJobData->SetShowPreview(fPreview->Value() == B_CONTROL_ON);
921 fJobData->SetColor(Color());
922 if (IsHalftoneConfigurationNeeded()) {
923 fJobData->SetGamma(Gamma());
924 fJobData->SetInkDensity(InkDensity());
925 fJobData->SetDitherType(DitherType());
928 int first_page;
929 int last_page;
931 if (B_CONTROL_ON == fAll->Value()) {
932 first_page = 1;
933 last_page = -1;
934 } else {
935 first_page = atoi(fFromPage->Text());
936 last_page = atoi(fToPage->Text());
939 fJobData->SetFirstPage(first_page);
940 fJobData->SetLastPage(last_page);
942 fJobData->SetPaperSource(PaperSource());
944 fJobData->SetNup(GetID(gNups, sizeof(gNups) / sizeof(gNups[0]),
945 fNup->FindMarked()->Label(), 1));
947 if (fPrinterCap->Supports(PrinterCap::kPrintStyle)) {
948 fJobData->SetPrintStyle((B_CONTROL_ON == fDuplex->Value())
949 ? JobData::kDuplex : JobData::kSimplex);
952 fJobData->SetCopies(atoi(fCopies->Text()));
954 fJobData->SetCollate(B_CONTROL_ON == fCollate->Value());
955 fJobData->SetReverse(B_CONTROL_ON == fReverse->Value());
957 JobData::PageSelection pageSelection = JobData::kAllPages;
958 if (fOddNumberedPages->Value() == B_CONTROL_ON)
959 pageSelection = JobData::kOddNumberedPages;
960 if (fEvenNumberedPages->Value() == B_CONTROL_ON)
961 pageSelection = JobData::kEvenNumberedPages;
962 fJobData->SetPageSelection(pageSelection);
965 std::map<PrinterCap::CapID, BPopUpMenu*>::iterator it =
966 fDriverSpecificPopUpMenus.begin();
967 for(; it != fDriverSpecificPopUpMenus.end(); it++) {
968 PrinterCap::CapID category = it->first;
969 BPopUpMenu* popUpMenu = it->second;
970 const char* key = fPrinterCap->FindCap(
971 PrinterCap::kDriverSpecificCapabilities, (int)category)->Key();
972 const char* label = popUpMenu->FindMarked()->Label();
973 const char* value = static_cast<const EnumCap*>(fPrinterCap->
974 FindCap(category, label))->Key();
975 fJobData->Settings().SetString(key, value);
980 std::map<string, BCheckBox*>::iterator it =
981 fDriverSpecificCheckBoxes.begin();
982 for(; it != fDriverSpecificCheckBoxes.end(); it++) {
983 const char* key = it->first.c_str();
984 BCheckBox* checkBox = it->second;
985 bool value = checkBox->Value() == B_CONTROL_ON;
986 fJobData->Settings().SetBoolean(key, value);
991 std::map<PrinterCap::CapID, IntRange>::iterator it =
992 fDriverSpecificIntSliders.begin();
993 for(; it != fDriverSpecificIntSliders.end(); it++) {
994 IntRange& range = it->second;
995 fJobData->Settings().SetInt(range.Key(), range.Value());
1000 std::map<PrinterCap::CapID, DoubleRange>::iterator it =
1001 fDriverSpecificDoubleSliders.begin();
1002 for(; it != fDriverSpecificDoubleSliders.end(); it++) {
1003 DoubleRange& range = it->second;
1004 fJobData->Settings().SetDouble(range.Key(), range.Value());
1008 fJobData->Save();
1009 return true;
1013 JobSetupDlg::JobSetupDlg(JobData* jobData, PrinterData* printerData,
1014 const PrinterCap* printerCap)
1016 DialogWindow(BRect(100, 100, 200, 200), "Print job setup",
1017 B_TITLED_WINDOW_LOOK, B_MODAL_APP_WINDOW_FEEL,
1018 B_NOT_RESIZABLE | B_NOT_MINIMIZABLE | B_NOT_ZOOMABLE
1019 | B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS
1020 | B_CLOSE_ON_ESCAPE)
1022 SetResult(B_ERROR);
1023 AddShortcut('W', B_COMMAND_KEY, new BMessage(B_QUIT_REQUESTED));
1025 fJobSetup = new JobSetupView(jobData, printerData, printerCap);
1026 SetLayout(new BGroupLayout(B_VERTICAL));
1027 AddChild(BGroupLayoutBuilder(B_VERTICAL, 0)
1028 .Add(fJobSetup)
1029 .SetInsets(10, 10, 10, 10)
1034 void
1035 JobSetupDlg::MessageReceived(BMessage* message)
1037 switch (message->what) {
1038 case kMsgOK:
1039 fJobSetup->UpdateJobData();
1040 SetResult(B_NO_ERROR);
1041 PostMessage(B_QUIT_REQUESTED);
1042 break;
1044 case kMsgCancel:
1045 PostMessage(B_QUIT_REQUESTED);
1046 break;
1048 default:
1049 DialogWindow::MessageReceived(message);
1050 break;