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