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