xref: /haiku/src/servers/print/ConfigWindow.cpp (revision 7120e97489acbf17d86d3f33e3b2e68974fd4b23)
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 (int 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 	BStringView* string;
132 
133 		// print selection popup menu
134 	BPopUpMenu* menu = new BPopUpMenu("Select a Printer");
135 	SetupPrintersMenu(menu);
136 
137 	fPrinters = new BMenuField(r, "Printer", "Printer", menu);
138 	fPrinters->SetDivider(40);
139 	panel->AddChild(fPrinters);
140 	top += fPrinters->Bounds().Height() + 10;
141 
142 		// page format button
143 	r.OffsetTo(left, top);
144 	fPageSetup = AddPictureButton(panel, r, "Page Format", "PAGE_SETUP_ON", "PAGE_SETUP_OFF", MSG_PAGE_SETUP);
145 		// add description to button
146 	r.OffsetTo(left + fPageSetup->Bounds().Width() + 5, top + 5);
147 	AddStringView(panel, r, "Setup page format");
148 	r.OffsetBy(0, 10);
149 	fPageFormatText = AddStringView(panel, r, "");
150 	top += fPageSetup->Bounds().Height() + 5;
151 
152 		// page selection button
153 	fJobSetup = NULL;
154 	if (kind == kJobSetup) {
155 		r.OffsetTo(left, top);
156 		fJobSetup = AddPictureButton(panel, r, "Page Selection", "JOB_SETUP_ON", "JOB_SETUP_OFF", MSG_JOB_SETUP);
157 			// add description to button
158 		r.OffsetTo(left + fJobSetup->Bounds().Width() + 5, top + 5);
159 		AddStringView(panel, r, "Setup print job");
160 		r.OffsetBy(0, 10);
161 		fJobSetupText = AddStringView(panel, r, "");
162 		top += fJobSetup->Bounds().Height() + 5;
163 	}
164 	top += 5;
165 
166 		// separator line
167 	BRect line(Bounds());
168 	line.OffsetTo(0, top);
169 	line.bottom = line.top+1;
170 	AddChild(new BBox(line, "line", B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP));
171 	top += 10;
172 
173 		// Cancel button
174 	r.OffsetTo(left, top);
175 	BButton* cancel = new BButton(r, "Cancel", "Cancel", new BMessage(B_QUIT_REQUESTED));
176 	panel->AddChild(cancel);
177 	cancel->ResizeToPreferred();
178 	left = cancel->Frame().right + 10;
179 
180 		// OK button
181 	r.OffsetTo(left, top);
182 	fOk = new BButton(r, "OK", "OK", new BMessage(MSG_OK));
183 	panel->AddChild(fOk);
184 	fOk->ResizeToPreferred();
185 	top += fOk->Bounds().Height() + 10;
186 
187 		// resize window
188 	ResizeTo(fOk->Frame().right + 10, top);
189 
190 	AddShortcut('i', 0, new BMessage(B_ABOUT_REQUESTED));
191 
192 	SetDefaultButton(fOk);
193 
194 	fPrinters->MakeFocus(true);
195 
196 	UpdateSettings(true);
197 }
198 
199 ConfigWindow::~ConfigWindow() {
200 	if (fCurrentPrinter) fCurrentPrinter->Release();
201 	release_sem(fFinished);
202 }
203 
204 void ConfigWindow::Go() {
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 void ConfigWindow::MessageReceived(BMessage* m) {
217 	switch (m->what) {
218 		case MSG_PAGE_SETUP: Setup(kPageSetup);
219 			break;
220 		case MSG_JOB_SETUP: Setup(kJobSetup);
221 			break;
222 		case MSG_PRINTER_SELECTED: {
223 				BString printer;
224 				if (m->FindString("name", &printer) == B_OK) {
225 					UpdateAppSettings(fSenderMimeType.String(), printer.String());
226 					PrinterForMimeType();
227 					UpdateSettings(true);
228 				}
229 			}
230 			break;
231 		case MSG_OK:
232 			UpdateSettings(false);
233 			fSender->SetReply(fKind == kPageSetup ? &fPageSettings : &fJobSettings);
234 			Quit();
235 			break;
236 		case B_ABOUT_REQUESTED: AboutRequested();
237 			break;
238 		default:
239 			inherited::MessageReceived(m);
240 	}
241 }
242 
243 static const char*
244 kAbout =
245 "Printer Server\n"
246 "© 2001, 2002 OpenBeOS\n"
247 "\n"
248 "\tIthamar R. Adema - Initial Implementation\n"
249 "\tMichael Pfeiffer - Release 1 and beyond\n"
250 ;
251 
252 void
253 ConfigWindow::AboutRequested()
254 {
255 	BAlert *about = new BAlert("About Printer Server", kAbout, "Cool");
256 	BTextView *v = about->TextView();
257 	if (v) {
258 		rgb_color red = {255, 0, 51, 255};
259 		rgb_color blue = {0, 102, 255, 255};
260 
261 		v->SetStylable(true);
262 		char *text = (char*)v->Text();
263 		char *s = text;
264 		// set all Be in blue and red
265 		while ((s = strstr(s, "Be")) != NULL) {
266 			int32 i = s - text;
267 			v->SetFontAndColor(i, i+1, NULL, 0, &blue);
268 			v->SetFontAndColor(i+1, i+2, NULL, 0, &red);
269 			s += 2;
270 		}
271 		// first text line
272 		s = strchr(text, '\n');
273 		BFont font;
274 		v->GetFontAndColor(0, &font);
275 		font.SetSize(12);
276 		v->SetFontAndColor(0, s-text+1, &font, B_FONT_SIZE);
277 	};
278 	about->Go();
279 }
280 
281 
282 void ConfigWindow::FrameMoved(BPoint p) {
283 	BRect frame = GetWindowFrame();
284 	frame.OffsetTo(p);
285 	SetWindowFrame(frame);
286 }
287 
288 BRect ConfigWindow::GetWindowFrame() {
289 	BAutolock lock(gLock);
290 	if (lock.IsLocked()) {
291 		return Settings::GetSettings()->ConfigWindowFrame();
292 	}
293 	return BRect(30, 30, 300, 300);
294 }
295 
296 void ConfigWindow::SetWindowFrame(BRect r) {
297 	BAutolock lock(gLock);
298 	if (lock.IsLocked()) {
299 		Settings::GetSettings()->SetConfigWindowFrame(r);
300 	}
301 }
302 
303 BPictureButton* ConfigWindow::AddPictureButton(BView* panel, BRect frame, const char* name, const char* on, const char* off, uint32 what) {
304 	BBitmap* onBM = LoadBitmap(on);
305 	BBitmap* offBM = LoadBitmap(off);
306 
307 	BPicture* onPict = BitmapToPicture(panel, onBM);
308 	BPicture* offPict = BitmapToPicture(panel, offBM);
309 
310 	BPictureButton* button = NULL;
311 
312 	if (onPict != NULL && offPict != NULL) {
313 		button = new BPictureButton(frame, name, onPict, offPict, new BMessage(what));
314 		button->SetViewColor(B_TRANSPARENT_COLOR);
315 		panel->AddChild(button);
316 		onBM->Lock();
317 		button->ResizeTo(onBM->Bounds().Width(), onBM->Bounds().Height());
318 		onBM->Unlock();
319 
320 		BPicture* disabled = BitmapToGrayedPicture(panel, offBM);
321 		button->SetDisabledOn(disabled);
322 		delete disabled;
323 
324 		disabled = BitmapToGrayedPicture(panel, onBM);
325 		button->SetDisabledOff(disabled);
326 		delete disabled;
327 	}
328 
329 	delete onPict; delete offPict;
330 	delete onBM; delete offBM;
331 
332 	return button;
333 }
334 
335 BStringView* ConfigWindow::AddStringView(BView* panel, BRect frame, const char* text) {
336 	// frame.bottom = frame.top ;
337 	BStringView* string = new BStringView(frame, "", text);
338 	string->SetViewColor(panel->ViewColor());
339 	string->SetLowColor(panel->ViewColor());
340  	panel->AddChild(string);
341  	return string;
342 }
343 
344 void ConfigWindow::PrinterForMimeType() {
345 	BAutolock lock(gLock);
346 	if (fCurrentPrinter) {
347 		fCurrentPrinter->Release(); fCurrentPrinter = NULL;
348 	}
349 	if (lock.IsLocked()) {
350 		Settings* s = Settings::GetSettings();
351 		AppSettings* app = s->FindAppSettings(fSenderMimeType.String());
352 		if (app) {
353 			fPrinterName = app->GetPrinter();
354 		} else {
355 			fPrinterName = fDefaultPrinter ? fDefaultPrinter->Name() : "";
356 		}
357 		fCurrentPrinter = Printer::Find(fPrinterName);
358 		if (fCurrentPrinter) fCurrentPrinter->Acquire();
359 	}
360 }
361 
362 void ConfigWindow::SetupPrintersMenu(BMenu* menu) {
363 		// clear menu
364 	for (int i = menu->CountItems() - 1; i >= 0; i --) {
365 		delete menu->RemoveItem(i);
366 	}
367 		// fill menu with printer names
368 	BAutolock lock(gLock);
369 	if (lock.IsLocked()) {
370 		BString n;
371 		Printer* p;
372 		BMessage* m;
373 		BMenuItem* item;
374 		for (int i = 0; i < Printer::CountPrinters(); i ++) {
375 			Printer::At(i)->GetName(n);
376 			m = new BMessage(MSG_PRINTER_SELECTED);
377 			m->AddString("name", n.String());
378 			menu->AddItem(item = new BMenuItem(n.String(), m));
379 			if (n == fPrinterName) item->SetMarked(true);
380 		}
381 	}
382 }
383 
384 void ConfigWindow::UpdateAppSettings(const char* mime, const char* printer) {
385 	BAutolock lock(gLock);
386 	if (lock.IsLocked()) {
387 		Settings* s = Settings::GetSettings();
388 		AppSettings* app = s->FindAppSettings(mime);
389 		if (app) app->SetPrinter(printer);
390 		else s->AddAppSettings(new AppSettings(mime, printer));
391 	}
392 }
393 
394 void ConfigWindow::UpdateSettings(bool read) {
395 	BAutolock lock(gLock);
396 	if (lock.IsLocked()) {
397 		Settings* s = Settings::GetSettings();
398 		PrinterSettings* p = s->FindPrinterSettings(fPrinterName.String());
399 		if (p == NULL) {
400 			p = new PrinterSettings(fPrinterName.String());
401 			s->AddPrinterSettings(p);
402 		}
403 		ASSERT(p != NULL);
404 		if (read) {
405 			fPageSettings = *p->GetPageSettings();
406 			fJobSettings = *p->GetJobSettings();
407 		} else {
408 			p->SetPageSettings(&fPageSettings);
409 			p->SetJobSettings(&fJobSettings);
410 		}
411 	}
412 	UpdateUI();
413 }
414 
415 void ConfigWindow::UpdateUI() {
416 	if (fCurrentPrinter == NULL) {
417 		fPageSetup->SetEnabled(false);
418 		if (fJobSetup) {
419 			fJobSetup->SetEnabled(false);
420 			fJobSetupText->SetText("Undefined job settings");
421 		}
422 		fOk->SetEnabled(false);
423 		fPageFormatText->SetText("Undefined paper format");
424 	} else {
425 		fPageSetup->SetEnabled(true);
426 
427 		if (fJobSetup) {
428 			fJobSetup->SetEnabled(fKind == kJobSetup && !fPageSettings.IsEmpty());
429 		}
430 		fOk->SetEnabled(fKind == kJobSetup && !fJobSettings.IsEmpty() ||
431 			fKind == kPageSetup && !fPageSettings.IsEmpty());
432 
433 			// display information about page format
434 		BRect paperRect;
435 		BString pageFormat;
436 		if (fPageSettings.FindRect(PSRV_FIELD_PAPER_RECT, &paperRect) == B_OK) {
437 			GetPageFormat(paperRect.Width(), paperRect.Height(), pageFormat);
438 
439 			int32 orientation = 0;
440 			fPageSettings.FindInt32(PSRV_FIELD_ORIENTATION, &orientation);
441 			if (orientation == 0) pageFormat << ", Portrait";
442 			else pageFormat << ", Landscape";
443 		} else {
444 			pageFormat << "Undefined paper format";
445 		}
446 		fPageFormatText->SetText(pageFormat.String());
447 
448 			// display information about job
449 		if (fKind == kJobSetup) {
450 			BString job;
451 			int32 first, last, copies;
452 			if (fJobSettings.FindInt32(PSRV_FIELD_FIRST_PAGE, &first) == B_OK &&
453 				fJobSettings.FindInt32(PSRV_FIELD_LAST_PAGE, &last) == B_OK) {
454 				if (first >= 1 && first <= last && last != INT_MAX) {
455 					job << "From page " << first << " to " << last;
456 				} else {
457 					job << "All pages";
458 				}
459 				int32 copies;
460 				if (fJobSettings.FindInt32(PSRV_FIELD_COPIES, &copies) == B_OK && copies > 1) {
461 					job << ", " << copies << " copies";
462 				}
463 			} else {
464 				job << "Undefined job settings";
465 			}
466 
467 			fJobSetupText->SetText(job.String());
468 		}
469 	}
470 }
471 
472 void ConfigWindow::Setup(config_setup_kind kind) {
473 	if (fCurrentPrinter) {
474 		Hide();
475 		if (kind == kPageSetup) {
476 			BMessage settings = fPageSettings;
477 			if (fCurrentPrinter->ConfigurePage(settings) == B_OK) {
478 				fPageSettings = settings;
479 				if (!fJobSettings.IsEmpty()) AddFields(&fJobSettings, &fPageSettings);
480 			}
481 		} else {
482 			BMessage settings;
483 			if (fJobSettings.IsEmpty()) settings = fPageSettings;
484 			else settings = fJobSettings;
485 
486 			if (fCurrentPrinter->ConfigureJob(settings) == B_OK)
487 				fJobSettings = settings;
488 		}
489 		UpdateUI();
490 		Show();
491 	}
492 }
493