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
AddPrinterDialog(BWindow * parent)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
QuitRequested()54 AddPrinterDialog::QuitRequested()
55 {
56 fPrintersPrefletMessenger.SendMessage(kMsgAddPrinterClosed);
57 return Inherited::QuitRequested();
58 }
59
60
61 void
MessageReceived(BMessage * msg)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
_AddPrinter(BMessage * msg)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
_StorePrinter(BMessage * msg)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
_HandleChangedTransport(BMessage * msg)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
_BuildGUI(int stage)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
_FillMenu(BMenu * menu,const char * path,uint32 what)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
_FillTransportMenu(BMenu * menu)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
_Update()400 AddPrinterDialog::_Update()
401 {
402 fOk->SetEnabled(fNameText != "" && fPrinterText != ""
403 && (fTransportText != "" || fPrinterText == "Preview"));
404
405 fTransport->SetEnabled(fPrinterText != "Preview");
406 }
407