/*
* Copyright 2002-2009, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Pfeiffer
* Philippe Houdoin
*/
#include "AddPrinterDialog.h"
#include <stdio.h>
#include <Button.h>
#include <Catalog.h>
#include <FindDirectory.h>
#include <GroupLayoutBuilder.h>
#include <Layout.h>
#include <LayoutBuilder.h>
#include <Locale.h>
#include <MenuField.h>
#include <MenuItem.h>
#include <MimeType.h>
#include <NodeInfo.h>
#include <Path.h>
#include "pr_server.h"
#include "Globals.h"
#include "Messages.h"
#include "PrinterListView.h"
#include "TransportMenu.h"
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "AddPrinterDialog"
AddPrinterDialog::AddPrinterDialog(BWindow *parent)
:
Inherited(BRect(78, 71, 400, 300), B_TRANSLATE("Add printer"),
B_TITLED_WINDOW_LOOK, B_MODAL_APP_WINDOW_FEEL,
B_NOT_ZOOMABLE | B_AUTO_UPDATE_SIZE_LIMITS
| B_CLOSE_ON_ESCAPE),
fPrintersPrefletMessenger(parent)
{
_BuildGUI(0);
Show();
}
bool
AddPrinterDialog::QuitRequested()
{
fPrintersPrefletMessenger.SendMessage(kMsgAddPrinterClosed);
return Inherited::QuitRequested();
}
void
AddPrinterDialog::MessageReceived(BMessage* msg)
{
switch(msg->what) {
case B_OK:
_AddPrinter(msg);
PostMessage(B_QUIT_REQUESTED);
break;
case B_CANCEL:
PostMessage(B_QUIT_REQUESTED);
break;
case kNameChangedMsg:
fNameText = fName->Text();
_Update();
break;
case kPrinterSelectedMsg:
_StorePrinter(msg);
break;
case kTransportSelectedMsg:
_HandleChangedTransport(msg);
break;
default:
Inherited::MessageReceived(msg);
break;
}
}
void
AddPrinterDialog::_AddPrinter(BMessage *msg)
{
BMessage m(PSRV_MAKE_PRINTER);
BMessenger msgr;
if (GetPrinterServerMessenger(msgr) != B_OK)
return;
BString transport;
BString transportPath;
if (fPrinterText != "Preview") {
// Preview printer does not use transport add-on
transport = fTransportText;
transportPath = fTransportPathText;
}
m.AddString("driver", fPrinterText.String());
m.AddString("transport", transport.String());
m.AddString("transport path", transportPath.String());
m.AddString("printer name", fNameText.String());
m.AddString("connection", "Local");
msgr.SendMessage(&m);
// request print_server to create printer
}
void
AddPrinterDialog::_StorePrinter(BMessage *msg)
{
BString name;
if (msg->FindString("name", &name) != B_OK)
name = "";
fPrinterText = name;
_Update();
}
void
AddPrinterDialog::_HandleChangedTransport(BMessage *msg)
{
BString name;
if (msg->FindString("name", &name) != B_OK) {
name = "";
}
fTransportText = name;
BString path;
if (msg->FindString("path", &path) == B_OK) {
// transport path selected
fTransportPathText = path;
// mark sub menu
void* pointer;
if (msg->FindPointer("source", &pointer) == B_OK) {
BMenuItem* item = (BMenuItem*)pointer;
// Update printer name with Transport Path if not filled in
if (strlen(fName->Text()) == 0)
fName->SetText(item->Label());
BMenu* menu = item->Menu();
int32 index = fTransport->IndexOf(menu);
item = fTransport->ItemAt(index);
if (item != NULL)
item->SetMarked(true);
}
} else {
// transport selected
fTransportPathText = "";
// remove mark from item in sub menu of transport sub menu
for (int32 i = fTransport->CountItems() - 1; i >= 0; i --) {
BMenu* menu = fTransport->SubmenuAt(i);
if (menu != NULL) {
BMenuItem* item = menu->FindMarked();
if (item != NULL)
item->SetMarked(false);
}
}
}
_Update();
}
void
AddPrinterDialog::_BuildGUI(int stage)
{
// add a "printer name" input field
fName = new BTextControl("printer_name", B_TRANSLATE("Printer name:"),
B_EMPTY_STRING, NULL);
fName->SetFont(be_bold_font);
fName->SetAlignment(B_ALIGN_RIGHT, B_ALIGN_LEFT);
fName->SetModificationMessage(new BMessage(kNameChangedMsg));
// add a "driver" popup menu field
fPrinter = new BPopUpMenu(B_TRANSLATE("<pick one>"));
BMenuField *printerMenuField = new BMenuField("drivers_list",
B_TRANSLATE("Printer type:"), fPrinter);
printerMenuField->SetAlignment(B_ALIGN_RIGHT);
_FillMenu(fPrinter, "Print", kPrinterSelectedMsg);
// add a "connected to" (aka transports list) menu field
fTransport = new BPopUpMenu(B_TRANSLATE("<pick one>"));
BMenuField *transportMenuField = new BMenuField("transports_list",
B_TRANSLATE("Connected to:"), fTransport);
transportMenuField->SetAlignment(B_ALIGN_RIGHT);
_FillTransportMenu(fTransport);
// add a "OK" button
fOk = new BButton(NULL, B_TRANSLATE("Add"), new BMessage((uint32)B_OK),
B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM);
// add a "Cancel button
BButton *cancel = new BButton(NULL, B_TRANSLATE("Cancel"),
new BMessage(B_CANCEL));
BLayoutBuilder::Grid<>(this, B_USE_ITEM_SPACING, B_USE_ITEM_SPACING)
.Add(fName->CreateLabelLayoutItem(), 0, 0)
.Add(fName->CreateTextViewLayoutItem(), 1, 0)
.Add(printerMenuField->CreateLabelLayoutItem(), 0, 1)
.Add(printerMenuField->CreateMenuBarLayoutItem(), 1, 1)
.Add(transportMenuField->CreateLabelLayoutItem(), 0, 2)
.Add(transportMenuField->CreateMenuBarLayoutItem(), 1, 2)
.Add(BGroupLayoutBuilder(B_HORIZONTAL)
.AddGlue()
.Add(cancel)
.Add(fOk)
, 0, 3, 2)
.SetInsets(B_USE_WINDOW_SPACING, B_USE_WINDOW_SPACING,
B_USE_WINDOW_SPACING, B_USE_WINDOW_SPACING);
AddShortcut('W', B_COMMAND_KEY, new BMessage(B_QUIT_REQUESTED));
SetDefaultButton(fOk);
fOk->MakeDefault(true);
fName->MakeFocus(true);
_Update();
// Stage == 0
// init_icon 64x114 Add a Local or Network Printer
// ------------------------------
// I would like to add a...
// Local Printer
// Network Printer
// ------------------------------------------------
// Cancel Continue
// Add local printer:
// Stage == 1
// local_icon Add a Local Printer
// ------------------------------
// Printer Name: ________________
// Printer Type: pick one
// Connected to: pick one
// ------------------------------------------------
// Cancel Add
// This seems to be hard coded into the preferences dialog:
// Don't show Network transport add-on in Printer Type menu.
// If Printer Type == Preview disable Connect to popup menu.
// If Printer Type == Serial Port add a submenu to menu item
// with names in /dev/ports (if empty remove item from menu)
// If Printer Type == Parallel Port add a submenu to menu item
// with names in /dev/parallel (if empty remove item from menu)
// Printer Driver Setup
// Dialog Info
// Would you like to make X the default printer?
// No Yes
// Add network printer:
// Dialog Info
// Apple Talk networking isn't currenty enabled. If you
// wish to install a network printer you should enable
// AppleTalk in the Network preferences.
// Cancel Open Network
// Stage == 2
// network_icon Add a Network Printer
// ------------------------------
// Printer Name: ________________
// Printer Type: pick one
// AppleTalk Printer: pick one
// ------------------------------------------------
// Cancel Add
}
static directory_which gAddonDirs[] = {
B_USER_NONPACKAGED_ADDONS_DIRECTORY,
B_USER_ADDONS_DIRECTORY,
B_SYSTEM_NONPACKAGED_ADDONS_DIRECTORY,
B_SYSTEM_ADDONS_DIRECTORY,
};
void
AddPrinterDialog::_FillMenu(BMenu* menu, const char* path, uint32 what)
{
for (uint32 i = 0; i < sizeof(gAddonDirs) / sizeof(directory_which); i++) {
BPath addonPath;
if (find_directory(gAddonDirs[i], &addonPath) != B_OK)
continue;
if (addonPath.Append(path) != B_OK)
continue;
BDirectory dir(addonPath.Path());
if (dir.InitCheck() != B_OK)
continue;
BEntry entry;
while (dir.GetNextEntry(&entry, true) == B_OK) {
if (!entry.IsFile())
continue;
BNode node(&entry);
if (node.InitCheck() != B_OK)
continue;
BNodeInfo info(&node);
if (info.InitCheck() != B_OK)
continue;
char type[B_MIME_TYPE_LENGTH + 1];
info.GetType(type);
BMimeType entryType(type);
// filter non executable entries (like "transport" subfolder...)
if (entryType == B_APP_MIME_TYPE) {
BPath transportPath;
if (entry.GetPath(&transportPath) != B_OK)
continue;
BMessage* msg = new BMessage(what);
msg->AddString("name", transportPath.Leaf());
menu->AddItem(new BMenuItem(transportPath.Leaf(), msg));
}
}
}
}
void
AddPrinterDialog::_FillTransportMenu(BMenu* menu)
{
BMessenger msgr;
if (GetPrinterServerMessenger(msgr) != B_OK)
return;
for (long idx = 0; ; idx++) {
BMessage reply, msg(B_GET_PROPERTY);
msg.AddSpecifier("Transport", idx);
if (msgr.SendMessage(&msg, &reply) != B_OK)
break;
BMessenger transport;
if (reply.FindMessenger("result", &transport) != B_OK)
break;
// Got messenger to transport now
msg.MakeEmpty();
msg.what = B_GET_PROPERTY;
msg.AddSpecifier("Name");
if (transport.SendMessage(&msg, &reply) != B_OK)
continue;
BString transportName;
if (reply.FindString("result", &transportName) != B_OK)
continue;
// Now get ports...
BString portId, portName;
int32 error;
msg.MakeEmpty();
msg.what = B_GET_PROPERTY;
msg.AddSpecifier("Ports");
if (transport.SendMessage(&msg, &reply) != B_OK
|| reply.FindInt32("error", &error) != B_OK
|| error != B_OK
|| (transportName == "IPP"
&& reply.FindString("port_id", &portId) != B_OK)) {
// Transport does not provide list of ports
BMessage* menuMsg = new BMessage(kTransportSelectedMsg);
menuMsg->AddString("name", transportName);
menu->AddItem(new BMenuItem(transportName.String(), menuMsg));
continue;
}
// Create submenu
BMenu* transportMenu = new TransportMenu(transportName.String(),
kTransportSelectedMsg, transport, transportName);
menu->AddItem(transportMenu);
transportMenu->SetRadioMode(true);
menu->ItemAt(menu->IndexOf(transportMenu))->
SetMessage(new BMessage(kTransportSelectedMsg));
}
}
void
AddPrinterDialog::_Update()
{
fOk->SetEnabled(fNameText != "" && fPrinterText != ""
&& (fTransportText != "" || fPrinterText == "Preview"));
fTransport->SetEnabled(fPrinterText != "Preview");
}
↑ V773 Visibility scope of the 'transportMenuField' pointer was exited without releasing the memory. A memory leak is possible.
↑ V773 Visibility scope of the 'printerMenuField' pointer was exited without releasing the memory. A memory leak is possible.