xref: /haiku/src/preferences/printers/AddPrinterDialog.cpp (revision 68ea01249e1e2088933cb12f9c28d4e5c5d1c9ef)
1 /*
2  * Copyright 2002-2009, Haiku.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Michael Pfeiffer
7  *		Philippe Houdoin
8  */
9 
10 
11 #include "AddPrinterDialog.h"
12 
13 #include <stdio.h>
14 
15 #include <Button.h>
16 #include <Catalog.h>
17 #include <FindDirectory.h>
18 #include <GroupLayoutBuilder.h>
19 #include <Layout.h>
20 #include <LayoutBuilder.h>
21 #include <Locale.h>
22 #include <MenuField.h>
23 #include <MenuItem.h>
24 #include <MimeType.h>
25 #include <NodeInfo.h>
26 #include <Path.h>
27 
28 #include "pr_server.h"
29 #include "Globals.h"
30 #include "Messages.h"
31 #include "PrinterListView.h"
32 #include "TransportMenu.h"
33 
34 
35 #undef B_TRANSLATION_CONTEXT
36 #define B_TRANSLATION_CONTEXT "AddPrinterDialog"
37 
38 
39 AddPrinterDialog::AddPrinterDialog(BWindow *parent)
40 	:
41 	Inherited(BRect(78, 71, 400, 300), B_TRANSLATE("Add printer"),
42 		B_TITLED_WINDOW_LOOK, B_MODAL_APP_WINDOW_FEEL,
43 		B_NOT_ZOOMABLE | B_AUTO_UPDATE_SIZE_LIMITS
44 		| B_CLOSE_ON_ESCAPE),
45 	fPrintersPrefletMessenger(parent)
46 {
47 	_BuildGUI(0);
48 
49 	Show();
50 }
51 
52 
53 bool
54 AddPrinterDialog::QuitRequested()
55 {
56 	fPrintersPrefletMessenger.SendMessage(kMsgAddPrinterClosed);
57 	return Inherited::QuitRequested();
58 }
59 
60 
61 void
62 AddPrinterDialog::MessageReceived(BMessage* msg)
63 {
64 	switch(msg->what) {
65 		case B_OK:
66 			_AddPrinter(msg);
67 			PostMessage(B_QUIT_REQUESTED);
68 			break;
69 
70 		case B_CANCEL:
71 			PostMessage(B_QUIT_REQUESTED);
72 			break;
73 
74 		case kNameChangedMsg:
75 			fNameText = fName->Text();
76 			_Update();
77 			break;
78 
79 		case kPrinterSelectedMsg:
80 			_StorePrinter(msg);
81 			break;
82 
83 		case kTransportSelectedMsg:
84 			_HandleChangedTransport(msg);
85 			break;
86 
87 		default:
88 			Inherited::MessageReceived(msg);
89 			break;
90 	}
91 }
92 
93 
94 void
95 AddPrinterDialog::_AddPrinter(BMessage *msg)
96 {
97 	BMessage m(PSRV_MAKE_PRINTER);
98 	BMessenger msgr;
99 	if (GetPrinterServerMessenger(msgr) != B_OK)
100 		return;
101 
102 	BString transport;
103 	BString transportPath;
104 	if (fPrinterText != "Preview") {
105 		// Preview printer does not use transport add-on
106 		transport = fTransportText;
107 		transportPath = fTransportPathText;
108 	}
109 
110 	m.AddString("driver", fPrinterText.String());
111 	m.AddString("transport", transport.String());
112 	m.AddString("transport path", transportPath.String());
113 	m.AddString("printer name", fNameText.String());
114 	m.AddString("connection", "Local");
115 	msgr.SendMessage(&m);
116 		// request print_server to create printer
117 }
118 
119 
120 void
121 AddPrinterDialog::_StorePrinter(BMessage *msg)
122 {
123 	BString name;
124 	if (msg->FindString("name", &name) != B_OK)
125 		name = "";
126 
127 	fPrinterText = name;
128 	_Update();
129 }
130 
131 
132 void
133 AddPrinterDialog::_HandleChangedTransport(BMessage *msg)
134 {
135 	BString name;
136 	if (msg->FindString("name", &name) != B_OK) {
137 		name = "";
138 	}
139 	fTransportText = name;
140 
141 	BString path;
142 	if (msg->FindString("path", &path) == B_OK) {
143 		// transport path selected
144 		fTransportPathText = path;
145 
146 		// mark sub menu
147 		void* pointer;
148 		if (msg->FindPointer("source", &pointer) == B_OK) {
149 			BMenuItem* item = (BMenuItem*)pointer;
150 
151 			// Update printer name with Transport Path if not filled in
152 			if (strlen(fName->Text()) == 0)
153 				fName->SetText(item->Label());
154 
155 			BMenu* menu = item->Menu();
156 			int32 index = fTransport->IndexOf(menu);
157 			item = fTransport->ItemAt(index);
158 			if (item != NULL)
159 				item->SetMarked(true);
160 		}
161 	} else {
162 		// transport selected
163 		fTransportPathText = "";
164 
165 		// remove mark from item in sub menu of transport sub menu
166 		for (int32 i = fTransport->CountItems() - 1; i >= 0; i --) {
167 			BMenu* menu = fTransport->SubmenuAt(i);
168 			if (menu != NULL) {
169 				BMenuItem* item = menu->FindMarked();
170 				if (item != NULL)
171 					item->SetMarked(false);
172 			}
173 		}
174 	}
175 	_Update();
176 }
177 
178 
179 void
180 AddPrinterDialog::_BuildGUI(int stage)
181 {
182 	// add a "printer name" input field
183 	fName = new BTextControl("printer_name", B_TRANSLATE("Printer name:"),
184 		B_EMPTY_STRING, NULL);
185 	fName->SetFont(be_bold_font);
186 	fName->SetAlignment(B_ALIGN_RIGHT, B_ALIGN_LEFT);
187 	fName->SetModificationMessage(new BMessage(kNameChangedMsg));
188 
189 	// add a "driver" popup menu field
190 	fPrinter = new BPopUpMenu(B_TRANSLATE("<pick one>"));
191 	BMenuField *printerMenuField = new BMenuField("drivers_list",
192 		B_TRANSLATE("Printer type:"), fPrinter);
193 	printerMenuField->SetAlignment(B_ALIGN_RIGHT);
194 	_FillMenu(fPrinter, "Print", kPrinterSelectedMsg);
195 
196 	// add a "connected to" (aka transports list) menu field
197 	fTransport = new BPopUpMenu(B_TRANSLATE("<pick one>"));
198 	BMenuField *transportMenuField = new BMenuField("transports_list",
199 		B_TRANSLATE("Connected to:"), fTransport);
200 	transportMenuField->SetAlignment(B_ALIGN_RIGHT);
201 	_FillTransportMenu(fTransport);
202 
203 	// add a "OK" button
204 	fOk = new BButton(NULL, B_TRANSLATE("Add"), new BMessage((uint32)B_OK),
205 		B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM);
206 
207 	// add a "Cancel button
208 	BButton *cancel = new BButton(NULL, B_TRANSLATE("Cancel"),
209 		new BMessage(B_CANCEL));
210 
211 	BLayoutBuilder::Grid<>(this, B_USE_ITEM_SPACING, B_USE_ITEM_SPACING)
212 		.Add(fName->CreateLabelLayoutItem(), 0, 0)
213 		.Add(fName->CreateTextViewLayoutItem(), 1, 0)
214 		.Add(printerMenuField->CreateLabelLayoutItem(), 0, 1)
215 		.Add(printerMenuField->CreateMenuBarLayoutItem(), 1, 1)
216 		.Add(transportMenuField->CreateLabelLayoutItem(), 0, 2)
217 		.Add(transportMenuField->CreateMenuBarLayoutItem(), 1, 2)
218 		.Add(BGroupLayoutBuilder(B_HORIZONTAL)
219 			.AddGlue()
220 			.Add(cancel)
221 			.Add(fOk)
222 			, 0, 3, 2)
223 		.SetInsets(B_USE_WINDOW_SPACING, B_USE_WINDOW_SPACING,
224 			B_USE_WINDOW_SPACING, B_USE_WINDOW_SPACING);
225 
226 	AddShortcut('W', B_COMMAND_KEY, new BMessage(B_QUIT_REQUESTED));
227 
228 	SetDefaultButton(fOk);
229 	fOk->MakeDefault(true);
230 
231 	fName->MakeFocus(true);
232 
233 	_Update();
234 // Stage == 0
235 // init_icon 64x114  Add a Local or Network Printer
236 //                   ------------------------------
237 //                   I would like to add a...
238 //                              Local Printer
239 //                              Network Printer
240 // ------------------------------------------------
241 //                                Cancel   Continue
242 
243 // Add local printer:
244 
245 // Stage == 1
246 // local_icon        Add a Local Printer
247 //                   ------------------------------
248 //                   Printer Name: ________________
249 //                   Printer Type: pick one
250 //                   Connected to: pick one
251 // ------------------------------------------------
252 //                                Cancel        Add
253 
254 // This seems to be hard coded into the preferences dialog:
255 // Don't show Network transport add-on in Printer Type menu.
256 // If Printer Type == Preview disable Connect to popup menu.
257 // If Printer Type == Serial Port add a submenu to menu item
258 //    with names in /dev/ports (if empty remove item from menu)
259 // If Printer Type == Parallel Port add a submenu to menu item
260 //    with names in /dev/parallel (if empty remove item from menu)
261 
262 // Printer Driver Setup
263 
264 // Dialog Info
265 // Would you like to make X the default printer?
266 //                                        No Yes
267 
268 // Add network printer:
269 
270 // Dialog Info
271 // Apple Talk networking isn't currenty enabled. If you
272 // wish to install a network printer you should enable
273 // AppleTalk in the Network preferences.
274 //                               Cancel   Open Network
275 
276 // Stage == 2
277 
278 // network_icon      Add a Network Printer
279 //                   ------------------------------
280 //                   Printer Name: ________________
281 //                   Printer Type: pick one
282 //              AppleTalk Printer: pick one
283 // ------------------------------------------------
284 //                                Cancel        Add
285 }
286 
287 
288 static directory_which gAddonDirs[] = {
289 	B_USER_NONPACKAGED_ADDONS_DIRECTORY,
290 	B_USER_ADDONS_DIRECTORY,
291 	B_SYSTEM_NONPACKAGED_ADDONS_DIRECTORY,
292 	B_SYSTEM_ADDONS_DIRECTORY,
293 };
294 
295 
296 void
297 AddPrinterDialog::_FillMenu(BMenu* menu, const char* path, uint32 what)
298 {
299 	for (uint32 i = 0; i < sizeof(gAddonDirs) / sizeof(directory_which); i++) {
300 		BPath addonPath;
301 		if (find_directory(gAddonDirs[i], &addonPath) != B_OK)
302 			continue;
303 
304 		if (addonPath.Append(path) != B_OK)
305 			continue;
306 
307 		BDirectory dir(addonPath.Path());
308 		if (dir.InitCheck() != B_OK)
309 			continue;
310 
311 		BEntry entry;
312 		while (dir.GetNextEntry(&entry, true) == B_OK) {
313 			if (!entry.IsFile())
314 				continue;
315 
316 			BNode node(&entry);
317 			if (node.InitCheck() != B_OK)
318 				continue;
319 
320 			BNodeInfo info(&node);
321 			if (info.InitCheck() != B_OK)
322 				continue;
323 
324 			char type[B_MIME_TYPE_LENGTH + 1];
325 			info.GetType(type);
326 			BMimeType entryType(type);
327 			// filter non executable entries (like "transport" subfolder...)
328 			if (entryType == B_APP_MIME_TYPE) {
329 				BPath transportPath;
330 				if (entry.GetPath(&transportPath) != B_OK)
331 					continue;
332 
333 				BMessage* msg = new BMessage(what);
334 				msg->AddString("name", transportPath.Leaf());
335 				menu->AddItem(new BMenuItem(transportPath.Leaf(), msg));
336 			}
337 		}
338 	}
339 }
340 
341 
342 void
343 AddPrinterDialog::_FillTransportMenu(BMenu* menu)
344 {
345 	BMessenger msgr;
346 	if (GetPrinterServerMessenger(msgr) != B_OK)
347 		return;
348 
349 	for (long idx = 0; ; idx++) {
350 		BMessage reply, msg(B_GET_PROPERTY);
351 		msg.AddSpecifier("Transport", idx);
352 		if (msgr.SendMessage(&msg, &reply) != B_OK)
353 			break;
354 
355 		BMessenger transport;
356 		if (reply.FindMessenger("result", &transport) != B_OK)
357 			break;
358 
359 		// Got messenger to transport now
360 		msg.MakeEmpty();
361 		msg.what = B_GET_PROPERTY;
362 		msg.AddSpecifier("Name");
363 		if (transport.SendMessage(&msg, &reply) != B_OK)
364 			continue;
365 
366 		BString transportName;
367 		if (reply.FindString("result", &transportName) != B_OK)
368 			continue;
369 
370 		// Now get ports...
371 		BString portId, portName;
372 		int32 error;
373 		msg.MakeEmpty();
374 		msg.what = B_GET_PROPERTY;
375 		msg.AddSpecifier("Ports");
376 		if (transport.SendMessage(&msg, &reply) != B_OK
377 				|| reply.FindInt32("error", &error) != B_OK
378 				|| error != B_OK
379 				|| (transportName == "IPP"
380 						&& reply.FindString("port_id", &portId) != B_OK)) {
381 			// Transport does not provide list of ports
382 			BMessage* menuMsg = new BMessage(kTransportSelectedMsg);
383 			menuMsg->AddString("name", transportName);
384 			menu->AddItem(new BMenuItem(transportName.String(), menuMsg));
385 			continue;
386 		}
387 
388 		// Create submenu
389 		BMenu* transportMenu = new TransportMenu(transportName.String(),
390 			kTransportSelectedMsg, transport, transportName);
391 		menu->AddItem(transportMenu);
392 		transportMenu->SetRadioMode(true);
393 		menu->ItemAt(menu->IndexOf(transportMenu))->
394 			SetMessage(new BMessage(kTransportSelectedMsg));
395 	}
396 }
397 
398 
399 void
400 AddPrinterDialog::_Update()
401 {
402 	fOk->SetEnabled(fNameText != "" && fPrinterText != ""
403 		&& (fTransportText != "" || fPrinterText == "Preview"));
404 
405 	fTransport->SetEnabled(fPrinterText != "Preview");
406 }
407