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