headers/bsd: Add sys/queue.h.
[haiku.git] / src / tests / add-ons / print / ppd / ui / PPDConfigView.cpp
blob963e904d3d21b6491b728dfc1d522ed5272fad79
1 /*
2 * Copyright 2008, Haiku.
3 * Distributed under the terms of the MIT license.
5 * Authors:
6 * Michael Pfeiffer <laplace@users.sourceforge.net>
7 */
9 #include "PPDConfigView.h"
10 #include "PPDParser.h"
11 #include "StatementListVisitor.h"
12 #include "UIUtils.h"
14 #include <Box.h>
15 #include <CheckBox.h>
16 #include <Menu.h>
17 #include <MenuField.h>
18 #include <MenuItem.h>
19 #include <RadioButton.h>
20 #include <ScrollView.h>
21 #include <StringView.h>
22 #include <Window.h>
24 // margin
25 const float kLeftMargin = 3.0;
26 const float kRightMargin = 3.0;
27 const float kTopMargin = 3.0;
28 const float kBottomMargin = 3.0;
30 // space between views
31 const float kHorizontalSpace = 8.0;
32 const float kVerticalSpace = 8.0;
34 // Message what values
35 const uint32 kMsgBooleanChanged = 'bool';
36 const uint32 kMsgStringChanged = 'strc';
38 #include <stdio.h>
40 class DefaultValueExtractor : public StatementListVisitor
42 BMessage fDefaultValues;
44 public:
45 void DoDefault(Statement* statement)
47 const char* keyword = statement->GetKeywordString();
48 const char* value = statement->GetValueString();
49 if (keyword != NULL && value != NULL) {
50 fDefaultValues.AddString(keyword, value);
54 const BMessage& GetDefaultValues()
56 return fDefaultValues;
60 class CategoryBuilder : public StatementListVisitor
62 BOutlineListView* fCategories;
64 public:
65 CategoryBuilder(BOutlineListView* categories)
66 : fCategories(categories)
69 void AddStatement(const char* text, Statement* statement)
71 if (text != NULL) {
72 BStringItem* item = new CategoryItem(text, statement, GetLevel());
73 fCategories->AddItem(item);
77 void BeginGroup(GroupStatement* group)
79 const char* translation = group->GetGroupTranslation();
80 const char* name = group->GetGroupName();
82 const char* text = NULL;
83 if (translation != NULL) {
84 text = translation;
85 } else {
86 text = name;
89 AddStatement(text, group->GetStatement());
95 DetailsBuilder adds views to the details view and sets the
96 value to the one specified in the settings.
98 The group type determines the view to be used for user input:
99 Type Input
100 ---------------------
101 Boolean BRadioButton
102 PickOne BMenuField
103 PickMany BCheckBox
104 Unknown BCheckBox
106 class DetailsBuilder : public StatementListVisitor
108 BView* fParent;
109 BView* fDetails;
110 BRect fBounds;
111 const char* fKeyword;
112 const char* fValue;
113 GroupStatement fGroup;
114 BMenu* fMenu;
115 BMenuField* fMenuField;
116 const BMessage& fSettings;
118 void AddView(BView* view);
120 BMessage* GetMessage(uint32 what, const char* option);
122 public:
123 DetailsBuilder(BView* parent, BView* details, BRect bounds, Statement* group, const BMessage& settings);
125 BRect GetBounds() { return fBounds; }
127 void Visit(StatementList* list);
129 void DoValue(Statement* statement);
132 void DetailsBuilder::AddView(BView* view)
134 if (view != NULL) {
135 fDetails->AddChild(view);
136 view->ResizeToPreferred();
138 fBounds.OffsetBy(0, view->Bounds().Height()+1);
140 BControl* control = dynamic_cast<BControl*>(view);
141 if (control != NULL) {
142 control->SetTarget(fParent);
147 DetailsBuilder::DetailsBuilder(BView* parent, BView* details, BRect bounds, Statement* group, const BMessage& settings)
148 : fParent(parent)
149 , fDetails(details)
150 , fBounds(bounds)
151 , fGroup(group)
152 , fMenu(NULL)
153 , fMenuField(NULL)
154 , fSettings(settings)
156 fKeyword = fGroup.GetGroupName();
158 if (fKeyword == NULL) return;
160 fValue = settings.FindString(fKeyword);
162 const char* label = fGroup.GetGroupTranslation();
163 if (label == NULL) {
164 label = fKeyword;
167 BView* view = NULL;
168 if (fGroup.GetType() == GroupStatement::kPickOne) {
169 fMenu = new BMenu("<pick one>");
170 fMenu->SetRadioMode(true);
171 fMenu->SetLabelFromMarked(true);
172 fMenuField = new BMenuField(fBounds, "menuField", label, fMenu);
173 view = fMenuField;
174 } else if (fGroup.GetType() == GroupStatement::kBoolean) {
175 BMessage* message = GetMessage(kMsgBooleanChanged, "");
176 BCheckBox* cb = new BCheckBox(fBounds, "", label, message);
177 view = cb;
178 cb->SetValue((fValue != NULL && strcmp(fValue, "True") == 0)
179 ? B_CONTROL_ON
180 : B_CONTROL_OFF);
183 AddView(view);
186 void DetailsBuilder::Visit(StatementList* list)
188 if (fKeyword == NULL) return;
190 StatementListVisitor::Visit(list);
193 BMessage* DetailsBuilder::GetMessage(uint32 what, const char* option)
195 BMessage* message = new BMessage(what);
196 message->AddString("keyword", fKeyword);
198 if (option != NULL) {
199 message->AddString("option", option);
201 return message;
204 void DetailsBuilder::DoValue(Statement* statement)
206 if (GetLevel() != 0) return;
207 if (strcmp(fKeyword, statement->GetKeywordString()) != 0) return;
209 const char* text = NULL;
210 const char* option = statement->GetOptionString();
211 if (statement->GetTranslationString() != NULL) {
212 text = statement->GetTranslationString();
213 } else if (option != NULL) {
214 text = option;
217 if (text == NULL) return;
219 BView* view = NULL;
220 BMessage* message = NULL;
222 if (fGroup.GetType() == GroupStatement::kPickMany ||
223 fGroup.GetType() == GroupStatement::kUnknown) {
224 message = GetMessage(kMsgStringChanged, option);
225 view = new BCheckBox(fBounds, "", text, message);
226 } else if (fGroup.GetType() == GroupStatement::kPickOne) {
227 message = GetMessage(kMsgStringChanged, option);
228 BMenuItem* item = new BMenuItem(text, message);
229 item->SetTarget(fParent);
230 fMenu->AddItem(item);
231 if (fValue != NULL && option != NULL && strcmp(fValue, option) == 0) {
232 item->SetMarked(true);
236 AddView(view);
239 #define kBoxHeight 20
240 #define kBoxBottomMargin 4
241 #define kBoxLeftMargin 8
242 #define kBoxRightMargin 8
244 #define kItemLeftMargin 5
245 #define kItemRightMargin 5
247 class PPDBuilder : public StatementListVisitor
249 BView* fParent;
250 BView* fView;
251 BRect fBounds;
252 BMessage& fSettings;
253 BList fNestedBoxes;
255 bool IsTop()
257 return fNestedBoxes.CountItems() == 0;
260 void Push(BView* view)
262 fNestedBoxes.AddItem(view);
265 void Pop()
267 fNestedBoxes.RemoveItem((int32)fNestedBoxes.CountItems()-1);
270 BView* GetView()
272 if (IsTop()) {
273 return fView;
274 } else {
275 return (BView*)fNestedBoxes.ItemAt(fNestedBoxes.CountItems()-1);
281 BRect GetControlBounds()
283 if (IsTop()) {
284 BRect bounds(fBounds);
285 bounds.left += kItemLeftMargin /** GetLevel()*/;
286 bounds.right -= kItemRightMargin /** GetLevel()*/;
287 return bounds;
290 BView* box = GetView();
291 BRect bounds(box->Bounds());
292 bounds.top = bounds.bottom - kBoxBottomMargin;
293 bounds.bottom = bounds.top + kBoxHeight;
294 bounds.left += kBoxLeftMargin;
295 bounds.right -= kBoxRightMargin;
296 return bounds;
299 bool IsUIGroup(GroupStatement* group)
301 return group->IsUIGroup() || group->IsJCL();
304 void UpdateParentHeight(float height)
306 if (IsTop()) {
307 fBounds.OffsetBy(0, height);
308 } else {
309 BView* parent = GetView();
310 parent->ResizeBy(0, height);
314 public:
315 PPDBuilder(BView* parent, BView* view, BMessage& settings)
316 : fParent(parent)
317 , fView(view)
318 , fBounds(view->Bounds())
319 , fSettings(settings)
321 RemoveChildren(view);
322 fBounds.OffsetTo(0, 0);
323 fBounds.left += kLeftMargin;
324 fBounds.top += kTopMargin;
325 fBounds.right -= kRightMargin;
328 BRect GetBounds()
330 return BRect(0, 0, fView->Bounds().Width(), fBounds.top);
333 void AddUIGroup(const char* text, Statement* statement)
335 if (statement->GetChildren() == NULL) return;
336 DetailsBuilder builder(fParent, GetView(), GetControlBounds(), statement, fSettings);
337 builder.Visit(statement->GetChildren());
339 if (IsTop()) {
340 fBounds.OffsetTo(fBounds.left, builder.GetBounds().top);
341 } else {
342 BView* box = GetView();
343 box->ResizeTo(box->Bounds().Width(), builder.GetBounds().top + kBoxBottomMargin);
347 void OpenGroup(const char* text)
349 if (text != NULL) {
350 BBox* box = new BBox(GetControlBounds(), text);
351 box->SetLabel(text);
352 GetView()->AddChild(box);
353 Push(box);
354 box->ResizeTo(box->Bounds().Width(), kBoxHeight);
358 void CloseGroup()
360 if (!IsTop()) {
361 BView* box = GetView();
362 Pop();
363 UpdateParentHeight(box->Bounds().Height());
367 void BeginGroup(GroupStatement* group)
369 const char* translation = group->GetGroupTranslation();
370 const char* name = group->GetGroupName();
372 const char* text = NULL;
373 if (translation != NULL) {
374 text = translation;
375 } else {
376 text = name;
379 if (IsUIGroup(group)) {
380 AddUIGroup(text, group->GetStatement());
381 } else {
382 OpenGroup(text);
386 void EndGroup(GroupStatement* group)
388 if (!IsUIGroup(group)) {
389 CloseGroup();
394 PPDConfigView::PPDConfigView(BRect bounds, const char *name, uint32 resizeMask, uint32 flags)
395 : BView(bounds, name, resizeMask, flags)
396 , fPPD(NULL)
398 // add category outline list view
399 bounds.OffsetTo(0, 0);
400 BRect listBounds(bounds.left + kLeftMargin, bounds.top + kTopMargin,
401 bounds.right - kHorizontalSpace, bounds.bottom - kBottomMargin);
402 listBounds.right -= B_V_SCROLL_BAR_WIDTH;
403 listBounds.bottom -= B_H_SCROLL_BAR_HEIGHT;
405 BStringView* label = new BStringView(listBounds, "printer-settings", "Printer Settings:");
406 AddChild(label);
407 label->ResizeToPreferred();
409 listBounds.top += label->Bounds().bottom + 5;
411 // add details view
412 fDetails = new BView(listBounds, "details", B_FOLLOW_ALL_SIDES, B_WILL_DRAW);
413 fDetails->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
415 BScrollView* scrollView = new BScrollView("details-scroll-view",
416 fDetails, B_FOLLOW_ALL_SIDES, 0, true, true);
418 AddChild(scrollView);
421 void SetScrollBar(BScrollBar* scroller, float contents, float client)
423 if (scroller != NULL) {
424 float extent = contents - client;
425 if (extent >= 0) {
426 scroller->SetRange(0, extent);
427 scroller->SetProportion(1-extent / contents);
428 scroller->SetSteps(20, client);
429 } else {
430 scroller->SetRange(0, 0);
435 void PPDConfigView::FillCategories()
437 if (fPPD == NULL) return;
439 PPDBuilder builder(this, fDetails, fSettings);
440 builder.Visit(fPPD);
441 BScrollBar* scroller = fDetails->ScrollBar(B_VERTICAL);
442 SetScrollBar(scroller, builder.GetBounds().Height(), fDetails->Bounds().Height());
443 scroller = fDetails->ScrollBar(B_HORIZONTAL);
444 SetScrollBar(scroller, builder.GetBounds().Width(), fDetails->Bounds().Width());
447 void PPDConfigView::FillDetails(Statement* statement)
449 RemoveChildren(fDetails);
451 if (statement == NULL) {
452 return;
455 StatementList* children= statement->GetChildren();
456 if (children == NULL) {
457 return;
460 BRect bounds(fDetails->Bounds());
461 bounds.OffsetTo(kLeftMargin, kTopMargin);
462 DetailsBuilder builder(this, fDetails, bounds, statement, fSettings);
463 builder.Visit(children);
466 void PPDConfigView::BooleanChanged(BMessage* msg)
468 const char* keyword = msg->FindString("keyword");
470 int32 value;
471 if (msg->FindInt32("be:value", &value) == B_OK) {
472 const char* option;
473 if (value) {
474 option = "True";
475 } else {
476 option = "False";
478 fSettings.ReplaceString(keyword, option);
482 void PPDConfigView::StringChanged(BMessage* msg)
484 const char* keyword = msg->FindString("keyword");
485 const char* option = msg->FindString("option");
487 if (keyword != NULL && keyword != NULL) {
488 fSettings.ReplaceString(keyword, option);
492 void PPDConfigView::MessageReceived(BMessage* msg)
494 switch (msg->what) {
495 case kMsgBooleanChanged: BooleanChanged(msg);
496 break;
497 case kMsgStringChanged: StringChanged(msg);
498 break;
501 BView::MessageReceived(msg);
504 void PPDConfigView::SetupSettings(const BMessage& currentSettings)
506 DefaultValueExtractor extractor;
507 extractor.Visit(fPPD);
509 const BMessage &defaultValues(extractor.GetDefaultValues());
510 fSettings.MakeEmpty();
512 char* name;
513 type_code code;
514 for (int32 index = 0; defaultValues.GetInfo(B_STRING_TYPE, index, &name, &code) == B_OK; index ++) {
515 const char* value = currentSettings.FindString(name);
516 if (value == NULL) {
517 value = defaultValues.FindString(name);
519 if (value != NULL) {
520 fSettings.AddString(name, value);
525 void PPDConfigView::Set(const char* file, const BMessage& currentSettings)
527 delete fPPD;
529 PPDParser parser(file);
530 fPPD = parser.ParseAll();
531 if (fPPD == NULL) {
532 fprintf(stderr, "Parsing error (%s): %s\n", file, parser.GetErrorMessage());
535 SetupSettings(currentSettings);
536 FillCategories();