xref: /haiku/src/preferences/printers/PrintersWindow.cpp (revision d3ff06683af390a4c2e83b69177e0a2eb76679bc)
1 /*
2  * Copyright 2001-2011, Haiku.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Michael Pfeiffer
7  *		Philippe Houdoin
8  */
9 
10 
11 #include "PrintersWindow.h"
12 
13 #include <stdio.h>
14 
15 #include <Application.h>
16 #include <Button.h>
17 #include <Catalog.h>
18 #include <FindDirectory.h>
19 #include <GroupLayout.h>
20 #include <Layout.h>
21 #include <ListView.h>
22 #include <Locale.h>
23 #include <PrintJob.h>
24 #include <ScrollView.h>
25 
26 #include "pr_server.h"
27 #include "AddPrinterDialog.h"
28 #include "Globals.h"
29 #include "JobListView.h"
30 #include "Messages.h"
31 #include "PrinterListView.h"
32 #include "TestPageView.h"
33 #include "SpoolFolder.h"
34 
35 
36 #undef B_TRANSLATE_CONTEXT
37 #define B_TRANSLATE_CONTEXT "PrintersWindow"
38 
39 
40 class TestPageWindow : public BWindow {
41 public:
42 						TestPageWindow(BPrintJob* job, PrinterItem* printer);
43 	virtual				~TestPageWindow();
44 
45 			void 		MessageReceived(BMessage* message);
46 private:
47 		BPrintJob*		fJob;
48 		TestPageView*	fTestPage;
49 };
50 
51 
52 TestPageWindow::TestPageWindow(BPrintJob* job, PrinterItem* printer)
53 	: BWindow(job->PaperRect().OffsetByCopy(-20000, -20000), B_TRANSLATE("Test Page"),
54 		B_TITLED_WINDOW, 0), fJob(job)
55 {
56 	fTestPage = new TestPageView(job->PrintableRect(), printer);
57 
58 	// SetLayout(new BGroupLayout(B_VERTICAL));
59 	AddChild(fTestPage);
60 }
61 
62 
63 TestPageWindow::~TestPageWindow()
64 {
65 	delete fJob;
66 }
67 
68 
69 void
70 TestPageWindow::MessageReceived(BMessage* message)
71 {
72 	if (message->what != kMsgPrintTestPage) {
73 		BWindow::MessageReceived(message);
74 		return;
75 	}
76 
77 	fJob->BeginJob();
78 
79 	fJob->DrawView(fTestPage, fTestPage->Bounds(), B_ORIGIN);
80 	fJob->SpoolPage();
81 
82 	if (!fJob->CanContinue())
83 		return;
84 
85 	fJob->CommitJob();
86 
87 	Quit();
88 }
89 
90 
91 // #pragma mark PrintersWindow main class
92 
93 
94 PrintersWindow::PrintersWindow(BRect frame)
95 	:
96 	BWindow(BRect(78, 71, 761, 509), B_TRANSLATE_SYSTEM_NAME("Printers"),
97 		B_TITLED_WINDOW, 0),
98 	fSelectedPrinter(NULL),
99 	fAddingPrinter(false)
100 {
101 	_BuildGUI();
102 }
103 
104 
105 bool
106 PrintersWindow::QuitRequested()
107 {
108 	bool result = Inherited::QuitRequested();
109 	if (result)
110 		be_app->PostMessage(B_QUIT_REQUESTED);
111 
112 	return result;
113 }
114 
115 
116 void
117 PrintersWindow::MessageReceived(BMessage* msg)
118 {
119 	switch(msg->what) {
120 		case kMsgPrinterSelected:
121 		{
122 			fSelectedPrinter = fPrinterListView->SelectedItem();
123 			if (fSelectedPrinter) {
124 				fJobsBox->SetLabel((BString(B_TRANSLATE("Print jobs for "))
125 					<< fSelectedPrinter->Name()).String());
126 				fMakeDefault->SetEnabled(true);
127 				fRemove->SetEnabled(true);
128 				fJobListView->SetSpoolFolder(fSelectedPrinter->Folder());
129 			} else {
130 				fJobsBox->SetLabel(
131 					B_TRANSLATE("Print jobs: No printer selected"));
132 				fMakeDefault->SetEnabled(false);
133 				fRemove->SetEnabled(false);
134 				fSelectedPrinter = NULL;
135 				fJobListView->SetSpoolFolder(NULL);
136 			}
137 			_UpdateJobButtons();
138 			_UpdatePrinterButtons();
139 			break;
140 		}
141 
142 		case kMsgAddPrinter:
143 			if (!fAddingPrinter) {
144 				fAddingPrinter = true;
145 				new AddPrinterDialog(this);
146 			}
147 			break;
148 
149 		case kMsgAddPrinterClosed:
150 			fAddingPrinter = false;
151 			break;
152 
153 		case kMsgRemovePrinter:
154 		{
155 			fSelectedPrinter = fPrinterListView->SelectedItem();
156 			if (fSelectedPrinter)
157 				fSelectedPrinter->Remove(fPrinterListView);
158 			break;
159 		}
160 
161 		case kMsgMakeDefaultPrinter:
162 		{
163 			PrinterItem* printer = fPrinterListView->SelectedItem();
164 			if (printer && printer == fPrinterListView->ActivePrinter())
165 				break;
166 			BMessenger msgr;
167 			if (printer && GetPrinterServerMessenger(msgr) == B_OK) {
168 				BMessage setActivePrinter(B_SET_PROPERTY);
169 				setActivePrinter.AddSpecifier("ActivePrinter");
170 				setActivePrinter.AddString("data", printer->Name());
171 				msgr.SendMessage(&setActivePrinter);
172 				_UpdatePrinterButtons();
173 			}
174 			break;
175 		}
176 
177 		case kMsgPrintTestPage:
178 		{
179 			fSelectedPrinter = fPrinterListView->SelectedItem();
180 			if (fSelectedPrinter)
181 				PrintTestPage(fSelectedPrinter);
182 			break;
183 		}
184 
185 		case kMsgCancelJob:
186 			fJobListView->CancelJob();
187 			break;
188 
189 		case kMsgRestartJob:
190 			fJobListView->RestartJob();
191 			break;
192 
193 		case kMsgJobSelected:
194 			_UpdateJobButtons();
195 			break;
196 
197 		case B_PRINTER_CHANGED:
198 		{
199 			// active printer could have been changed, even outside of prefs
200 			BString activePrinterName(ActivePrinterName());
201 			PrinterItem* item = fPrinterListView->ActivePrinter();
202 			if (item && item->Name() != activePrinterName)
203 				fPrinterListView->UpdateItem(item);
204 
205 			for (int32 i = 0; i < fPrinterListView->CountItems(); ++i) {
206 				item = dynamic_cast<PrinterItem*>(fPrinterListView->ItemAt(i));
207 				if (item && item->Name() == activePrinterName) {
208 					fPrinterListView->UpdateItem(item);
209 					fPrinterListView->SetActivePrinter(item);
210 					break;
211 				}
212 			}
213 		}	break;
214 
215 		default:
216 			Inherited::MessageReceived(msg);
217 	}
218 }
219 
220 
221 void
222 PrintersWindow::PrintTestPage(PrinterItem* printer)
223 {
224 	BPrintJob* job = new BPrintJob(B_TRANSLATE("Test Page"));
225 	job->ConfigPage();
226 
227 	// job->ConfigJob();
228 
229 	BMessage* settings = job->Settings();
230 	if (settings == NULL) {
231 		delete job;
232 		return;
233 	}
234 
235 	// enforce job config properties
236 	settings->AddInt32("copies", 1);
237 	settings->AddInt32("first_page", 1);
238 	settings->AddInt32("last_page", -1);
239 
240 	BWindow* win = new TestPageWindow(job, printer);
241 	win->Show();
242 	win->PostMessage(kMsgPrintTestPage);
243 }
244 
245 
246 void
247 PrintersWindow::AddJob(SpoolFolder* folder, Job* job)
248 {
249 	if (_IsSelected(folder->Item()))
250 		fJobListView->AddJob(job);
251 	fPrinterListView->UpdateItem(folder->Item());
252 	_UpdatePrinterButtons();
253 }
254 
255 
256 void
257 PrintersWindow::RemoveJob(SpoolFolder* folder, Job* job)
258 {
259 	if (_IsSelected(folder->Item()))
260 		fJobListView->RemoveJob(job);
261 	fPrinterListView->UpdateItem(folder->Item());
262 	_UpdatePrinterButtons();
263 }
264 
265 
266 void
267 PrintersWindow::UpdateJob(SpoolFolder* folder, Job* job)
268 {
269 	if (_IsSelected(folder->Item())) {
270 		fJobListView->UpdateJob(job);
271 		_UpdateJobButtons();
272 	}
273 	fPrinterListView->UpdateItem(folder->Item());
274 	_UpdatePrinterButtons();
275 }
276 
277 
278 // #pragma mark -
279 
280 
281 void
282 PrintersWindow::_BuildGUI()
283 {
284 	const float boxInset = 10.0;
285 	BRect r(Bounds());
286 
287 // ------------------------ First of all, create a nice grey backdrop
288 	BBox * backdrop = new BBox(Bounds(), "backdrop", B_FOLLOW_ALL_SIDES,
289 						B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE_JUMP,
290 						B_PLAIN_BORDER);
291 	AddChild(backdrop);
292 
293 // ------------------------ Next, build the printers overview box
294 	BBox* printersBox = new BBox(BRect(boxInset, boxInset,
295 		r.Width() - boxInset, (r.Height()/2) - (boxInset/2)),
296 		"printersBox", B_FOLLOW_ALL);
297 	printersBox->SetFont(be_bold_font);
298 	printersBox->SetLabel(B_TRANSLATE("Printers"));
299 	backdrop->AddChild(printersBox);
300 
301 		// Width of largest button
302 	float maxWidth = 0;
303 
304 		// Add Button
305 	BButton* addButton = new BButton(BRect(5,5,5,5), "add",
306 		B_TRANSLATE("Add …"), new BMessage(kMsgAddPrinter), B_FOLLOW_RIGHT);
307 	printersBox->AddChild(addButton);
308 	addButton->ResizeToPreferred();
309 
310 	maxWidth = addButton->Bounds().Width();
311 
312 		// Remove button
313 	fRemove = new BButton(BRect(5,30,5,30), "remove",
314 		B_TRANSLATE("Remove"), new BMessage(kMsgRemovePrinter),
315 		B_FOLLOW_RIGHT);
316 	printersBox->AddChild(fRemove);
317 	fRemove->ResizeToPreferred();
318 
319 	if (fRemove->Bounds().Width() > maxWidth)
320 		maxWidth = fRemove->Bounds().Width();
321 
322 		// Make Default button
323 	fMakeDefault = new BButton(BRect(5,60,5,60), "default",
324 		B_TRANSLATE("Make default"), new BMessage(kMsgMakeDefaultPrinter),
325 		B_FOLLOW_RIGHT);
326 	printersBox->AddChild(fMakeDefault);
327 	fMakeDefault->ResizeToPreferred();
328 
329 	if (fMakeDefault->Bounds().Width() > maxWidth)
330 		maxWidth = fMakeDefault->Bounds().Width();
331 
332 		// Print Test Page button
333 	fPrintTestPage = new BButton(BRect(5,60,5,60), "print_test_page",
334 		B_TRANSLATE("Print test page"), new BMessage(kMsgPrintTestPage),
335 		B_FOLLOW_RIGHT);
336 	printersBox->AddChild(fPrintTestPage);
337 	fPrintTestPage->ResizeToPreferred();
338 
339 	if (fPrintTestPage->Bounds().Width() > maxWidth)
340 		maxWidth = fPrintTestPage->Bounds().Width();
341 
342 
343 		// Resize all buttons to maximum width and align them to the right
344 	float xPos = printersBox->Bounds().Width() - boxInset - maxWidth;
345 	addButton->MoveTo(xPos, boxInset + 8);
346 	addButton->ResizeTo(maxWidth, addButton->Bounds().Height());
347 
348 	fRemove->MoveTo(xPos,
349 		boxInset + addButton->Bounds().Height() + boxInset + 8);
350 	fRemove->ResizeTo(maxWidth, fRemove->Bounds().Height());
351 
352 	fMakeDefault->MoveTo(xPos, boxInset + addButton->Bounds().Height() +
353 		boxInset + fRemove->Bounds().Height() + boxInset + 8);
354 	fMakeDefault->ResizeTo(maxWidth, fMakeDefault->Bounds().Height());
355 
356 	fPrintTestPage->MoveTo(xPos, boxInset + addButton->Bounds().Height() +
357 		boxInset + fRemove->Bounds().Height() +
358 		boxInset + fMakeDefault->Bounds().Height() + boxInset + 8);
359 	fPrintTestPage->ResizeTo(maxWidth, fPrintTestPage->Bounds().Height());
360 
361 
362 		// Disable all selection-based buttons
363 	fRemove->SetEnabled(false);
364 	fMakeDefault->SetEnabled(false);
365 	fPrintTestPage->SetEnabled(false);
366 
367 		// Create listview with scroller
368 	BRect listBounds(boxInset, boxInset + 8,
369 		fMakeDefault->Frame().left - boxInset - B_V_SCROLL_BAR_WIDTH,
370 		printersBox->Bounds().Height()- boxInset - 3);
371 	fPrinterListView = new PrinterListView(listBounds);
372 	BScrollView* pscroller = new BScrollView("printer_scroller", fPrinterListView,
373 		B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS, false, true, B_FANCY_BORDER);
374 	printersBox->AddChild(pscroller);
375 
376 // ------------------------ Lastly, build the jobs overview box
377 	fJobsBox = new BBox(BRect(boxInset, r.Height() / 2 + boxInset / 2,
378 		Bounds().Width() - 10, Bounds().Height() - boxInset), "jobsBox",
379 		B_FOLLOW_LEFT_RIGHT | B_FOLLOW_BOTTOM);
380 	fJobsBox->SetFont(be_bold_font);
381 	fJobsBox->SetLabel(B_TRANSLATE("Print jobs: No printer selected"));
382 	backdrop->AddChild(fJobsBox);
383 
384 		// Cancel Job Button
385 	BButton* cancelButton = new BButton(BRect(5, 5, 5, 5), "cancel",
386 		B_TRANSLATE("Cancel job"), new BMessage(kMsgCancelJob),
387 		B_FOLLOW_RIGHT+B_FOLLOW_TOP);
388 	fJobsBox->AddChild(cancelButton);
389 	cancelButton->ResizeToPreferred();
390 	fCancel = cancelButton;
391 
392 	maxWidth = cancelButton->Bounds().Width();
393 
394 		// Restart Job button
395 	BButton* restartButton = new BButton(BRect(5, 30, 5, 30), "restart",
396 		B_TRANSLATE("Restart job"), new BMessage(kMsgRestartJob),
397 		B_FOLLOW_RIGHT | B_FOLLOW_TOP);
398 	fJobsBox->AddChild(restartButton);
399 	restartButton->ResizeToPreferred();
400 	fRestart = restartButton;
401 
402 	if (restartButton->Bounds().Width() > maxWidth)
403 		maxWidth = restartButton->Bounds().Width();
404 
405 		// Resize all buttons to maximum width and align them to the right
406 	xPos = fJobsBox->Bounds().Width() - boxInset - maxWidth;
407 	cancelButton->MoveTo(xPos, boxInset + 8);
408 	cancelButton->ResizeTo(maxWidth, cancelButton->Bounds().Height());
409 
410 	restartButton->MoveTo(xPos, boxInset + cancelButton->Bounds().Height()
411 		+ boxInset + 8);
412 	restartButton->ResizeTo(maxWidth, restartButton->Bounds().Height());
413 
414 		// Disable all selection-based buttons
415 	cancelButton->SetEnabled(false);
416 	restartButton->SetEnabled(false);
417 
418 		// Create listview with scroller
419 	listBounds = BRect(boxInset, boxInset + 8,
420 		cancelButton->Frame().left - boxInset - B_V_SCROLL_BAR_WIDTH,
421 		fJobsBox->Bounds().Height() - boxInset - 3);
422 	fJobListView = new JobListView(listBounds);
423 	BScrollView* jscroller = new BScrollView("jobs_scroller", fJobListView,
424 		B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS, false, true, B_FANCY_BORDER);
425 	fJobsBox->AddChild(jscroller);
426 
427 		// Determine min width
428 	float width = (jscroller->Bounds().Width() < pscroller->Bounds().Width())
429 		? jscroller->Bounds().Width() : pscroller->Bounds().Width();
430 
431 		// Resize boxes to the same size
432 	jscroller->ResizeTo(width, jscroller->Bounds().Height());
433 	pscroller->ResizeTo(width, pscroller->Bounds().Height());
434 }
435 
436 
437 bool
438 PrintersWindow::_IsSelected(PrinterItem* printer)
439 {
440 	return fSelectedPrinter && fSelectedPrinter == printer;
441 }
442 
443 
444 void
445 PrintersWindow::_UpdatePrinterButtons()
446 {
447 	PrinterItem* item = fPrinterListView->SelectedItem();
448 	fRemove->SetEnabled(item && !item->HasPendingJobs());
449 	fMakeDefault->SetEnabled(item && !item->IsActivePrinter());
450 	fPrintTestPage->SetEnabled(item);
451 }
452 
453 
454 void
455 PrintersWindow::_UpdateJobButtons()
456 {
457 	JobItem* item = fJobListView->SelectedItem();
458 	if (item != NULL) {
459 		Job* job = item->GetJob();
460 		fCancel->SetEnabled(job->Status() != kProcessing);
461 		fRestart->SetEnabled(job->Status() == kFailed);
462 	} else {
463 		fCancel->SetEnabled(false);
464 		fRestart->SetEnabled(false);
465 	}
466 }
467 
468 
469