vfs: check userland buffers before reading them.
[haiku.git] / src / servers / print / ConfigWindow.cpp
blob658304ad03c1048c2bc53ac362307ddcb94704bf
1 /*
2 * Copyright 2002-2011, Haiku. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Michael Pfeiffer
7 */
10 #include "ConfigWindow.h"
12 #include <limits.h>
13 #include <math.h>
14 #include <stdlib.h>
15 #include <string.h>
17 #include <Application.h>
18 #include <Autolock.h>
19 #include <Catalog.h>
20 #include <Debug.h>
21 #include <GroupLayout.h>
22 #include <GroupLayoutBuilder.h>
23 #include <IconUtils.h>
24 #include <Layout.h>
25 #include <Locale.h>
26 #include <Resources.h>
27 #include <Window.h>
29 #include "pr_server.h"
30 #include "Printer.h"
31 #include "PrintServerApp.h"
32 #include "PrintUtils.h"
35 #undef B_TRANSLATION_CONTEXT
36 #define B_TRANSLATION_CONTEXT "ConfigWindow"
39 static const float a0_width = 2380.0;
40 static const float a0_height = 3368.0;
41 static const float a1_width = 1684.0;
42 static const float a1_height = 2380.0;
43 static const float a2_width = 1190.0;
44 static const float a2_height = 1684.0;
45 static const float a3_width = 842.0;
46 static const float a3_height = 1190.0;
47 static const float a4_width = 595.0;
48 static const float a4_height = 842.0;
49 static const float a5_width = 421.0;
50 static const float a5_height = 595.0;
51 static const float a6_width = 297.0;
52 static const float a6_height = 421.0;
53 static const float b5_width = 501.0;
54 static const float b5_height = 709.0;
55 static const float letter_width = 612.0;
56 static const float letter_height = 792.0;
57 static const float legal_width = 612.0;
58 static const float legal_height = 1008.0;
59 static const float ledger_width = 1224.0;
60 static const float ledger_height = 792.0;
61 static const float tabloid_width = 792.0;
62 static const float tabloid_height = 1224.0;
63 static const float jis_b5_width = 516.0;
64 static const float jis_b5_height = 729.0;
67 static struct PageFormat
69 const char *label;
70 float width;
71 float height;
72 } pageFormat[] =
74 {B_TRANSLATE_MARK_COMMENT("Letter", "ANSI A (letter), a North American "
75 "paper size"), letter_width, letter_height },
76 {B_TRANSLATE_MARK_COMMENT("Legal", "A North American paper size (216 x 356"
77 " mm, or 8.5 x 14 in)"), legal_width, legal_height },
78 {B_TRANSLATE_MARK_COMMENT("Ledger", "ANSI B (ledger), a North American "
79 "paper size"), ledger_width, ledger_height },
80 {B_TRANSLATE_MARK_COMMENT("Tabloid", "ANSI B (tabloid), a North American "
81 "paper size"), tabloid_width, tabloid_height },
82 {B_TRANSLATE_MARK_COMMENT("A0", "ISO 216 paper size"),
83 a0_width, a0_height },
84 {B_TRANSLATE_MARK_COMMENT("A1", "ISO 216 paper size"),
85 a1_width, a1_height },
86 {B_TRANSLATE_MARK_COMMENT("A2", "ISO 216 paper size"),
87 a2_width, a2_height },
88 {B_TRANSLATE_MARK_COMMENT("A3", "ISO 216 paper size"),
89 a3_width, a3_height },
90 {B_TRANSLATE_MARK_COMMENT("A4", "ISO 216 paper size"),
91 a4_width, a4_height },
92 {B_TRANSLATE_MARK_COMMENT("A5", "ISO 216 paper size"),
93 a5_width, a5_height },
94 {B_TRANSLATE_MARK_COMMENT("A6", "ISO 216 paper size"),
95 a6_width, a6_height },
96 {B_TRANSLATE_MARK_COMMENT("B5", "ISO 216 paper size"),
97 b5_width, b5_height },
98 {B_TRANSLATE_MARK_COMMENT("B5 (JIS)", "JIS P0138 B5, a Japanese "
99 "paper size"), jis_b5_width, jis_b5_height },
103 static void
104 GetPageFormat(float w, float h, BString& label)
106 w = floor(w + 0.5); h = floor(h + 0.5);
107 for (uint i = 0; i < sizeof(pageFormat) / sizeof(struct PageFormat); i ++) {
108 struct PageFormat& pf = pageFormat[i];
109 if ((pf.width == w && pf.height == h) || (pf.width == h
110 && pf.height == w)) {
111 label = B_TRANSLATE_NOCOLLECT(pf.label);
112 return;
116 float unit = 72.0; // currently inches only
117 label << (w / unit) << "x" << (h / unit) << " in.";
121 static BGroupLayoutBuilder
122 LeftAlign(BView* view)
124 return BGroupLayoutBuilder(B_HORIZONTAL)
125 .Add(view)
126 .AddGlue()
127 .SetInsets(0, 0, 0, 0);
131 ConfigWindow::ConfigWindow(config_setup_kind kind, Printer* defaultPrinter,
132 BMessage* settings, AutoReply* sender)
134 BWindow(ConfigWindow::GetWindowFrame(),
135 B_TRANSLATE("Page setup"),
136 B_TITLED_WINDOW,
137 B_NOT_RESIZABLE | B_NOT_ZOOMABLE | B_AUTO_UPDATE_SIZE_LIMITS
138 | B_CLOSE_ON_ESCAPE),
139 fKind(kind),
140 fDefaultPrinter(defaultPrinter),
141 fSettings(settings),
142 fSender(sender),
143 fCurrentPrinter(NULL),
144 fPageFormatText(NULL),
145 fJobSetupText(NULL)
147 MimeTypeForSender(settings, fSenderMimeType);
148 PrinterForMimeType();
150 if (kind == kJobSetup)
151 SetTitle(B_TRANSLATE("Print setup"));
153 BView* panel = new BBox(Bounds(), "temporary", B_FOLLOW_ALL, B_WILL_DRAW);
154 AddChild(panel);
156 // print selection pop up menu
157 BPopUpMenu* menu = new BPopUpMenu(B_TRANSLATE("Select a printer"));
158 SetupPrintersMenu(menu);
160 fPrinters = new BMenuField(B_TRANSLATE("Printer:"), menu);
162 // page format button
163 fPageSetup = AddPictureButton(panel, "Paper setup",
164 "PAGE_SETUP", MSG_PAGE_SETUP);
166 // add description to button
167 BStringView *pageFormatTitle = new BStringView("paperSetupTitle",
168 B_TRANSLATE("Paper setup:"));
169 fPageFormatText = new BStringView("pageSetupText", "");
171 // page selection button
172 fJobSetup = NULL;
173 BStringView* jobSetupTitle = NULL;
174 if (kind == kJobSetup) {
175 fJobSetup = AddPictureButton(panel, "Job setup",
176 "JOB_SETUP", MSG_JOB_SETUP);
177 // add description to button
178 jobSetupTitle = new BStringView("jobSetupTitle",
179 B_TRANSLATE("Print job setup:"));
180 fJobSetupText = new BStringView("jobSetupText", "");
183 // separator line
184 BBox* separator = new BBox("separator");
185 separator->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, 1));
187 // Cancel & OK button
188 BButton* cancel = new BButton("Cancel", B_TRANSLATE("Cancel"),
189 new BMessage(B_QUIT_REQUESTED));
190 fOk = new BButton("OK", B_TRANSLATE("OK"), new BMessage(MSG_OK));
192 RemoveChild(panel);
194 SetLayout(new BGroupLayout(B_VERTICAL));
195 BGroupLayoutBuilder builder(B_VERTICAL);
197 builder
198 .Add(fPrinters)
199 .Add(BGroupLayoutBuilder(B_HORIZONTAL, 10)
200 .Add(fPageSetup)
201 .Add(BGroupLayoutBuilder(B_VERTICAL, 0)
202 .Add(LeftAlign(pageFormatTitle))
203 .Add(LeftAlign(fPageFormatText))
204 .SetInsets(0, 0, 0, 0)
206 .AddGlue()
209 if (fJobSetup != NULL) {
210 builder
211 .Add(BGroupLayoutBuilder(B_HORIZONTAL, 10)
212 .Add(fJobSetup)
213 .Add(BGroupLayoutBuilder(B_VERTICAL, 0)
214 .Add(LeftAlign(jobSetupTitle))
215 .Add(LeftAlign(fJobSetupText))
216 .SetInsets(0, 0, 0, 0)
218 .AddGlue()
222 builder
223 .AddGlue()
224 .Add(separator)
225 .Add(BGroupLayoutBuilder(B_HORIZONTAL)
226 .AddGlue()
227 .Add(cancel)
228 .Add(fOk)
230 .SetInsets(5, 5, 5, 5);
232 AddChild(builder);
234 AddShortcut('a', 0, new BMessage(B_ABOUT_REQUESTED));
236 SetDefaultButton(fOk);
238 fPrinters->MakeFocus(true);
240 UpdateSettings(true);
244 ConfigWindow::~ConfigWindow()
246 if (fCurrentPrinter)
247 fCurrentPrinter->Release();
248 release_sem(fFinished);
252 void
253 ConfigWindow::Go()
255 sem_id sid = create_sem(0, "finished");
256 if (sid >= 0) {
257 fFinished = sid;
258 Show();
259 acquire_sem(sid);
260 delete_sem(sid);
261 } else {
262 Quit();
267 void
268 ConfigWindow::MessageReceived(BMessage* m)
270 switch (m->what) {
271 case MSG_PAGE_SETUP:
272 Setup(kPageSetup);
273 break;
274 case MSG_JOB_SETUP:
275 Setup(kJobSetup);
276 break;
277 case MSG_PRINTER_SELECTED:
279 BString printer;
280 if (m->FindString("name", &printer) == B_OK) {
281 UpdateAppSettings(fSenderMimeType.String(), printer.String());
282 PrinterForMimeType();
283 UpdateSettings(true);
285 break;
287 case MSG_OK:
288 UpdateSettings(false);
289 if (fKind == kPageSetup)
290 fSender->SetReply(&fPageSettings);
291 else
292 fSender->SetReply(&fJobSettings);
293 Quit();
294 break;
295 case B_ABOUT_REQUESTED: AboutRequested();
296 break;
297 default:
298 BWindow::MessageReceived(m);
303 void
304 ConfigWindow::AboutRequested()
306 BString text = B_TRANSLATE("Printer server");
307 text << "\n"
308 "© 2001-2010 Haiku, Inc.\n"
309 "\n"
310 "\tIthamar R. Adema\n"
311 "\tMichael Pfeiffer\n";
313 BAlert *about = new BAlert("About printer server", text.String(),
314 B_TRANSLATE("OK"));
315 about->SetFlags(about->Flags() | B_CLOSE_ON_ESCAPE);
316 about->Go();
320 void
321 ConfigWindow::FrameMoved(BPoint p)
323 BRect frame = GetWindowFrame();
324 frame.OffsetTo(p);
325 SetWindowFrame(frame);
329 BRect
330 ConfigWindow::GetWindowFrame()
332 BRect frame(0, 0, 10, 10);
333 BAutolock lock(gLock);
334 if (lock.IsLocked())
335 frame.OffsetBy(Settings::GetSettings()->ConfigWindowFrame().LeftTop());
337 frame.OffsetBy(30, 30);
338 return frame;
342 void
343 ConfigWindow::SetWindowFrame(BRect r)
345 BAutolock lock(gLock);
346 if (lock.IsLocked())
347 Settings::GetSettings()->SetConfigWindowFrame(r);
351 BButton*
352 ConfigWindow::AddPictureButton(BView* panel, const char* name,
353 const char* picture, uint32 what)
355 BResources *res = BApplication::AppResources();
356 if (res == NULL)
357 return NULL;
359 size_t length;
360 const void *bits = res->LoadResource('VICN', picture, &length);
361 BButton* button = NULL;
363 BBitmap* onBM = new BBitmap(BRect(0, 0, 24, 24), B_RGBA32);
365 if (onBM != NULL) {
366 if (BIconUtils::GetVectorIcon((uint8*)bits, length, onBM) != B_OK) {
367 delete onBM;
368 return NULL;
371 button = new BButton(name, new BMessage(what));
372 button->SetIcon(onBM, B_TRIM_ICON_BITMAP_KEEP_ASPECT);
373 button->SetViewColor(B_TRANSPARENT_COLOR);
374 button->SetLabel(NULL);
377 delete onBM;
379 return button;
383 void
384 ConfigWindow::PrinterForMimeType()
386 BAutolock lock(gLock);
387 if (fCurrentPrinter) {
388 fCurrentPrinter->Release();
389 fCurrentPrinter = NULL;
392 if (lock.IsLocked()) {
393 Settings* s = Settings::GetSettings();
394 AppSettings* app = s->FindAppSettings(fSenderMimeType.String());
395 if (app)
396 fPrinterName = app->GetPrinter();
397 else
398 fPrinterName = fDefaultPrinter ? fDefaultPrinter->Name() : "";
399 fCurrentPrinter = Printer::Find(fPrinterName);
400 if (fCurrentPrinter)
401 fCurrentPrinter->Acquire();
406 void
407 ConfigWindow::SetupPrintersMenu(BMenu* menu)
409 // clear menu
410 while (menu->CountItems() != 0)
411 delete menu->RemoveItem((int32)0);
413 // fill menu with printer names
414 BAutolock lock(gLock);
415 if (lock.IsLocked()) {
416 BString n;
417 BMessage* m;
418 BMenuItem* item;
419 for (int i = 0; i < Printer::CountPrinters(); i ++) {
420 Printer::At(i)->GetName(n);
421 m = new BMessage(MSG_PRINTER_SELECTED);
422 m->AddString("name", n.String());
423 menu->AddItem(item = new BMenuItem(n.String(), m));
424 if (n == fPrinterName)
425 item->SetMarked(true);
431 void
432 ConfigWindow::UpdateAppSettings(const char* mime, const char* printer)
434 BAutolock lock(gLock);
435 if (lock.IsLocked()) {
436 Settings* s = Settings::GetSettings();
437 AppSettings* app = s->FindAppSettings(mime);
438 if (app)
439 app->SetPrinter(printer);
440 else
441 s->AddAppSettings(new AppSettings(mime, printer));
446 void
447 ConfigWindow::UpdateSettings(bool read)
449 BAutolock lock(gLock);
450 if (lock.IsLocked()) {
451 Settings* s = Settings::GetSettings();
452 PrinterSettings* p = s->FindPrinterSettings(fPrinterName.String());
453 if (p == NULL) {
454 p = new PrinterSettings(fPrinterName.String());
455 s->AddPrinterSettings(p);
457 ASSERT(p != NULL);
458 if (read) {
459 fPageSettings = *p->GetPageSettings();
460 fJobSettings = *p->GetJobSettings();
461 } else {
462 p->SetPageSettings(&fPageSettings);
463 p->SetJobSettings(&fJobSettings);
466 UpdateUI();
470 void
471 ConfigWindow::UpdateUI()
473 if (fCurrentPrinter == NULL) {
474 fPageSetup->SetEnabled(false);
475 if (fJobSetup) {
476 fJobSetup->SetEnabled(false);
477 fJobSetupText->SetText(B_TRANSLATE("Undefined"));
479 fOk->SetEnabled(false);
480 fPageFormatText->SetText(B_TRANSLATE("Undefined"));
481 } else {
482 fPageSetup->SetEnabled(true);
484 if (fJobSetup)
485 fJobSetup->SetEnabled(fKind == kJobSetup
486 && !fPageSettings.IsEmpty());
488 fOk->SetEnabled((fKind == kJobSetup && !fJobSettings.IsEmpty())
489 || (fKind == kPageSetup && !fPageSettings.IsEmpty()));
491 // display information about page format
492 BRect paperRect;
493 BString pageFormat;
494 if (fPageSettings.FindRect(PSRV_FIELD_PAPER_RECT, &paperRect) == B_OK) {
495 GetPageFormat(paperRect.Width(), paperRect.Height(), pageFormat);
497 int32 orientation = 0;
498 fPageSettings.FindInt32(PSRV_FIELD_ORIENTATION, &orientation);
499 if (orientation == 0)
500 pageFormat << ", " << B_TRANSLATE("Portrait");
501 else
502 pageFormat << ", " << B_TRANSLATE("Landscape");
503 } else
504 pageFormat << B_TRANSLATE("Undefined");
506 fPageFormatText->SetText(pageFormat.String());
508 // display information about job
509 if (fKind == kJobSetup) {
510 BString job;
511 int32 first, last, copies;
512 if (fJobSettings.FindInt32(PSRV_FIELD_FIRST_PAGE, &first) == B_OK
513 && fJobSettings.FindInt32(PSRV_FIELD_LAST_PAGE, &last) ==
514 B_OK) {
516 bool printRange = first >= 1 && first <= last && last != INT_MAX;
517 char number[12];
518 if (fJobSettings.FindInt32(PSRV_FIELD_COPIES, &copies)
519 == B_OK && copies > 1) {
520 if (printRange) {
521 job = B_TRANSLATE("Page %1 to %2, %3 copies");
522 snprintf(number, sizeof(number), "%d", (int)first);
523 job.ReplaceFirst("%1", number);
524 snprintf(number, sizeof(number), "%d", (int)last);
525 job.ReplaceFirst("%2", number);
526 snprintf(number, sizeof(number), "%d", (int)copies);
527 job.ReplaceFirst("%3", number);
528 } else {
529 job = B_TRANSLATE("All pages, %1 copies");
530 snprintf(number, sizeof(number), "%d", (int)copies);
531 job.ReplaceFirst("%1", number);
533 } else {
534 if (printRange) {
535 job = B_TRANSLATE("Page %1 to %2");
536 snprintf(number, sizeof(number), "%d", (int)first);
537 job.ReplaceFirst("%1", number);
538 snprintf(number, sizeof(number), "%d", (int)last);
539 job.ReplaceFirst("%2", number);
540 } else
541 job = B_TRANSLATE("All pages");
543 } else
544 job << B_TRANSLATE("Undefined");
546 fJobSetupText->SetText(job.String());
552 void
553 ConfigWindow::Setup(config_setup_kind kind)
555 if (fCurrentPrinter) {
556 Hide();
557 if (kind == kPageSetup) {
558 BMessage settings = fPageSettings;
559 if (fCurrentPrinter->ConfigurePage(settings) == B_OK) {
560 fPageSettings = settings;
561 if (!fJobSettings.IsEmpty())
562 AddFields(&fJobSettings, &fPageSettings);
564 } else {
565 BMessage settings;
566 if (fJobSettings.IsEmpty()) settings = fPageSettings;
567 else settings = fJobSettings;
569 if (fCurrentPrinter->ConfigureJob(settings) == B_OK)
570 fJobSettings = settings;
572 UpdateUI();
573 Show();