/*
* JobSetupDlg.cpp
* Copyright 1999-2000 Y.Takagi. All Rights Reserved.
*/
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <string>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <math.h>
#include <Alert.h>
#include <Bitmap.h>
#include <Box.h>
#include <Button.h>
#include <CheckBox.h>
#include <Debug.h>
#include <GridView.h>
#include <GroupLayout.h>
#include <GroupLayoutBuilder.h>
#include <Looper.h>
#include <MessageFilter.h>
#include <MenuField.h>
#include <MenuItem.h>
#include <Message.h>
#include <Point.h>
#include <PopUpMenu.h>
#include <PrintJob.h>
#include <RadioButton.h>
#include <Rect.h>
#include <Slider.h>
#include <String.h>
#include <TextControl.h>
#include <TextView.h>
#include <View.h>
#include "HalftoneView.h"
#include "JobSetupDlg.h"
#include "JobData.h"
#include "JSDSlider.h"
#include "PagesView.h"
#include "PrinterData.h"
#include "PrinterCap.h"
#include "DbgMsg.h"
using namespace std;
struct NupCap : public EnumCap {
NupCap(const string &label, bool isDefault, int nup)
:
EnumCap(label, isDefault),
fNup(nup)
{}
int32 ID() const { return fNup; }
int fNup;
};
struct DitherCap : public EnumCap {
DitherCap(const string &label, bool isDefault,
Halftone::DitherType ditherType)
:
EnumCap(label, isDefault),
fDitherType(ditherType)
{}
int32 ID() const { return fDitherType; }
Halftone::DitherType fDitherType;
};
static const NupCap gNup1("1", true, 1);
static const NupCap gNup2("2", false, 2);
static const NupCap gNup4("4", false, 4);
static const NupCap gNup8("8", false, 8);
static const NupCap gNup9("9", false, 9);
static const NupCap gNup16("16", false, 16);
static const NupCap gNup25("25", false, 25);
static const NupCap gNup32("32", false, 32);
static const NupCap gNup36("36", false, 36);
static const DitherCap gDitherType1("Crosshatch", false, Halftone::kType1);
static const DitherCap gDitherType2("Grid", false, Halftone::kType2);
static const DitherCap gDitherType3("Stipple", false, Halftone::kType3);
static const DitherCap gDitherFloydSteinberg("Floyd-Steinberg", false,
Halftone::kTypeFloydSteinberg);
const BaseCap *gNups[] = {
&gNup1,
&gNup2,
&gNup4,
&gNup8,
&gNup9,
&gNup16,
&gNup25,
&gNup32,
&gNup36
};
const BaseCap *gDitherTypes[] = {
&gDitherType1,
&gDitherType2,
&gDitherType3,
&gDitherFloydSteinberg
};
static const char* kCategoryID = "id";
enum {
kMsgRangeAll = 'JSdl',
kMsgRangeSelection,
kMsgCancel,
kMsgOK,
kMsgQuality,
kMsgCollateChanged,
kMsgReverseChanged,
kMsgDuplexChanged,
kMsgIntSliderChanged,
kMsgDoubleSliderChanged,
kMsgNone = 0
};
JobSetupView::JobSetupView(JobData* jobData, PrinterData* printerData,
const PrinterCap *printerCap)
:
BView("jobSetup", B_WILL_DRAW),
fCopies(NULL),
fFromPage(NULL),
fToPage(NULL),
fJobData(jobData),
fPrinterData(printerData),
fPrinterCap(printerCap),
fColorType(NULL),
fDitherType(NULL),
fGamma(NULL),
fInkDensity(NULL),
fHalftone(NULL),
fAll(NULL),
fCollate(NULL),
fReverse(NULL),
fPages(NULL),
fPaperFeed(NULL),
fDuplex(NULL),
fNup(NULL),
fAllPages(NULL),
fOddNumberedPages(NULL),
fEvenNumberedPages(NULL)
{
SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
}
BRadioButton*
JobSetupView::CreatePageSelectionItem(const char* name, const char* label,
JobData::PageSelection pageSelection)
{
BRadioButton* button = new BRadioButton(name, label, NULL);
if (fJobData->GetPageSelection() == pageSelection) {
button->SetValue(B_CONTROL_ON);
}
return button;
}
void
JobSetupView::AllowOnlyDigits(BTextView* textView, int maxDigits)
{
int num;
for (num = 0; num <= 255; num++) {
textView->DisallowChar(num);
}
for (num = 0; num <= 9; num++) {
textView->AllowChar('0' + num);
}
textView->SetMaxBytes(maxDigits);
}
void
JobSetupView::AttachedToWindow()
{
// quality
BBox* qualityBox = new BBox("quality");
qualityBox->SetLabel("Quality");
// color
fColorType = new BPopUpMenu("color");
fColorType->SetRadioMode(true);
FillCapabilityMenu(fColorType, kMsgQuality, PrinterCap::kColor,
fJobData->GetColor());
BMenuField* colorMenuField = new BMenuField("color", "Color:", fColorType);
fColorType->SetTargetForItems(this);
if (IsHalftoneConfigurationNeeded())
CreateHalftoneConfigurationUI();
// page range
BBox* pageRangeBox = new BBox("pageRange");
pageRangeBox->SetLabel("Page range");
fAll = new BRadioButton("all", "Print all Pages", new BMessage(kMsgRangeAll));
BRadioButton *range = new BRadioButton("selection", "Print selected Pages:",
new BMessage(kMsgRangeSelection));
fFromPage = new BTextControl("from", "From:", "", NULL);
fFromPage->SetAlignment(B_ALIGN_LEFT, B_ALIGN_RIGHT);
AllowOnlyDigits(fFromPage->TextView(), 6);
fToPage = new BTextControl("to", "To:", "", NULL);
fToPage->SetAlignment(B_ALIGN_LEFT, B_ALIGN_RIGHT);
AllowOnlyDigits(fToPage->TextView(), 6);
int first_page = fJobData->GetFirstPage();
int last_page = fJobData->GetLastPage();
if (first_page <= 1 && last_page <= 0) {
fAll->SetValue(B_CONTROL_ON);
} else {
range->SetValue(B_CONTROL_ON);
if (first_page < 1)
first_page = 1;
if (first_page > last_page)
last_page = -1;
BString oss1;
oss1 << first_page;
fFromPage->SetText(oss1.String());
BString oss2;
oss2 << last_page;
fToPage->SetText(oss2.String());
}
fAll->SetTarget(this);
range->SetTarget(this);
// paper source
fPaperFeed = new BPopUpMenu("");
fPaperFeed->SetRadioMode(true);
FillCapabilityMenu(fPaperFeed, kMsgNone, PrinterCap::kPaperSource,
fJobData->GetPaperSource());
BMenuField* paperSourceMenufield = new BMenuField("paperSource",
"Paper source:", fPaperFeed);
// Pages per sheet
fNup = new BPopUpMenu("");
fNup->SetRadioMode(true);
FillCapabilityMenu(fNup, kMsgNone, gNups,
sizeof(gNups) / sizeof(gNups[0]), (int)fJobData->GetNup());
BMenuField* pagesPerSheet = new BMenuField("pagesPerSheet",
"Pages per sheet:", fNup);
// duplex
if (fPrinterCap->Supports(PrinterCap::kPrintStyle)) {
fDuplex = new BCheckBox("duplex", "Duplex",
new BMessage(kMsgDuplexChanged));
if (fJobData->GetPrintStyle() != JobData::kSimplex) {
fDuplex->SetValue(B_CONTROL_ON);
}
fDuplex->SetTarget(this);
} else {
fDuplex = NULL;
}
// copies
fCopies = new BTextControl("copies", "Number of copies:", "", NULL);
AllowOnlyDigits(fCopies->TextView(), 3);
BString copies;
copies << fJobData->GetCopies();
fCopies->SetText(copies.String());
// collate
fCollate = new BCheckBox("collate", "Collate",
new BMessage(kMsgCollateChanged));
if (fJobData->GetCollate()) {
fCollate->SetValue(B_CONTROL_ON);
}
fCollate->SetTarget(this);
// reverse
fReverse = new BCheckBox("reverse", "Reverse order",
new BMessage(kMsgReverseChanged));
if (fJobData->GetReverse()) {
fReverse->SetValue(B_CONTROL_ON);
}
fReverse->SetTarget(this);
// pages view
// TODO make layout API compatible
fPages = new PagesView(BRect(0, 0, 150, 40), "pages", B_FOLLOW_ALL,
B_WILL_DRAW);
fPages->SetCollate(fJobData->GetCollate());
fPages->SetReverse(fJobData->GetReverse());
fPages->SetExplicitMinSize(BSize(150, 40));
fPages->SetExplicitMaxSize(BSize(150, 40));
// page selection
BBox* pageSelectionBox = new BBox("pageSelection");
pageSelectionBox->SetLabel("Page selection");
fAllPages = CreatePageSelectionItem("allPages", "All pages",
JobData::kAllPages);
fOddNumberedPages = CreatePageSelectionItem("oddPages",
"Odd-numbered pages", JobData::kOddNumberedPages);
fEvenNumberedPages = CreatePageSelectionItem("evenPages",
"Even-numbered pages", JobData::kEvenNumberedPages);
fPreview = new BCheckBox("preview", "Show preview before printing", NULL);
if (fJobData->GetShowPreview())
fPreview->SetValue(B_CONTROL_ON);
// separator line
BBox *separator = new BBox("separator");
separator->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, 1));
// buttons
BButton* cancel = new BButton("cancel", "Cancel",
new BMessage(kMsgCancel));
BButton* ok = new BButton("ok", "OK", new BMessage(kMsgOK));
ok->MakeDefault(true);
if (IsHalftoneConfigurationNeeded()) {
BGroupView* halftoneGroup = new BGroupView(B_VERTICAL, 0);
BGroupLayout* halftoneLayout = halftoneGroup->GroupLayout();
halftoneLayout->AddView(fHalftone);
fHalftoneBox->AddChild(halftoneGroup);
}
BGridView* qualityGrid = new BGridView();
BGridLayout* qualityGridLayout = qualityGrid->GridLayout();
qualityGridLayout->AddItem(colorMenuField->CreateLabelLayoutItem(), 0, 0);
qualityGridLayout->AddItem(colorMenuField->CreateMenuBarLayoutItem(), 1, 0);
if (IsHalftoneConfigurationNeeded()) {
qualityGridLayout->AddItem(fDitherMenuField->CreateLabelLayoutItem(),
0, 1);
qualityGridLayout->AddItem(fDitherMenuField->CreateMenuBarLayoutItem(),
1, 1);
qualityGridLayout->AddView(fGamma, 0, 2, 2);
qualityGridLayout->AddView(fInkDensity, 0, 3, 2);
qualityGridLayout->AddView(fHalftoneBox, 0, 4, 2);
} else {
AddDriverSpecificSettings(qualityGridLayout, 1);
}
qualityGridLayout->SetSpacing(0, 0);
qualityGridLayout->SetInsets(5, 5, 5, 5);
qualityBox->AddChild(qualityGrid);
// TODO put qualityGrid in a scroll view
// the layout of the box surrounding the scroll view using the following
// code is not correct; the box still has the size of the qualityGird;
// and the scroll view is vertically centered inside the box!
//BScrollView* qualityScroller = new BScrollView("qualityScroller",
// qualityGrid, 0, false, true);
//qualityScroller->SetExplicitMaxSize(BSize(500, 500));
//qualityBox->AddChild(qualityScroller);
BGridView* pageRangeGrid = new BGridView();
BGridLayout* pageRangeLayout = pageRangeGrid->GridLayout();
pageRangeLayout->AddItem(fFromPage->CreateLabelLayoutItem(), 0, 0);
pageRangeLayout->AddItem(fFromPage->CreateTextViewLayoutItem(), 1, 0);
pageRangeLayout->AddItem(fToPage->CreateLabelLayoutItem(), 0, 1);
pageRangeLayout->AddItem(fToPage->CreateTextViewLayoutItem(), 1, 1);
pageRangeLayout->SetInsets(0, 0, 0, 0);
pageRangeLayout->SetSpacing(0, 0);
BGroupView* pageRangeGroup = new BGroupView(B_VERTICAL, 0);
BGroupLayout* pageRangeGroupLayout = pageRangeGroup->GroupLayout();
pageRangeGroupLayout->AddView(fAll);
pageRangeGroupLayout->AddView(range);
pageRangeGroupLayout->AddView(pageRangeGrid);
pageRangeGroupLayout->SetInsets(5, 5, 5, 5);
pageRangeBox->AddChild(pageRangeGroup);
BGridView* settings = new BGridView();
BGridLayout* settingsLayout = settings->GridLayout();
settingsLayout->AddItem(paperSourceMenufield->CreateLabelLayoutItem(), 0,
0);
settingsLayout->AddItem(paperSourceMenufield->CreateMenuBarLayoutItem(), 1,
0);
settingsLayout->AddItem(pagesPerSheet->CreateLabelLayoutItem(), 0, 1);
settingsLayout->AddItem(pagesPerSheet->CreateMenuBarLayoutItem(), 1, 1);
int row = 2;
if (fDuplex != NULL) {
settingsLayout->AddView(fDuplex, 0, row, 2);
row ++;
}
settingsLayout->AddItem(fCopies->CreateLabelLayoutItem(), 0, row);
settingsLayout->AddItem(fCopies->CreateTextViewLayoutItem(), 1, row);
settingsLayout->SetSpacing(0, 0);
BGroupView* pageSelectionGroup = new BGroupView(B_VERTICAL, 0);
BGroupLayout* groupLayout = pageSelectionGroup->GroupLayout();
groupLayout->AddView(fAllPages);
groupLayout->AddView(fOddNumberedPages);
groupLayout->AddView(fEvenNumberedPages);
groupLayout->SetInsets(5, 5, 5, 5);
pageSelectionBox->AddChild(pageSelectionGroup);
SetLayout(new BGroupLayout(B_VERTICAL));
AddChild(BGroupLayoutBuilder(B_VERTICAL, 0)
.AddGroup(B_HORIZONTAL, 10, 1.0f)
.AddGroup(B_VERTICAL, 10, 1.0f)
.Add(qualityBox)
.Add(pageRangeBox)
.AddGlue()
.End()
.AddGroup(B_VERTICAL, 0, 1.0f)
.Add(settings)
.AddStrut(5)
.Add(fCollate)
.Add(fReverse)
.Add(fPages)
.AddStrut(5)
.Add(pageSelectionBox)
.AddGlue()
.End()
.End()
.Add(fPreview)
.AddGlue()
.Add(separator)
.AddGroup(B_HORIZONTAL, 10, 1.0f)
.AddGlue()
.Add(cancel)
.Add(ok)
.End()
.SetInsets(0, 0, 0, 0)
);
UpdateHalftonePreview();
UpdateButtonEnabledState();
}
bool
JobSetupView::IsHalftoneConfigurationNeeded()
{
return fPrinterCap->Supports(PrinterCap::kHalftone);
}
void
JobSetupView::CreateHalftoneConfigurationUI()
{
// dither type
fDitherType = new BPopUpMenu("");
fDitherType->SetRadioMode(true);
FillCapabilityMenu(fDitherType, kMsgQuality, gDitherTypes,
sizeof(gDitherTypes) / sizeof(gDitherTypes[0]),
(int)fJobData->GetDitherType());
fDitherMenuField = new BMenuField("dithering", "Dot Pattern:",
fDitherType);
fDitherType->SetTargetForItems(this);
// halftone preview view
fHalftoneBox = new BBox("halftoneBox");
fHalftoneBox->SetBorder(B_PLAIN_BORDER);
// TODO make layout compatible
BSize size(240, 14 * 4);
BRect rect(0, 0, size.width, size.height);
fHalftone = new HalftoneView(rect, "halftone",
B_FOLLOW_ALL, B_WILL_DRAW);
fHalftone->SetExplicitMinSize(size);
fHalftone->SetExplicitMaxSize(size);
// gamma
fGamma = new JSDSlider("gamma", "Gamma", new BMessage(kMsgQuality),
-300, 300);
fGamma->SetLimitLabels("Lighter", "Darker");
fGamma->SetValue((int32)(100 * log(fJobData->GetGamma()) / log(2.0)));
fGamma->SetHashMarks(B_HASH_MARKS_BOTH);
fGamma->SetHashMarkCount(7);
fGamma->SetModificationMessage(new BMessage(kMsgQuality));
fGamma->SetTarget(this);
// ink density
fInkDensity = new JSDSlider("inkDensity", "Ink usage",
new BMessage(kMsgQuality), 0, 127);
fInkDensity->SetLimitLabels("Min", "Max");
fInkDensity->SetValue((int32)fJobData->GetInkDensity());
fInkDensity->SetHashMarks(B_HASH_MARKS_BOTH);
fInkDensity->SetHashMarkCount(10);
fInkDensity->SetModificationMessage(new BMessage(kMsgQuality));
fInkDensity->SetTarget(this);
}
void
JobSetupView::AddDriverSpecificSettings(BGridLayout* gridLayout, int row)
{
if (!fPrinterCap->Supports(PrinterCap::kDriverSpecificCapabilities))
return;
int count = fPrinterCap->CountCap(PrinterCap::kDriverSpecificCapabilities);
const BaseCap** capabilities = fPrinterCap->GetCaps(
PrinterCap::kDriverSpecificCapabilities);
for (int i = 0; i < count; i ++) {
const DriverSpecificCap* capability =
static_cast<const DriverSpecificCap*>(capabilities[i]);
switch (capability->fType) {
case DriverSpecificCap::kList:
AddPopUpMenu(capability, gridLayout, row);
break;
case DriverSpecificCap::kBoolean:
AddCheckBox(capability, gridLayout, row);
break;
case DriverSpecificCap::kIntRange:
case DriverSpecificCap::kIntDimension:
AddIntSlider(capability, gridLayout, row);
break;
case DriverSpecificCap::kDoubleRange:
AddDoubleSlider(capability, gridLayout, row);
break;
}
}
}
void
JobSetupView::AddPopUpMenu(const DriverSpecificCap* capability,
BGridLayout* gridLayout, int& row)
{
const char* label = capability->fLabel.c_str();
BPopUpMenu* popUpMenu = new BPopUpMenu(label);
popUpMenu->SetRadioMode(true);
PrinterCap::CapID category = static_cast<PrinterCap::CapID>(
capability->ID());
const BaseCap** categoryCapabilities = fPrinterCap->GetCaps(category);
int categoryCount = fPrinterCap->CountCap(category);
string value = GetDriverSpecificValue(category, capability->Key());
PrinterCap::KeyPredicate predicate(value.c_str());
FillCapabilityMenu(popUpMenu, kMsgNone, categoryCapabilities,
categoryCount, predicate);
BString menuLabel = label;
menuLabel << ":";
BMenuField* menuField = new BMenuField(label, menuLabel.String(),
popUpMenu);
popUpMenu->SetTargetForItems(this);
gridLayout->AddItem(menuField->CreateLabelLayoutItem(),
0, row);
gridLayout->AddItem(menuField->CreateMenuBarLayoutItem(),
1, row);
row ++;
fDriverSpecificPopUpMenus[category] = popUpMenu;
}
void
JobSetupView::AddCheckBox(const DriverSpecificCap* capability,
BGridLayout* gridLayout, int& row)
{
PrinterCap::CapID category = static_cast<PrinterCap::CapID>(
capability->ID());
const BooleanCap* booleanCap = fPrinterCap->FindBooleanCap(category);
if (booleanCap == NULL) {
fprintf(stderr, "Internal error: BooleanCap for '%s' not found!\n",
capability->Label());
return;
}
const char* key = capability->Key();
BString name;
name << "pds_" << key;
BCheckBox* checkBox = new BCheckBox(name.String(), capability->Label(),
NULL);
bool value = booleanCap->DefaultValue();
if (fJobData->Settings().HasBoolean(key))
value = fJobData->Settings().GetBoolean(key);
if (value)
checkBox->SetValue(B_CONTROL_ON);
gridLayout->AddView(checkBox, 0, row, 2);
row ++;
fDriverSpecificCheckBoxes[capability->Key()] = checkBox;
}
void
JobSetupView::AddIntSlider(const DriverSpecificCap* capability,
BGridLayout* gridLayout, int& row)
{
PrinterCap::CapID category = static_cast<PrinterCap::CapID>(
capability->ID());
const IntRangeCap* range = fPrinterCap->FindIntRangeCap(category);
if (range == NULL) {
fprintf(stderr, "Internal error: IntRangeCap for '%s' not found!\n",
capability->Label());
return;
}
const char* label = capability->Label();
const char* key = capability->Key();
BString name;
name << "pds_" << key;
BMessage* message = new BMessage(kMsgIntSliderChanged);
message->AddInt32(kCategoryID, category);
BSlider* slider = new BSlider(name.String(), label,
message, 0, 1000, B_HORIZONTAL);
slider->SetModificationMessage(new BMessage(*message));
slider->SetTarget(this);
int32 value = range->DefaultValue();
if (fJobData->Settings().HasInt(key))
value = fJobData->Settings().GetInt(key);
float position = (value - range->Lower()) /
(range->Upper() - range->Lower());
slider->SetPosition(position);
gridLayout->AddView(slider, 0, row, 2);
row ++;
IntRange intRange(label, key, range, slider);
fDriverSpecificIntSliders[category] = intRange;
intRange.UpdateLabel();
}
void
JobSetupView::AddDoubleSlider(const DriverSpecificCap* capability,
BGridLayout* gridLayout, int& row)
{
PrinterCap::CapID category = static_cast<PrinterCap::CapID>(
capability->ID());
const DoubleRangeCap* range = fPrinterCap->FindDoubleRangeCap(category);
if (range == NULL) {
fprintf(stderr, "Internal error: DoubleRangeCap for '%s' not found!\n",
capability->Label());
return;
}
const char* label = capability->Label();
const char* key = capability->Key();
BString name;
name << "pds_" << key;
BMessage* message = new BMessage(kMsgDoubleSliderChanged);
message->AddInt32(kCategoryID, category);
BSlider* slider = new BSlider(name.String(), label,
message, 0, 1000, B_HORIZONTAL);
slider->SetModificationMessage(new BMessage(*message));
slider->SetTarget(this);
double value = range->DefaultValue();
if (fJobData->Settings().HasDouble(key))
value = fJobData->Settings().GetDouble(key);
float position = static_cast<float>((value - range->Lower()) /
(range->Upper() - range->Lower()));
slider->SetPosition(position);
gridLayout->AddView(slider, 0, row, 2);
row ++;
DoubleRange doubleRange(label, key, range, slider);
fDriverSpecificDoubleSliders[category] = doubleRange;
doubleRange.UpdateLabel();
}
string
JobSetupView::GetDriverSpecificValue(PrinterCap::CapID category,
const char* key)
{
if (fJobData->Settings().HasString(key))
return fJobData->Settings().GetString(key);
const EnumCap* defaultCapability = fPrinterCap->GetDefaultCap(category);
return defaultCapability->fKey;
}
template<typename Predicate>
void
JobSetupView::FillCapabilityMenu(BPopUpMenu* menu, uint32 message,
const BaseCap** capabilities, int count, Predicate& predicate)
{
bool marked = false;
BMenuItem* firstItem = NULL;
BMenuItem* defaultItem = NULL;
BMenuItem* item = NULL;
while (count--) {
const EnumCap* capability = dynamic_cast<const EnumCap*>(*capabilities);
if (message != kMsgNone)
item = new BMenuItem(capability->fLabel.c_str(),
new BMessage(message));
else
item = new BMenuItem(capability->fLabel.c_str(), NULL);
menu->AddItem(item);
if (firstItem == NULL)
firstItem = item;
if (capability->fIsDefault)
defaultItem = item;
if (predicate(capability)) {
item->SetMarked(true);
marked = true;
}
capabilities++;
}
if (marked)
return;
if (defaultItem != NULL)
defaultItem->SetMarked(true);
else if (firstItem != NULL)
firstItem->SetMarked(true);
}
void
JobSetupView::FillCapabilityMenu(BPopUpMenu* menu, uint32 message,
PrinterCap::CapID category, int id)
{
PrinterCap::IDPredicate predicate(id);
int count = fPrinterCap->CountCap(category);
const BaseCap **capabilities = fPrinterCap->GetCaps(category);
FillCapabilityMenu(menu, message, capabilities, count, predicate);
}
void
JobSetupView::FillCapabilityMenu(BPopUpMenu* menu, uint32 message,
const BaseCap** capabilities, int count, int id)
{
PrinterCap::IDPredicate predicate(id);
FillCapabilityMenu(menu, message, capabilities, count, predicate);
}
int
JobSetupView::GetID(const BaseCap** capabilities, int count, const char* label,
int defaultValue)
{
while (count--) {
const EnumCap* capability =
dynamic_cast<const EnumCap*>(*capabilities);
if (capability == NULL)
break;
if (capability->fLabel == label)
return capability->ID();
}
return defaultValue;
}
void
JobSetupView::UpdateButtonEnabledState()
{
bool pageRangeEnabled = fAll->Value() != B_CONTROL_ON;
fFromPage->SetEnabled(pageRangeEnabled);
fToPage->SetEnabled(pageRangeEnabled);
bool pageSelectionEnabled = fDuplex == NULL ||
fDuplex->Value() != B_CONTROL_ON;
fAllPages->SetEnabled(pageSelectionEnabled);
fOddNumberedPages->SetEnabled(pageSelectionEnabled);
fEvenNumberedPages->SetEnabled(pageSelectionEnabled);
}
void
JobSetupView::MessageReceived(BMessage* message)
{
switch (message->what) {
case kMsgRangeAll:
case kMsgRangeSelection:
case kMsgDuplexChanged:
UpdateButtonEnabledState();
break;
case kMsgQuality:
UpdateHalftonePreview();
break;
case kMsgCollateChanged:
fPages->SetCollate(fCollate->Value() == B_CONTROL_ON);
break;
case kMsgReverseChanged:
fPages->SetReverse(fReverse->Value() == B_CONTROL_ON);
break;
case kMsgIntSliderChanged:
UpdateIntSlider(message);
break;
case kMsgDoubleSliderChanged:
UpdateDoubleSlider(message);
break;
}
}
void
JobSetupView::UpdateHalftonePreview()
{
if (!IsHalftoneConfigurationNeeded())
return;
fHalftone->Preview(Gamma(), InkDensity(), DitherType(),
Color() != JobData::kMonochrome);
}
void
JobSetupView::UpdateIntSlider(BMessage* message)
{
int32 id;
if (message->FindInt32(kCategoryID, &id) != B_OK)
return;
PrinterCap::CapID capID = static_cast<PrinterCap::CapID>(id);
fDriverSpecificIntSliders[capID].UpdateLabel();
}
void
JobSetupView::UpdateDoubleSlider(BMessage* message)
{
int32 id;
if (message->FindInt32(kCategoryID, &id) != B_OK)
return;
PrinterCap::CapID capID = static_cast<PrinterCap::CapID>(id);
fDriverSpecificDoubleSliders[capID].UpdateLabel();
}
JobData::Color
JobSetupView::Color()
{
const char *label = fColorType->FindMarked()->Label();
const BaseCap* capability = fPrinterCap->FindCap(PrinterCap::kColor, label);
if (capability == NULL)
return JobData::kMonochrome;
const ColorCap* colorCap = static_cast<const ColorCap*>(capability);
return colorCap->fColor;
}
Halftone::DitherType
JobSetupView::DitherType()
{
const char *label = fDitherType->FindMarked()->Label();
int id = GetID(gDitherTypes, sizeof(gDitherTypes) / sizeof(gDitherTypes[0]),
label, Halftone::kTypeFloydSteinberg);
return static_cast<Halftone::DitherType>(id);
}
float
JobSetupView::Gamma()
{
const float value = (float)fGamma->Value();
return pow(2.0, value / 100.0);
}
float
JobSetupView::InkDensity()
{
const float value = (float)(127 - fInkDensity->Value());
return value;
}
JobData::PaperSource
JobSetupView::PaperSource()
{
const char *label = fPaperFeed->FindMarked()->Label();
const BaseCap* capability = fPrinterCap->FindCap(PrinterCap::kPaperSource,
label);
if (capability == NULL)
capability = fPrinterCap->GetDefaultCap(PrinterCap::kPaperSource);
return static_cast<const PaperSourceCap*>(capability)->fPaperSource;
}
bool
JobSetupView::UpdateJobData()
{
fJobData->SetShowPreview(fPreview->Value() == B_CONTROL_ON);
fJobData->SetColor(Color());
if (IsHalftoneConfigurationNeeded()) {
fJobData->SetGamma(Gamma());
fJobData->SetInkDensity(InkDensity());
fJobData->SetDitherType(DitherType());
}
int first_page;
int last_page;
if (B_CONTROL_ON == fAll->Value()) {
first_page = 1;
last_page = -1;
} else {
first_page = atoi(fFromPage->Text());
last_page = atoi(fToPage->Text());
}
fJobData->SetFirstPage(first_page);
fJobData->SetLastPage(last_page);
fJobData->SetPaperSource(PaperSource());
fJobData->SetNup(GetID(gNups, sizeof(gNups) / sizeof(gNups[0]),
fNup->FindMarked()->Label(), 1));
if (fPrinterCap->Supports(PrinterCap::kPrintStyle)) {
fJobData->SetPrintStyle((B_CONTROL_ON == fDuplex->Value())
? JobData::kDuplex : JobData::kSimplex);
}
fJobData->SetCopies(atoi(fCopies->Text()));
fJobData->SetCollate(B_CONTROL_ON == fCollate->Value());
fJobData->SetReverse(B_CONTROL_ON == fReverse->Value());
JobData::PageSelection pageSelection = JobData::kAllPages;
if (fOddNumberedPages->Value() == B_CONTROL_ON)
pageSelection = JobData::kOddNumberedPages;
if (fEvenNumberedPages->Value() == B_CONTROL_ON)
pageSelection = JobData::kEvenNumberedPages;
fJobData->SetPageSelection(pageSelection);
{
std::map<PrinterCap::CapID, BPopUpMenu*>::iterator it =
fDriverSpecificPopUpMenus.begin();
for(; it != fDriverSpecificPopUpMenus.end(); it++) {
PrinterCap::CapID category = it->first;
BPopUpMenu* popUpMenu = it->second;
const char* key = fPrinterCap->FindCap(
PrinterCap::kDriverSpecificCapabilities, (int)category)->Key();
const char* label = popUpMenu->FindMarked()->Label();
const char* value = static_cast<const EnumCap*>(fPrinterCap->
FindCap(category, label))->Key();
fJobData->Settings().SetString(key, value);
}
}
{
std::map<string, BCheckBox*>::iterator it =
fDriverSpecificCheckBoxes.begin();
for(; it != fDriverSpecificCheckBoxes.end(); it++) {
const char* key = it->first.c_str();
BCheckBox* checkBox = it->second;
bool value = checkBox->Value() == B_CONTROL_ON;
fJobData->Settings().SetBoolean(key, value);
}
}
{
std::map<PrinterCap::CapID, IntRange>::iterator it =
fDriverSpecificIntSliders.begin();
for(; it != fDriverSpecificIntSliders.end(); it++) {
IntRange& range = it->second;
fJobData->Settings().SetInt(range.Key(), range.Value());
}
}
{
std::map<PrinterCap::CapID, DoubleRange>::iterator it =
fDriverSpecificDoubleSliders.begin();
for(; it != fDriverSpecificDoubleSliders.end(); it++) {
DoubleRange& range = it->second;
fJobData->Settings().SetDouble(range.Key(), range.Value());
}
}
fJobData->Save();
return true;
}
JobSetupDlg::JobSetupDlg(JobData* jobData, PrinterData* printerData,
const PrinterCap* printerCap)
:
DialogWindow(BRect(100, 100, 200, 200), "Print job setup",
B_TITLED_WINDOW_LOOK, B_MODAL_APP_WINDOW_FEEL,
B_NOT_RESIZABLE | B_NOT_MINIMIZABLE | B_NOT_ZOOMABLE
| B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS
| B_CLOSE_ON_ESCAPE)
{
SetResult(B_ERROR);
AddShortcut('W', B_COMMAND_KEY, new BMessage(B_QUIT_REQUESTED));
fJobSetup = new JobSetupView(jobData, printerData, printerCap);
SetLayout(new BGroupLayout(B_VERTICAL));
AddChild(BGroupLayoutBuilder(B_VERTICAL, 0)
.Add(fJobSetup)
.SetInsets(10, 10, 10, 10)
);
}
void
JobSetupDlg::MessageReceived(BMessage* message)
{
switch (message->what) {
case kMsgOK:
fJobSetup->UpdateJobData();
SetResult(B_NO_ERROR);
PostMessage(B_QUIT_REQUESTED);
break;
case kMsgCancel:
PostMessage(B_QUIT_REQUESTED);
break;
default:
DialogWindow::MessageReceived(message);
break;
}
}
↑ V773 Visibility scope of the 'pagesPerSheet' pointer was exited without releasing the memory. A memory leak is possible.
↑ V773 Visibility scope of the 'paperSourceMenufield' pointer was exited without releasing the memory. A memory leak is possible.
↑ V730 Not all members of a class are initialized inside the constructor. Consider inspecting: fDitherMenuField, fHalftoneBox, fPreview.
↑ V773 Visibility scope of the 'colorMenuField' pointer was exited without releasing the memory. A memory leak is possible.