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