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