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