xref: /haiku/src/servers/print/ConfigWindow.cpp (revision 24159a0c7d6d6dcba9f2a0c1a7c08d2c8167f21b)
1 /*****************************************************************************/
2 // ConfigWindow
3 //
4 // Author
5 //   Michael Pfeiffer
6 //
7 // This application and all source files used in its construction, except
8 // where noted, are licensed under the MIT License, and have been written
9 // and are:
10 //
11 // Copyright (c) 2002 OpenBeOS Project
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining a
14 // copy of this software and associated documentation files (the "Software"),
15 // to deal in the Software without restriction, including without limitation
16 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 // and/or sell copies of the Software, and to permit persons to whom the
18 // Software is furnished to do so, subject to the following conditions:
19 //
20 // The above copyright notice and this permission notice shall be included
21 // in all copies or substantial portions of the Software.
22 //
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 // DEALINGS IN THE SOFTWARE.
30 /*****************************************************************************/
31 
32 
33 #include "pr_server.h"
34 #include "Printer.h"
35 #include "PrintServerApp.h"
36 #include "ConfigWindow.h"
37 #include "BeUtils.h"
38 
39 // posix
40 #include <limits.h>
41 #include <math.h>
42 #include <stdlib.h>
43 #include <string.h>
44 
45 // BeOS
46 #include <Application.h>
47 #include <Autolock.h>
48 #include <Window.h>
49 
50 static const float a0_width = 2380.0;
51 static const float a0_height = 3368.0;
52 static const float a1_width = 1684.0;
53 static const float a1_height = 2380.0;
54 static const float a2_width = 1190.0;
55 static const float a2_height = 1684.0;
56 static const float a3_width = 842.0;
57 static const float a3_height = 1190.0;
58 static const float a4_width = 595.0;
59 static const float a4_height = 842.0;
60 static const float a5_width = 421.0;
61 static const float a5_height = 595.0;
62 static const float a6_width = 297.0;
63 static const float a6_height = 421.0;
64 static const float b5_width = 501.0;
65 static const float b5_height = 709.0;
66 static const float letter_width = 612.0;
67 static const float letter_height = 792.0;
68 static const float legal_width  = 612.0;
69 static const float legal_height  = 1008.0;
70 static const float ledger_width = 1224.0;
71 static const float ledger_height = 792.0;
72 static const float p11x17_width = 792.0;
73 static const float p11x17_height = 1224.0;
74 
75 static struct PageFormat
76 {
77 	char  *label;
78 	float width;
79 	float height;
80 } pageFormat[] =
81 {
82 	{"Letter", letter_width, letter_height },
83 	{"Legal",  legal_width,  legal_height  },
84 	{"Ledger", ledger_width, ledger_height  },
85 	{"p11x17", p11x17_width, p11x17_height  },
86 	{"A0",     a0_width,     a0_height     },
87 	{"A1",     a1_width,     a1_height     },
88 	{"A2",     a2_width,     a2_height     },
89 	{"A3",     a3_width,     a3_height     },
90 	{"A4",     a4_width,     a4_height     },
91 	{"A5",     a5_width,     a5_height     },
92 	{"A6",     a6_width,     a6_height     },
93 	{"B5",     b5_width,     b5_height     },
94 };
95 
96 static void GetPageFormat(float w, float h, BString& label) {
97 	w = floor(w + 0.5); h = floor(h + 0.5);
98 	for (uint i = 0; i < sizeof(pageFormat) / sizeof(struct PageFormat); i ++) {
99 		struct PageFormat& pf = pageFormat[i];
100 		if (pf.width == w && pf.height == h || pf.width == h && pf.height == w) {
101 			label = pf.label; return;
102 		}
103 	}
104 
105 	float unit = 72.0; // currently inc[h]es only
106 	label << (w / unit) << "x" << (h / unit) << " in.";
107 }
108 
109 ConfigWindow::ConfigWindow(config_setup_kind kind, Printer* defaultPrinter, BMessage* settings, AutoReply* sender)
110 	: BWindow(ConfigWindow::GetWindowFrame(), "Page Setup",
111 		B_TITLED_WINDOW, B_NOT_RESIZABLE | B_NOT_ZOOMABLE)
112 	, fKind(kind)
113 	, fDefaultPrinter(defaultPrinter)
114 	, fSettings(settings)
115 	, fSender(sender)
116 	, fCurrentPrinter(NULL)
117 {
118 	MimeTypeForSender(settings, fSenderMimeType);
119 	PrinterForMimeType();
120 
121 	if (kind == kJobSetup) SetTitle("Print Setup");
122 
123 	BView* panel = new BBox(Bounds(), "top_panel", B_FOLLOW_ALL,
124 					B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE_JUMP,
125 					B_PLAIN_BORDER);
126 
127 	AddChild(panel);
128 
129 	float left = 10, top = 5;
130 	BRect r(left, top, 160, 15);
131 
132 		// print selection popup menu
133 	BPopUpMenu* menu = new BPopUpMenu("Select a Printer");
134 	SetupPrintersMenu(menu);
135 
136 	fPrinters = new BMenuField(r, "Printer", "Printer", menu);
137 	fPrinters->SetDivider(40);
138 	panel->AddChild(fPrinters);
139 	top += fPrinters->Bounds().Height() + 10;
140 
141 		// page format button
142 	r.OffsetTo(left, top);
143 	fPageSetup = AddPictureButton(panel, r, "Page Format", "PAGE_SETUP_ON", "PAGE_SETUP_OFF", MSG_PAGE_SETUP);
144 		// add description to button
145 	r.OffsetTo(left + fPageSetup->Bounds().Width() + 5, top + 5);
146 	AddStringView(panel, r, "Setup page format");
147 	r.OffsetBy(0, 10);
148 	fPageFormatText = AddStringView(panel, r, "");
149 	top += fPageSetup->Bounds().Height() + 5;
150 
151 		// page selection button
152 	fJobSetup = NULL;
153 	if (kind == kJobSetup) {
154 		r.OffsetTo(left, top);
155 		fJobSetup = AddPictureButton(panel, r, "Page Selection", "JOB_SETUP_ON", "JOB_SETUP_OFF", MSG_JOB_SETUP);
156 			// add description to button
157 		r.OffsetTo(left + fJobSetup->Bounds().Width() + 5, top + 5);
158 		AddStringView(panel, r, "Setup print job");
159 		r.OffsetBy(0, 10);
160 		fJobSetupText = AddStringView(panel, r, "");
161 		top += fJobSetup->Bounds().Height() + 5;
162 	}
163 	top += 5;
164 
165 		// separator line
166 	BRect line(Bounds());
167 	line.OffsetTo(0, top);
168 	line.bottom = line.top+1;
169 	AddChild(new BBox(line, "line", B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP));
170 	top += 10;
171 
172 		// Cancel button
173 	r.OffsetTo(left, top);
174 	BButton* cancel = new BButton(r, "Cancel", "Cancel", new BMessage(B_QUIT_REQUESTED));
175 	panel->AddChild(cancel);
176 	cancel->ResizeToPreferred();
177 	left = cancel->Frame().right + 10;
178 
179 		// OK button
180 	r.OffsetTo(left, top);
181 	fOk = new BButton(r, "OK", "OK", new BMessage(MSG_OK));
182 	panel->AddChild(fOk);
183 	fOk->ResizeToPreferred();
184 	top += fOk->Bounds().Height() + 10;
185 
186 		// resize window
187 	ResizeTo(fOk->Frame().right + 10, top);
188 
189 	AddShortcut('i', 0, new BMessage(B_ABOUT_REQUESTED));
190 
191 	SetDefaultButton(fOk);
192 
193 	fPrinters->MakeFocus(true);
194 
195 	UpdateSettings(true);
196 }
197 
198 ConfigWindow::~ConfigWindow() {
199 	if (fCurrentPrinter) fCurrentPrinter->Release();
200 	release_sem(fFinished);
201 }
202 
203 void ConfigWindow::Go() {
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 void ConfigWindow::MessageReceived(BMessage* m) {
216 	switch (m->what) {
217 		case MSG_PAGE_SETUP: Setup(kPageSetup);
218 			break;
219 		case MSG_JOB_SETUP: Setup(kJobSetup);
220 			break;
221 		case MSG_PRINTER_SELECTED: {
222 				BString printer;
223 				if (m->FindString("name", &printer) == B_OK) {
224 					UpdateAppSettings(fSenderMimeType.String(), printer.String());
225 					PrinterForMimeType();
226 					UpdateSettings(true);
227 				}
228 			}
229 			break;
230 		case MSG_OK:
231 			UpdateSettings(false);
232 			fSender->SetReply(fKind == kPageSetup ? &fPageSettings : &fJobSettings);
233 			Quit();
234 			break;
235 		case B_ABOUT_REQUESTED: AboutRequested();
236 			break;
237 		default:
238 			inherited::MessageReceived(m);
239 	}
240 }
241 
242 static const char*
243 kAbout =
244 "Printer Server\n"
245 "© 2001, 2002 OpenBeOS\n"
246 "\n"
247 "\tIthamar R. Adema - Initial Implementation\n"
248 "\tMichael Pfeiffer - Release 1 and beyond\n"
249 ;
250 
251 void
252 ConfigWindow::AboutRequested()
253 {
254 	BAlert *about = new BAlert("About Printer Server", kAbout, "Cool");
255 	BTextView *v = about->TextView();
256 	if (v) {
257 		rgb_color red = {255, 0, 51, 255};
258 		rgb_color blue = {0, 102, 255, 255};
259 
260 		v->SetStylable(true);
261 		char *text = (char*)v->Text();
262 		char *s = text;
263 		// set all Be in blue and red
264 		while ((s = strstr(s, "Be")) != NULL) {
265 			int32 i = s - text;
266 			v->SetFontAndColor(i, i+1, NULL, 0, &blue);
267 			v->SetFontAndColor(i+1, i+2, NULL, 0, &red);
268 			s += 2;
269 		}
270 		// first text line
271 		s = strchr(text, '\n');
272 		BFont font;
273 		v->GetFontAndColor(0, &font);
274 		font.SetSize(12);
275 		v->SetFontAndColor(0, s-text+1, &font, B_FONT_SIZE);
276 	};
277 	about->Go();
278 }
279 
280 
281 void ConfigWindow::FrameMoved(BPoint p) {
282 	BRect frame = GetWindowFrame();
283 	frame.OffsetTo(p);
284 	SetWindowFrame(frame);
285 }
286 
287 BRect ConfigWindow::GetWindowFrame() {
288 	BAutolock lock(gLock);
289 	if (lock.IsLocked()) {
290 		return Settings::GetSettings()->ConfigWindowFrame();
291 	}
292 	return BRect(30, 30, 300, 300);
293 }
294 
295 void ConfigWindow::SetWindowFrame(BRect r) {
296 	BAutolock lock(gLock);
297 	if (lock.IsLocked()) {
298 		Settings::GetSettings()->SetConfigWindowFrame(r);
299 	}
300 }
301 
302 BPictureButton* ConfigWindow::AddPictureButton(BView* panel, BRect frame, const char* name, const char* on, const char* off, uint32 what) {
303 	BBitmap* onBM = LoadBitmap(on);
304 	BBitmap* offBM = LoadBitmap(off);
305 
306 	BPicture* onPict = BitmapToPicture(panel, onBM);
307 	BPicture* offPict = BitmapToPicture(panel, offBM);
308 
309 	BPictureButton* button = NULL;
310 
311 	if (onPict != NULL && offPict != NULL) {
312 		button = new BPictureButton(frame, name, onPict, offPict, new BMessage(what));
313 		button->SetViewColor(B_TRANSPARENT_COLOR);
314 		panel->AddChild(button);
315 		onBM->Lock();
316 		button->ResizeTo(onBM->Bounds().Width(), onBM->Bounds().Height());
317 		onBM->Unlock();
318 
319 		BPicture* disabled = BitmapToGrayedPicture(panel, offBM);
320 		button->SetDisabledOn(disabled);
321 		delete disabled;
322 
323 		disabled = BitmapToGrayedPicture(panel, onBM);
324 		button->SetDisabledOff(disabled);
325 		delete disabled;
326 	}
327 
328 	delete onPict; delete offPict;
329 	delete onBM; delete offBM;
330 
331 	return button;
332 }
333 
334 BStringView* ConfigWindow::AddStringView(BView* panel, BRect frame, const char* text) {
335 	// frame.bottom = frame.top ;
336 	BStringView* string = new BStringView(frame, "", text);
337 	string->SetViewColor(panel->ViewColor());
338 	string->SetLowColor(panel->ViewColor());
339  	panel->AddChild(string);
340  	return string;
341 }
342 
343 void ConfigWindow::PrinterForMimeType() {
344 	BAutolock lock(gLock);
345 	if (fCurrentPrinter) {
346 		fCurrentPrinter->Release(); fCurrentPrinter = NULL;
347 	}
348 	if (lock.IsLocked()) {
349 		Settings* s = Settings::GetSettings();
350 		AppSettings* app = s->FindAppSettings(fSenderMimeType.String());
351 		if (app) {
352 			fPrinterName = app->GetPrinter();
353 		} else {
354 			fPrinterName = fDefaultPrinter ? fDefaultPrinter->Name() : "";
355 		}
356 		fCurrentPrinter = Printer::Find(fPrinterName);
357 		if (fCurrentPrinter) fCurrentPrinter->Acquire();
358 	}
359 }
360 
361 void ConfigWindow::SetupPrintersMenu(BMenu* menu) {
362 		// clear menu
363 	for (int i = menu->CountItems() - 1; i >= 0; i --) {
364 		delete menu->RemoveItem(i);
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) item->SetMarked(true);
378 		}
379 	}
380 }
381 
382 void ConfigWindow::UpdateAppSettings(const char* mime, const char* printer) {
383 	BAutolock lock(gLock);
384 	if (lock.IsLocked()) {
385 		Settings* s = Settings::GetSettings();
386 		AppSettings* app = s->FindAppSettings(mime);
387 		if (app) app->SetPrinter(printer);
388 		else s->AddAppSettings(new AppSettings(mime, printer));
389 	}
390 }
391 
392 void ConfigWindow::UpdateSettings(bool read) {
393 	BAutolock lock(gLock);
394 	if (lock.IsLocked()) {
395 		Settings* s = Settings::GetSettings();
396 		PrinterSettings* p = s->FindPrinterSettings(fPrinterName.String());
397 		if (p == NULL) {
398 			p = new PrinterSettings(fPrinterName.String());
399 			s->AddPrinterSettings(p);
400 		}
401 		ASSERT(p != NULL);
402 		if (read) {
403 			fPageSettings = *p->GetPageSettings();
404 			fJobSettings = *p->GetJobSettings();
405 		} else {
406 			p->SetPageSettings(&fPageSettings);
407 			p->SetJobSettings(&fJobSettings);
408 		}
409 	}
410 	UpdateUI();
411 }
412 
413 void ConfigWindow::UpdateUI() {
414 	if (fCurrentPrinter == NULL) {
415 		fPageSetup->SetEnabled(false);
416 		if (fJobSetup) {
417 			fJobSetup->SetEnabled(false);
418 			fJobSetupText->SetText("Undefined job settings");
419 		}
420 		fOk->SetEnabled(false);
421 		fPageFormatText->SetText("Undefined paper format");
422 	} else {
423 		fPageSetup->SetEnabled(true);
424 
425 		if (fJobSetup) {
426 			fJobSetup->SetEnabled(fKind == kJobSetup && !fPageSettings.IsEmpty());
427 		}
428 		fOk->SetEnabled(fKind == kJobSetup && !fJobSettings.IsEmpty() ||
429 			fKind == kPageSetup && !fPageSettings.IsEmpty());
430 
431 			// display information about page format
432 		BRect paperRect;
433 		BString pageFormat;
434 		if (fPageSettings.FindRect(PSRV_FIELD_PAPER_RECT, &paperRect) == B_OK) {
435 			GetPageFormat(paperRect.Width(), paperRect.Height(), pageFormat);
436 
437 			int32 orientation = 0;
438 			fPageSettings.FindInt32(PSRV_FIELD_ORIENTATION, &orientation);
439 			if (orientation == 0) pageFormat << ", Portrait";
440 			else pageFormat << ", Landscape";
441 		} else {
442 			pageFormat << "Undefined paper format";
443 		}
444 		fPageFormatText->SetText(pageFormat.String());
445 
446 			// display information about job
447 		if (fKind == kJobSetup) {
448 			BString job;
449 			int32 first, last;
450 			if (fJobSettings.FindInt32(PSRV_FIELD_FIRST_PAGE, &first) == B_OK &&
451 				fJobSettings.FindInt32(PSRV_FIELD_LAST_PAGE, &last) == B_OK) {
452 				if (first >= 1 && first <= last && last != INT_MAX) {
453 					job << "From page " << first << " to " << last;
454 				} else {
455 					job << "All pages";
456 				}
457 				int32 copies;
458 				if (fJobSettings.FindInt32(PSRV_FIELD_COPIES, &copies) == B_OK && copies > 1) {
459 					job << ", " << copies << " copies";
460 				}
461 			} else {
462 				job << "Undefined job settings";
463 			}
464 
465 			fJobSetupText->SetText(job.String());
466 		}
467 	}
468 }
469 
470 void ConfigWindow::Setup(config_setup_kind kind) {
471 	if (fCurrentPrinter) {
472 		Hide();
473 		if (kind == kPageSetup) {
474 			BMessage settings = fPageSettings;
475 			if (fCurrentPrinter->ConfigurePage(settings) == B_OK) {
476 				fPageSettings = settings;
477 				if (!fJobSettings.IsEmpty()) AddFields(&fJobSettings, &fPageSettings);
478 			}
479 		} else {
480 			BMessage settings;
481 			if (fJobSettings.IsEmpty()) settings = fPageSettings;
482 			else settings = fJobSettings;
483 
484 			if (fCurrentPrinter->ConfigureJob(settings) == B_OK)
485 				fJobSettings = settings;
486 		}
487 		UpdateUI();
488 		Show();
489 	}
490 }
491