xref: /haiku/src/preferences/printers/PrintersWindow.cpp (revision d0ac609964842f8cdb6d54b3c539c6c15293e172)
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 				fJobsBox->SetLabel((BString(B_TRANSLATE("Print jobs for "))
127 					<< fSelectedPrinter->Name()).String());
128 				fMakeDefault->SetEnabled(true);
129 				fRemove->SetEnabled(true);
130 				fJobListView->SetSpoolFolder(fSelectedPrinter->Folder());
131 			} else {
132 				fJobsBox->SetLabel(
133 					B_TRANSLATE("Print jobs: No printer selected"));
134 				fMakeDefault->SetEnabled(false);
135 				fRemove->SetEnabled(false);
136 				fSelectedPrinter = NULL;
137 				fJobListView->SetSpoolFolder(NULL);
138 			}
139 			_UpdateJobButtons();
140 			_UpdatePrinterButtons();
141 			break;
142 		}
143 
144 		case kMsgAddPrinter:
145 			if (!fAddingPrinter) {
146 				fAddingPrinter = true;
147 				new AddPrinterDialog(this);
148 			}
149 			break;
150 
151 		case kMsgAddPrinterClosed:
152 			fAddingPrinter = false;
153 			break;
154 
155 		case kMsgRemovePrinter:
156 		{
157 			fSelectedPrinter = fPrinterListView->SelectedItem();
158 			if (fSelectedPrinter)
159 				fSelectedPrinter->Remove(fPrinterListView);
160 			break;
161 		}
162 
163 		case kMsgMakeDefaultPrinter:
164 		{
165 			PrinterItem* printer = fPrinterListView->SelectedItem();
166 			if (printer && printer == fPrinterListView->ActivePrinter())
167 				break;
168 			BMessenger msgr;
169 			if (printer && GetPrinterServerMessenger(msgr) == B_OK) {
170 				BMessage setActivePrinter(B_SET_PROPERTY);
171 				setActivePrinter.AddSpecifier("ActivePrinter");
172 				setActivePrinter.AddString("data", printer->Name());
173 				msgr.SendMessage(&setActivePrinter);
174 				_UpdatePrinterButtons();
175 			}
176 			break;
177 		}
178 
179 		case kMsgPrintTestPage:
180 		{
181 			fSelectedPrinter = fPrinterListView->SelectedItem();
182 			if (fSelectedPrinter)
183 				PrintTestPage(fSelectedPrinter);
184 			break;
185 		}
186 
187 		case kMsgCancelJob:
188 			fJobListView->CancelJob();
189 			break;
190 
191 		case kMsgRestartJob:
192 			fJobListView->RestartJob();
193 			break;
194 
195 		case kMsgJobSelected:
196 			_UpdateJobButtons();
197 			break;
198 
199 		case B_PRINTER_CHANGED:
200 		{
201 			// active printer could have been changed, even outside of prefs
202 			BString activePrinterName(ActivePrinterName());
203 			PrinterItem* item = fPrinterListView->ActivePrinter();
204 			if (item && item->Name() != activePrinterName)
205 				fPrinterListView->UpdateItem(item);
206 
207 			for (int32 i = 0; i < fPrinterListView->CountItems(); ++i) {
208 				item = dynamic_cast<PrinterItem*>(fPrinterListView->ItemAt(i));
209 				if (item && item->Name() == activePrinterName) {
210 					fPrinterListView->UpdateItem(item);
211 					fPrinterListView->SetActivePrinter(item);
212 					break;
213 				}
214 			}
215 		}	break;
216 
217 		default:
218 			Inherited::MessageReceived(msg);
219 	}
220 }
221 
222 
223 void
224 PrintersWindow::PrintTestPage(PrinterItem* printer)
225 {
226 	BPrintJob* job = new BPrintJob(B_TRANSLATE("Test Page"));
227 	job->ConfigPage();
228 
229 	// job->ConfigJob();
230 
231 	BMessage* settings = job->Settings();
232 	if (settings == NULL) {
233 		delete job;
234 		return;
235 	}
236 
237 	// enforce job config properties
238 	settings->AddInt32("copies", 1);
239 	settings->AddInt32("first_page", 1);
240 	settings->AddInt32("last_page", -1);
241 
242 	BWindow* win = new TestPageWindow(job, printer);
243 	win->Show();
244 	win->PostMessage(kMsgPrintTestPage);
245 }
246 
247 
248 void
249 PrintersWindow::AddJob(SpoolFolder* folder, Job* job)
250 {
251 	if (_IsSelected(folder->Item()))
252 		fJobListView->AddJob(job);
253 	fPrinterListView->UpdateItem(folder->Item());
254 	_UpdatePrinterButtons();
255 }
256 
257 
258 void
259 PrintersWindow::RemoveJob(SpoolFolder* folder, Job* job)
260 {
261 	if (_IsSelected(folder->Item()))
262 		fJobListView->RemoveJob(job);
263 	fPrinterListView->UpdateItem(folder->Item());
264 	_UpdatePrinterButtons();
265 }
266 
267 
268 void
269 PrintersWindow::UpdateJob(SpoolFolder* folder, Job* job)
270 {
271 	if (_IsSelected(folder->Item())) {
272 		fJobListView->UpdateJob(job);
273 		_UpdateJobButtons();
274 	}
275 	fPrinterListView->UpdateItem(folder->Item());
276 	_UpdatePrinterButtons();
277 }
278 
279 
280 // #pragma mark -
281 
282 
283 void
284 PrintersWindow::_BuildGUI()
285 {
286 // ------------------------ Next, build the printers overview box
287 	BBox* printersBox = new BBox("printersBox");
288 	printersBox->SetFont(be_bold_font);
289 	printersBox->SetLabel(B_TRANSLATE("Printers"));
290 
291 		// Add Button
292 	BButton* addButton = new BButton("add",
293 		B_TRANSLATE("Add" B_UTF8_ELLIPSIS), new BMessage(kMsgAddPrinter));
294 	addButton->SetExplicitMaxSize(
295 		BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
296 
297 		// Remove button
298 	fRemove = new BButton("remove",
299 		B_TRANSLATE("Remove"), new BMessage(kMsgRemovePrinter));
300 	fRemove->SetExplicitMaxSize(
301 		BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
302 
303 		// Make Default button
304 	fMakeDefault = new BButton("default",
305 		B_TRANSLATE("Make default"), new BMessage(kMsgMakeDefaultPrinter));
306 	fMakeDefault->SetExplicitMaxSize(
307 		BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
308 
309 		// Print Test Page button
310 	fPrintTestPage = new BButton("print_test_page",
311 		B_TRANSLATE("Print test page"), new BMessage(kMsgPrintTestPage));
312 	fPrintTestPage->SetExplicitMaxSize(
313 		BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
314 
315 		// Disable all selection-based buttons
316 	fRemove->SetEnabled(false);
317 	fMakeDefault->SetEnabled(false);
318 	fPrintTestPage->SetEnabled(false);
319 
320 		// Create listview with scroller
321 	fPrinterListView = new PrinterListView(BRect());
322 	BScrollView* printerScrollView = new BScrollView("printer_scroller",
323 		fPrinterListView, B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS,
324 		false, true, B_FANCY_BORDER);
325 
326 	printerScrollView->SetExplicitMinSize(
327 		BSize(be_plain_font->Size() * 30, B_SIZE_UNSET));
328 
329 	float padding = be_control_look->DefaultItemSpacing();
330 
331 	BLayoutBuilder::Group<>(printersBox, B_HORIZONTAL, padding)
332 		.SetInsets(padding, padding * 2, padding, padding)
333 		.Add(printerScrollView)
334 		.AddGroup(B_VERTICAL, padding / 2, 0.0f)
335 			.SetInsets(0)
336 			.Add(addButton)
337 			.Add(fRemove)
338 			.Add(fMakeDefault)
339 			.Add(fPrintTestPage)
340 			.AddGlue();
341 
342 // ------------------------ Lastly, build the jobs overview box
343 	fJobsBox = new BBox("jobsBox");
344 	fJobsBox->SetFont(be_bold_font);
345 	fJobsBox->SetLabel(B_TRANSLATE("Print jobs: No printer selected"));
346 
347 		// Cancel Job Button
348 	fCancel = new BButton("cancel",
349 		B_TRANSLATE("Cancel job"), new BMessage(kMsgCancelJob));
350 	fCancel->SetExplicitMaxSize(
351 		BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
352 
353 		// Restart Job button
354 	fRestart = new BButton("restart",
355 		B_TRANSLATE("Restart job"), new BMessage(kMsgRestartJob));
356 	fRestart->SetExplicitMaxSize(
357 		BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
358 
359 		// Disable all selection-based buttons
360 	fCancel->SetEnabled(false);
361 	fRestart->SetEnabled(false);
362 
363 		// Create listview with scroller
364 	fJobListView = new JobListView(BRect());
365 	BScrollView* jobScrollView = new BScrollView("jobs_scroller",
366 		fJobListView, B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS,
367 		false, true, B_FANCY_BORDER);
368 
369 	BLayoutBuilder::Group<>(fJobsBox, B_HORIZONTAL, padding)
370 		.SetInsets(padding, padding * 2, padding, padding)
371 		.Add(jobScrollView)
372 		.AddGroup(B_VERTICAL, padding / 2, 0.0f)
373 			.SetInsets(0)
374 			.Add(fCancel)
375 			.Add(fRestart)
376 			.AddGlue();
377 
378 	BLayoutBuilder::Group<>(this, B_VERTICAL, 0)
379 		.SetInsets(B_USE_WINDOW_SPACING)
380 		.Add(printersBox)
381 		.AddStrut(B_USE_DEFAULT_SPACING)
382 		.Add(fJobsBox);
383 
384 		// There is a better solution?
385 	Layout(true);
386 	if (fPrintTestPage->Bounds().Width() > fRestart->Bounds().Width())
387 		fRestart->SetExplicitMinSize(
388 			BSize(fPrintTestPage->Bounds().Width(), B_SIZE_UNSET));
389 	else
390 		fPrintTestPage->SetExplicitMinSize(
391 			BSize(fRestart->Bounds().Width(), B_SIZE_UNSET));
392 }
393 
394 
395 bool
396 PrintersWindow::_IsSelected(PrinterItem* printer)
397 {
398 	return fSelectedPrinter && fSelectedPrinter == printer;
399 }
400 
401 
402 void
403 PrintersWindow::_UpdatePrinterButtons()
404 {
405 	PrinterItem* item = fPrinterListView->SelectedItem();
406 	fRemove->SetEnabled(item && !item->HasPendingJobs());
407 	fMakeDefault->SetEnabled(item && !item->IsActivePrinter());
408 	fPrintTestPage->SetEnabled(item);
409 }
410 
411 
412 void
413 PrintersWindow::_UpdateJobButtons()
414 {
415 	JobItem* item = fJobListView->SelectedItem();
416 	if (item != NULL) {
417 		Job* job = item->GetJob();
418 		fCancel->SetEnabled(job->Status() != kProcessing);
419 		fRestart->SetEnabled(job->Status() == kFailed);
420 	} else {
421 		fCancel->SetEnabled(false);
422 		fRestart->SetEnabled(false);
423 	}
424 }
425 
426 
427