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