xref: /haiku/src/preferences/printers/PrintersWindow.cpp (revision 323b65468e5836bb27a5e373b14027d902349437)
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 		return;
232 
233 	// enforce job config properties
234 	settings->AddInt32("copies", 1);
235 	settings->AddInt32("first_page", 1);
236 	settings->AddInt32("last_page", -1);
237 
238 	BWindow* win = new TestPageWindow(job, printer);
239 	win->Show();
240 	win->PostMessage(kMsgPrintTestPage);
241 }
242 
243 
244 void
245 PrintersWindow::AddJob(SpoolFolder* folder, Job* job)
246 {
247 	if (_IsSelected(folder->Item()))
248 		fJobListView->AddJob(job);
249 	fPrinterListView->UpdateItem(folder->Item());
250 	_UpdatePrinterButtons();
251 }
252 
253 
254 void
255 PrintersWindow::RemoveJob(SpoolFolder* folder, Job* job)
256 {
257 	if (_IsSelected(folder->Item()))
258 		fJobListView->RemoveJob(job);
259 	fPrinterListView->UpdateItem(folder->Item());
260 	_UpdatePrinterButtons();
261 }
262 
263 
264 void
265 PrintersWindow::UpdateJob(SpoolFolder* folder, Job* job)
266 {
267 	if (_IsSelected(folder->Item())) {
268 		fJobListView->UpdateJob(job);
269 		_UpdateJobButtons();
270 	}
271 	fPrinterListView->UpdateItem(folder->Item());
272 	_UpdatePrinterButtons();
273 }
274 
275 
276 // #pragma mark -
277 
278 
279 void
280 PrintersWindow::_BuildGUI()
281 {
282 	const float boxInset = 10.0;
283 	BRect r(Bounds());
284 
285 // ------------------------ First of all, create a nice grey backdrop
286 	BBox * backdrop = new BBox(Bounds(), "backdrop", B_FOLLOW_ALL_SIDES,
287 						B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE_JUMP,
288 						B_PLAIN_BORDER);
289 	AddChild(backdrop);
290 
291 // ------------------------ Next, build the printers overview box
292 	BBox* printersBox = new BBox(BRect(boxInset, boxInset,
293 		r.Width() - boxInset, (r.Height()/2) - (boxInset/2)),
294 		"printersBox", B_FOLLOW_ALL);
295 	printersBox->SetFont(be_bold_font);
296 	printersBox->SetLabel(B_TRANSLATE("Printers"));
297 	backdrop->AddChild(printersBox);
298 
299 		// Width of largest button
300 	float maxWidth = 0;
301 
302 		// Add Button
303 	BButton* addButton = new BButton(BRect(5,5,5,5), "add",
304 		B_TRANSLATE("Add …"), new BMessage(kMsgAddPrinter), B_FOLLOW_RIGHT);
305 	printersBox->AddChild(addButton);
306 	addButton->ResizeToPreferred();
307 
308 	maxWidth = addButton->Bounds().Width();
309 
310 		// Remove button
311 	fRemove = new BButton(BRect(5,30,5,30), "remove",
312 		B_TRANSLATE("Remove"), new BMessage(kMsgRemovePrinter),
313 		B_FOLLOW_RIGHT);
314 	printersBox->AddChild(fRemove);
315 	fRemove->ResizeToPreferred();
316 
317 	if (fRemove->Bounds().Width() > maxWidth)
318 		maxWidth = fRemove->Bounds().Width();
319 
320 		// Make Default button
321 	fMakeDefault = new BButton(BRect(5,60,5,60), "default",
322 		B_TRANSLATE("Make default"), new BMessage(kMsgMakeDefaultPrinter),
323 		B_FOLLOW_RIGHT);
324 	printersBox->AddChild(fMakeDefault);
325 	fMakeDefault->ResizeToPreferred();
326 
327 	if (fMakeDefault->Bounds().Width() > maxWidth)
328 		maxWidth = fMakeDefault->Bounds().Width();
329 
330 		// Print Test Page button
331 	fPrintTestPage = new BButton(BRect(5,60,5,60), "print_test_page",
332 		B_TRANSLATE("Print test page"), new BMessage(kMsgPrintTestPage),
333 		B_FOLLOW_RIGHT);
334 	printersBox->AddChild(fPrintTestPage);
335 	fPrintTestPage->ResizeToPreferred();
336 
337 	if (fPrintTestPage->Bounds().Width() > maxWidth)
338 		maxWidth = fPrintTestPage->Bounds().Width();
339 
340 
341 		// Resize all buttons to maximum width and align them to the right
342 	float xPos = printersBox->Bounds().Width() - boxInset - maxWidth;
343 	addButton->MoveTo(xPos, boxInset + 8);
344 	addButton->ResizeTo(maxWidth, addButton->Bounds().Height());
345 
346 	fRemove->MoveTo(xPos,
347 		boxInset + addButton->Bounds().Height() + boxInset + 8);
348 	fRemove->ResizeTo(maxWidth, fRemove->Bounds().Height());
349 
350 	fMakeDefault->MoveTo(xPos, boxInset + addButton->Bounds().Height() +
351 		boxInset + fRemove->Bounds().Height() + boxInset + 8);
352 	fMakeDefault->ResizeTo(maxWidth, fMakeDefault->Bounds().Height());
353 
354 	fPrintTestPage->MoveTo(xPos, boxInset + addButton->Bounds().Height() +
355 		boxInset + fRemove->Bounds().Height() +
356 		boxInset + fMakeDefault->Bounds().Height() + boxInset + 8);
357 	fPrintTestPage->ResizeTo(maxWidth, fPrintTestPage->Bounds().Height());
358 
359 
360 		// Disable all selection-based buttons
361 	fRemove->SetEnabled(false);
362 	fMakeDefault->SetEnabled(false);
363 	fPrintTestPage->SetEnabled(false);
364 
365 		// Create listview with scroller
366 	BRect listBounds(boxInset, boxInset + 8,
367 		fMakeDefault->Frame().left - boxInset - B_V_SCROLL_BAR_WIDTH,
368 		printersBox->Bounds().Height()- boxInset - 3);
369 	fPrinterListView = new PrinterListView(listBounds);
370 	BScrollView* pscroller = new BScrollView("printer_scroller", fPrinterListView,
371 		B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS, false, true, B_FANCY_BORDER);
372 	printersBox->AddChild(pscroller);
373 
374 // ------------------------ Lastly, build the jobs overview box
375 	fJobsBox = new BBox(BRect(boxInset, r.Height() / 2 + boxInset / 2,
376 		Bounds().Width() - 10, Bounds().Height() - boxInset), "jobsBox",
377 		B_FOLLOW_LEFT_RIGHT | B_FOLLOW_BOTTOM);
378 	fJobsBox->SetFont(be_bold_font);
379 	fJobsBox->SetLabel(B_TRANSLATE("Print jobs: No printer selected"));
380 	backdrop->AddChild(fJobsBox);
381 
382 		// Cancel Job Button
383 	BButton* cancelButton = new BButton(BRect(5, 5, 5, 5), "cancel",
384 		B_TRANSLATE("Cancel job"), new BMessage(kMsgCancelJob),
385 		B_FOLLOW_RIGHT+B_FOLLOW_TOP);
386 	fJobsBox->AddChild(cancelButton);
387 	cancelButton->ResizeToPreferred();
388 	fCancel = cancelButton;
389 
390 	maxWidth = cancelButton->Bounds().Width();
391 
392 		// Restart Job button
393 	BButton* restartButton = new BButton(BRect(5, 30, 5, 30), "restart",
394 		B_TRANSLATE("Restart job"), new BMessage(kMsgRestartJob),
395 		B_FOLLOW_RIGHT | B_FOLLOW_TOP);
396 	fJobsBox->AddChild(restartButton);
397 	restartButton->ResizeToPreferred();
398 	fRestart = restartButton;
399 
400 	if (restartButton->Bounds().Width() > maxWidth)
401 		maxWidth = restartButton->Bounds().Width();
402 
403 		// Resize all buttons to maximum width and align them to the right
404 	xPos = fJobsBox->Bounds().Width() - boxInset - maxWidth;
405 	cancelButton->MoveTo(xPos, boxInset + 8);
406 	cancelButton->ResizeTo(maxWidth, cancelButton->Bounds().Height());
407 
408 	restartButton->MoveTo(xPos, boxInset + cancelButton->Bounds().Height()
409 		+ boxInset + 8);
410 	restartButton->ResizeTo(maxWidth, restartButton->Bounds().Height());
411 
412 		// Disable all selection-based buttons
413 	cancelButton->SetEnabled(false);
414 	restartButton->SetEnabled(false);
415 
416 		// Create listview with scroller
417 	listBounds = BRect(boxInset, boxInset + 8,
418 		cancelButton->Frame().left - boxInset - B_V_SCROLL_BAR_WIDTH,
419 		fJobsBox->Bounds().Height() - boxInset - 3);
420 	fJobListView = new JobListView(listBounds);
421 	BScrollView* jscroller = new BScrollView("jobs_scroller", fJobListView,
422 		B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS, false, true, B_FANCY_BORDER);
423 	fJobsBox->AddChild(jscroller);
424 
425 		// Determine min width
426 	float width = (jscroller->Bounds().Width() < pscroller->Bounds().Width())
427 		? jscroller->Bounds().Width() : pscroller->Bounds().Width();
428 
429 		// Resize boxes to the same size
430 	jscroller->ResizeTo(width, jscroller->Bounds().Height());
431 	pscroller->ResizeTo(width, pscroller->Bounds().Height());
432 }
433 
434 
435 bool
436 PrintersWindow::_IsSelected(PrinterItem* printer)
437 {
438 	return fSelectedPrinter && fSelectedPrinter == printer;
439 }
440 
441 
442 void
443 PrintersWindow::_UpdatePrinterButtons()
444 {
445 	PrinterItem* item = fPrinterListView->SelectedItem();
446 	fRemove->SetEnabled(item && !item->HasPendingJobs());
447 	fMakeDefault->SetEnabled(item && !item->IsActivePrinter());
448 	fPrintTestPage->SetEnabled(item);
449 }
450 
451 
452 void
453 PrintersWindow::_UpdateJobButtons()
454 {
455 	JobItem* item = fJobListView->SelectedItem();
456 	if (item != NULL) {
457 		Job* job = item->GetJob();
458 		fCancel->SetEnabled(job->Status() != kProcessing);
459 		fRestart->SetEnabled(job->Status() == kFailed);
460 	} else {
461 		fCancel->SetEnabled(false);
462 		fRestart->SetEnabled(false);
463 	}
464 }
465 
466 
467