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
40AddPrinterDialog::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
53bool
54AddPrinterDialog::QuitRequested()
55{
56	fPrintersPrefletMessenger.SendMessage(kMsgAddPrinterClosed);
57	return Inherited::QuitRequested();
58}
59
60
61void
62AddPrinterDialog::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
93void
94AddPrinterDialog::_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
119void
120AddPrinterDialog::_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
131void
132AddPrinterDialog::_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
178void
179AddPrinterDialog::_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
287static directory_which gAddonDirs[] = {
288	B_USER_ADDONS_DIRECTORY,
289	B_COMMON_ADDONS_DIRECTORY,
290	B_SYSTEM_ADDONS_DIRECTORY,
291};
292
293
294void
295AddPrinterDialog::_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
340void
341AddPrinterDialog::_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
395void
396AddPrinterDialog::_Update()
397{
398	fOk->SetEnabled(fNameText != "" && fPrinterText != ""
399		&& (fTransportText != "" || fPrinterText == "Preview"));
400
401	fTransport->SetEnabled(fPrinterText != "Preview");
402}
403
404