xref: /haiku/src/servers/print/ConfigWindow.cpp (revision 746cac055adc6ac3308c7bc2d29040fb95689cc9)
1 /*
2  * Copyright 2002-2008, Haiku. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Michael Pfeiffer
7  */
8 
9 #include "pr_server.h"
10 #include "Printer.h"
11 #include "PrintServerApp.h"
12 #include "ConfigWindow.h"
13 #include "PrintUtils.h"
14 
15 // posix
16 #include <limits.h>
17 #include <math.h>
18 #include <stdlib.h>
19 #include <string.h>
20 
21 // BeOS
22 #include <Application.h>
23 #include <Autolock.h>
24 #include <Window.h>
25 
26 
27 static const float a0_width = 2380.0;
28 static const float a0_height = 3368.0;
29 static const float a1_width = 1684.0;
30 static const float a1_height = 2380.0;
31 static const float a2_width = 1190.0;
32 static const float a2_height = 1684.0;
33 static const float a3_width = 842.0;
34 static const float a3_height = 1190.0;
35 static const float a4_width = 595.0;
36 static const float a4_height = 842.0;
37 static const float a5_width = 421.0;
38 static const float a5_height = 595.0;
39 static const float a6_width = 297.0;
40 static const float a6_height = 421.0;
41 static const float b5_width = 501.0;
42 static const float b5_height = 709.0;
43 static const float letter_width = 612.0;
44 static const float letter_height = 792.0;
45 static const float legal_width  = 612.0;
46 static const float legal_height  = 1008.0;
47 static const float ledger_width = 1224.0;
48 static const float ledger_height = 792.0;
49 static const float p11x17_width = 792.0;
50 static const float p11x17_height = 1224.0;
51 
52 
53 static struct PageFormat
54 {
55 	char  *label;
56 	float width;
57 	float height;
58 } pageFormat[] =
59 {
60 	{"Letter", letter_width, letter_height },
61 	{"Legal",  legal_width,  legal_height  },
62 	{"Ledger", ledger_width, ledger_height  },
63 	{"p11x17", p11x17_width, p11x17_height  },
64 	{"A0",     a0_width,     a0_height     },
65 	{"A1",     a1_width,     a1_height     },
66 	{"A2",     a2_width,     a2_height     },
67 	{"A3",     a3_width,     a3_height     },
68 	{"A4",     a4_width,     a4_height     },
69 	{"A5",     a5_width,     a5_height     },
70 	{"A6",     a6_width,     a6_height     },
71 	{"B5",     b5_width,     b5_height     },
72 };
73 
74 
75 static void GetPageFormat(float w, float h, BString& label)
76 {
77 	w = floor(w + 0.5); h = floor(h + 0.5);
78 	for (uint i = 0; i < sizeof(pageFormat) / sizeof(struct PageFormat); i ++) {
79 		struct PageFormat& pf = pageFormat[i];
80 		if (pf.width == w && pf.height == h || pf.width == h && pf.height == w) {
81 			label = pf.label; return;
82 		}
83 	}
84 
85 	float unit = 72.0; // currently inc[h]es only
86 	label << (w / unit) << "x" << (h / unit) << " in.";
87 }
88 
89 
90 ConfigWindow::ConfigWindow(config_setup_kind kind, Printer* defaultPrinter,
91 	BMessage* settings, AutoReply* sender)
92 	: BWindow(ConfigWindow::GetWindowFrame(), "Page Setup",
93 		B_TITLED_WINDOW, B_NOT_RESIZABLE | B_NOT_ZOOMABLE)
94 	, fKind(kind)
95 	, fDefaultPrinter(defaultPrinter)
96 	, fSettings(settings)
97 	, fSender(sender)
98 	, fCurrentPrinter(NULL)
99 	, fPageFormatText(NULL)
100 	, fJobSetupText(NULL)
101 {
102 	MimeTypeForSender(settings, fSenderMimeType);
103 	PrinterForMimeType();
104 
105 	if (kind == kJobSetup)
106 		SetTitle("Print Setup");
107 
108 	BView* panel = new BBox(Bounds(), "top_panel", B_FOLLOW_ALL,
109 					B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE_JUMP,
110 					B_PLAIN_BORDER);
111 
112 	AddChild(panel);
113 
114 	float left = 10, top = 10;
115 	BRect r(left, top, 160, 20);
116 
117 	// print selection popup menu
118 	BPopUpMenu* menu = new BPopUpMenu("Select a Printer");
119 	SetupPrintersMenu(menu);
120 
121 	float width = be_plain_font->StringWidth("Printer:") + 10.0;
122 	r.right = r.left + width + menu->MaxContentWidth() + 10;
123 	fPrinters = new BMenuField(r, "Printer", "Printer:", menu);
124 	fPrinters->SetDivider(width);
125 	panel->AddChild(fPrinters);
126 	top += fPrinters->Bounds().Height() + 10;
127 
128 	// page format button
129 	r.OffsetTo(left, top);
130 	fPageSetup = AddPictureButton(panel, r, "Page Format", "PAGE_SETUP_ON",
131 		"PAGE_SETUP_OFF", MSG_PAGE_SETUP);
132 
133 	// add description to button
134 	r.OffsetTo(left + fPageSetup->Bounds().Width() + 5, fPageSetup->Frame().top);
135 	BStringView *stringView = AddStringView(panel, r, "Paper Setup:");
136 	stringView->ResizeToPreferred();
137 	r = stringView->Frame();
138 	r.OffsetBy(0, r.Height());
139 	fPageFormatText = AddStringView(panel, r, "");
140 	fPageFormatText->ResizeToPreferred();
141 	top = fPageSetup->Frame().bottom + 15;
142 
143 	// page selection button
144 	fJobSetup = NULL;
145 	if (kind == kJobSetup) {
146 		r.OffsetTo(left, top);
147 		fJobSetup = AddPictureButton(panel, r, "Page Selection", "JOB_SETUP_ON",
148 			"JOB_SETUP_OFF", MSG_JOB_SETUP);
149 		// add description to button
150 		r.OffsetTo(left + fJobSetup->Bounds().Width() + 5, top);
151 		stringView = AddStringView(panel, r, "Pages to Print:");
152 		stringView->ResizeToPreferred();
153 		r.OffsetBy(0, stringView->Frame().Height());
154 		fJobSetupText = AddStringView(panel, r, "");
155 		fJobSetupText->ResizeToPreferred();
156 		top = fJobSetup->Frame().bottom + 15;
157 	}
158 	top += 5;
159 
160 	// separator line
161 	BRect line(Bounds());
162 	line.OffsetTo(0, top);
163 	line.bottom = line.top+1;
164 	AddChild(new BBox(line, "line", B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP));
165 	top += 10;
166 
167 	// Cancel button
168 	r.OffsetTo(left, top);
169 	BButton* cancel = new BButton(r, "Cancel", "Cancel",
170 		new BMessage(B_QUIT_REQUESTED));
171 	panel->AddChild(cancel);
172 	cancel->ResizeToPreferred();
173 	left = cancel->Frame().right + 10;
174 
175 	// OK button
176 	r.OffsetTo(left, top);
177 	fOk = new BButton(r, "OK", "OK", new BMessage(MSG_OK));
178 	panel->AddChild(fOk);
179 	fOk->ResizeToPreferred();
180 	top += fOk->Bounds().Height() + 10;
181 
182 	// resize window
183 	ResizeTo(fOk->Frame().right + 10, top);
184 
185 	AddShortcut('i', 0, new BMessage(B_ABOUT_REQUESTED));
186 
187 	SetDefaultButton(fOk);
188 
189 	fPrinters->MakeFocus(true);
190 
191 	UpdateSettings(true);
192 }
193 
194 ConfigWindow::~ConfigWindow()
195 {
196 	if (fCurrentPrinter)
197 		fCurrentPrinter->Release();
198 	release_sem(fFinished);
199 }
200 
201 
202 void ConfigWindow::Go()
203 {
204 	sem_id sid = create_sem(0, "finished");
205 	if (sid >= 0) {
206 		fFinished = sid;
207 		Show();
208 		acquire_sem(sid);
209 		delete_sem(sid);
210 	} else {
211 		Quit();
212 	}
213 }
214 
215 
216 void ConfigWindow::MessageReceived(BMessage* m)
217 {
218 	switch (m->what) {
219 		case MSG_PAGE_SETUP:
220 			Setup(kPageSetup);
221 			break;
222 		case MSG_JOB_SETUP:
223 			Setup(kJobSetup);
224 			break;
225 		case MSG_PRINTER_SELECTED: {
226 				BString printer;
227 				if (m->FindString("name", &printer) == B_OK) {
228 					UpdateAppSettings(fSenderMimeType.String(), printer.String());
229 					PrinterForMimeType();
230 					UpdateSettings(true);
231 				}
232 			}
233 			break;
234 		case MSG_OK:
235 			UpdateSettings(false);
236 			fSender->SetReply(fKind == kPageSetup ? &fPageSettings : &fJobSettings);
237 			Quit();
238 			break;
239 		case B_ABOUT_REQUESTED: AboutRequested();
240 			break;
241 		default:
242 			BWindow::MessageReceived(m);
243 	}
244 }
245 
246 
247 static const char*
248 kAbout =
249 "Printer Server\n"
250 "© 2001-2008 Haiku\n"
251 "\n"
252 "\tIthamar R. Adema - Initial Implementation\n"
253 "\tMichael Pfeiffer - Release 1 and beyond\n"
254 ;
255 
256 
257 void
258 ConfigWindow::AboutRequested()
259 {
260 	BAlert *about = new BAlert("About Printer Server", kAbout, "OK");
261 	about->Go();
262 }
263 
264 
265 void ConfigWindow::FrameMoved(BPoint p)
266 {
267 	BRect frame = GetWindowFrame();
268 	frame.OffsetTo(p);
269 	SetWindowFrame(frame);
270 }
271 
272 
273 BRect ConfigWindow::GetWindowFrame()
274 {
275 	BAutolock lock(gLock);
276 	if (lock.IsLocked())
277 		return Settings::GetSettings()->ConfigWindowFrame();
278 
279 	return BRect(30, 30, 300, 300);
280 }
281 
282 
283 void ConfigWindow::SetWindowFrame(BRect r)
284 {
285 	BAutolock lock(gLock);
286 	if (lock.IsLocked())
287 		Settings::GetSettings()->SetConfigWindowFrame(r);
288 }
289 
290 
291 BPictureButton* ConfigWindow::AddPictureButton(BView* panel, BRect frame,
292 	const char* name, const char* on, const char* off, uint32 what)
293 {
294 	BBitmap* onBM = LoadBitmap(on);
295 	BBitmap* offBM = LoadBitmap(off);
296 
297 	BPicture* onPict = BitmapToPicture(panel, onBM);
298 	BPicture* offPict = BitmapToPicture(panel, offBM);
299 
300 	BPictureButton* button = NULL;
301 
302 	if (onPict != NULL && offPict != NULL) {
303 		button = new BPictureButton(frame, name, onPict, offPict, new BMessage(what));
304 		button->SetViewColor(B_TRANSPARENT_COLOR);
305 		panel->AddChild(button);
306 		onBM->Lock();
307 		button->ResizeTo(onBM->Bounds().Width(), onBM->Bounds().Height());
308 		onBM->Unlock();
309 
310 		BPicture* disabled = BitmapToGrayedPicture(panel, offBM);
311 		button->SetDisabledOn(disabled);
312 		delete disabled;
313 
314 		disabled = BitmapToGrayedPicture(panel, onBM);
315 		button->SetDisabledOff(disabled);
316 		delete disabled;
317 	}
318 
319 	delete onPict; delete offPict;
320 	delete onBM; delete offBM;
321 
322 	return button;
323 }
324 
325 
326 BStringView* ConfigWindow::AddStringView(BView* panel, BRect frame, const char* text)
327 {
328 	// frame.bottom = frame.top ;
329 	BStringView* string = new BStringView(frame, "", text);
330 	string->SetViewColor(panel->ViewColor());
331 	string->SetLowColor(panel->ViewColor());
332  	panel->AddChild(string);
333  	return string;
334 }
335 
336 
337 void ConfigWindow::PrinterForMimeType()
338 {
339 	BAutolock lock(gLock);
340 	if (fCurrentPrinter) {
341 		fCurrentPrinter->Release();
342 		fCurrentPrinter = NULL;
343 	}
344 
345 	if (lock.IsLocked()) {
346 		Settings* s = Settings::GetSettings();
347 		AppSettings* app = s->FindAppSettings(fSenderMimeType.String());
348 		if (app) {
349 			fPrinterName = app->GetPrinter();
350 		} else {
351 			fPrinterName = fDefaultPrinter ? fDefaultPrinter->Name() : "";
352 		}
353 		fCurrentPrinter = Printer::Find(fPrinterName);
354 		if (fCurrentPrinter)
355 			fCurrentPrinter->Acquire();
356 	}
357 }
358 
359 
360 void ConfigWindow::SetupPrintersMenu(BMenu* menu)
361 {
362 	// clear menu
363 	while (menu->CountItems() != 0)
364 		delete menu->RemoveItem(0L);
365 
366 	// fill menu with printer names
367 	BAutolock lock(gLock);
368 	if (lock.IsLocked()) {
369 		BString n;
370 		BMessage* m;
371 		BMenuItem* item;
372 		for (int i = 0; i < Printer::CountPrinters(); i ++) {
373 			Printer::At(i)->GetName(n);
374 			m = new BMessage(MSG_PRINTER_SELECTED);
375 			m->AddString("name", n.String());
376 			menu->AddItem(item = new BMenuItem(n.String(), m));
377 			if (n == fPrinterName)
378 				item->SetMarked(true);
379 		}
380 	}
381 }
382 
383 
384 void ConfigWindow::UpdateAppSettings(const char* mime, const char* printer)
385 {
386 	BAutolock lock(gLock);
387 	if (lock.IsLocked()) {
388 		Settings* s = Settings::GetSettings();
389 		AppSettings* app = s->FindAppSettings(mime);
390 		if (app)
391 			app->SetPrinter(printer);
392 		else
393 			s->AddAppSettings(new AppSettings(mime, printer));
394 	}
395 }
396 
397 
398 void ConfigWindow::UpdateSettings(bool read)
399 {
400 	BAutolock lock(gLock);
401 	if (lock.IsLocked()) {
402 		Settings* s = Settings::GetSettings();
403 		PrinterSettings* p = s->FindPrinterSettings(fPrinterName.String());
404 		if (p == NULL) {
405 			p = new PrinterSettings(fPrinterName.String());
406 			s->AddPrinterSettings(p);
407 		}
408 		ASSERT(p != NULL);
409 		if (read) {
410 			fPageSettings = *p->GetPageSettings();
411 			fJobSettings = *p->GetJobSettings();
412 		} else {
413 			p->SetPageSettings(&fPageSettings);
414 			p->SetJobSettings(&fJobSettings);
415 		}
416 	}
417 	UpdateUI();
418 }
419 
420 
421 void ConfigWindow::UpdateUI()
422 {
423 	if (fCurrentPrinter == NULL) {
424 		fPageSetup->SetEnabled(false);
425 		if (fJobSetup) {
426 			fJobSetup->SetEnabled(false);
427 			fJobSetupText->SetText("Undefined job settings");
428 			fJobSetupText->ResizeToPreferred();
429 		}
430 		fOk->SetEnabled(false);
431 		fPageFormatText->SetText("Undefined paper format");
432 		fPageFormatText->ResizeToPreferred();
433 	} else {
434 		fPageSetup->SetEnabled(true);
435 
436 		if (fJobSetup)
437 			fJobSetup->SetEnabled(fKind == kJobSetup && !fPageSettings.IsEmpty());
438 
439 		fOk->SetEnabled(fKind == kJobSetup && !fJobSettings.IsEmpty() ||
440 			fKind == kPageSetup && !fPageSettings.IsEmpty());
441 
442 		// display information about page format
443 		BRect paperRect;
444 		BString pageFormat;
445 		if (fPageSettings.FindRect(PSRV_FIELD_PAPER_RECT, &paperRect) == B_OK) {
446 			GetPageFormat(paperRect.Width(), paperRect.Height(), pageFormat);
447 
448 			int32 orientation = 0;
449 			fPageSettings.FindInt32(PSRV_FIELD_ORIENTATION, &orientation);
450 			if (orientation == 0)
451 				pageFormat << ", Portrait";
452 			else
453 				pageFormat << ", Landscape";
454 		} else {
455 			pageFormat << "Undefined paper format";
456 		}
457 		fPageFormatText->SetText(pageFormat.String());
458 		fPageFormatText->ResizeToPreferred();
459 
460 			// display information about job
461 		if (fKind == kJobSetup) {
462 			BString job;
463 			int32 first, last;
464 			if (fJobSettings.FindInt32(PSRV_FIELD_FIRST_PAGE, &first) == B_OK &&
465 				fJobSettings.FindInt32(PSRV_FIELD_LAST_PAGE, &last) == B_OK) {
466 				if (first >= 1 && first <= last && last != INT_MAX) {
467 					job << "From page " << first << " to " << last;
468 				} else {
469 					job << "All pages";
470 				}
471 				int32 copies;
472 				if (fJobSettings.FindInt32(PSRV_FIELD_COPIES, &copies)
473 					== B_OK && copies > 1) {
474 					job << ", " << copies << " copies";
475 				}
476 			} else {
477 				job << "Undefined job settings";
478 			}
479 			fJobSetupText->SetText(job.String());
480 			fJobSetupText->ResizeToPreferred();
481 		}
482 	}
483 
484 	if (fOk->Frame().right < fPageFormatText->Frame().right)
485 		ResizeTo(fPageFormatText->Frame().right + 10, Bounds().bottom);
486 
487 	if (fJobSetupText) {
488 		if (fOk->Frame().right < fJobSetupText->Frame().right)
489 			ResizeTo(fJobSetupText->Frame().right + 10, Bounds().bottom);
490 	}
491 }
492 
493 
494 void ConfigWindow::Setup(config_setup_kind kind)
495 {
496 	if (fCurrentPrinter) {
497 		Hide();
498 		if (kind == kPageSetup) {
499 			BMessage settings = fPageSettings;
500 			if (fCurrentPrinter->ConfigurePage(settings) == B_OK) {
501 				fPageSettings = settings;
502 				if (!fJobSettings.IsEmpty())
503 					AddFields(&fJobSettings, &fPageSettings);
504 			}
505 		} else {
506 			BMessage settings;
507 			if (fJobSettings.IsEmpty()) settings = fPageSettings;
508 			else settings = fJobSettings;
509 
510 			if (fCurrentPrinter->ConfigureJob(settings) == B_OK)
511 				fJobSettings = settings;
512 		}
513 		UpdateUI();
514 		Show();
515 	}
516 }
517