/***************************************************************************
 *
 * knetworkmanager-tray.cpp - A NetworkManager frontend for KDE
 *
 * Copyright (C) 2005, 2006 Novell, Inc.
 *
 * Author: Timo Hoenig        <thoenig@suse.de>, <thoenig@nouse.net>
 *         Will Stephenson    <wstephenson@suse.de>, <wstephenson@kde.org>
 *         Valentine Sinitsyn <e_val@inbox.ru>
 *         Helmut Schaa       <hschaa@suse.de>, <helmut.schaa@gmx.de>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 **************************************************************************/

class WirelessDialog;

#include <qsignalmapper.h>
#include <qevent.h>
#include <qvbox.h>
#include <qlayout.h>
#include <qpushbutton.h>
#include <qpixmap.h>
#include <qpixmapcache.h>
#include <qpainter.h>
#include <qstyle.h>
#include <qvaluelist.h>
#include <dcopclient.h>
#include <dbus/qdbusobjectpath.h>
#include <kdebug.h>
#include <kdialogbase.h>
#include <knotifyclient.h>
#include <knotifydialog.h>
#include <klocale.h>
#include <kstdguiitem.h>
#include <khelpmenu.h>
#include <kprocess.h>
#include <kiconloader.h>
#include <kconfig.h>
#include <kmessagebox.h>

#include <NetworkManager.h>

#include <dbus/qdbuserror.h>

#include "vpn_tray_component.h"
#include "devicetraycomponent.h"
#include "knetworkmanager-cellular_device_tray.h"
#include "knetworkmanager-cellular_device.h"
#include "knetworkmanager-device.h"
#include "knetworkmanager-devicestore.h"
#include "knetworkmanager-tray.h"
#include "knetworkmanager-menu_subhead.h"
#include "knetworkmanager-nm_proxy.h"
#include "knetworkmanager-connection_setting_info.h"
#include "knetworkmanager-connection_settings_dialog.h"
#include "knetworkmanager-connection_store.h"
#include "knetworkmanager-vpn_connection.h"
#include "knetworkmanager-connection.h"
#include "knetworkmanager-storage.h"
#include "knetworkmanager-connection_editor.h"
#include "knetworkmanager-vpnauthenticationdialog.h"
#include "knetworkmanager-wired_device.h"
#include "knetworkmanager-wired_device_tray.h"
#include "knetworkmanager-wireless_device_tray.h"
#include "knetworkmanager-wireless_device.h"

#define KDED_NETWORK_NAME "NMNetwork"

class TrayPrivate
{
	public:
		TrayPrivate(QObject* parent)
			: foregroundTrayComponent(0)
		  , signalMapper(parent, "signal_mapper")
		  , current_idx(0)
		{}
		~TrayPrivate() {}

		static Tray* tray;
		QValueList<TrayComponent*> trayComponents;
		DeviceTrayComponent * foregroundTrayComponent;
		QSignalMapper signalMapper;
		QMap<int, QPair<ConnectionSettings::Connection*, Device*> > act_conn_map;
		int current_idx;
};

Tray* TrayPrivate::tray = NULL;

Tray* Tray::getInstance()
{
	if (TrayPrivate::tray)
		return TrayPrivate::tray;
	else return (TrayPrivate::tray = new Tray());
}

void Tray::slotEditConnections()
{
	ConnectionEditorImpl* dlg = new ConnectionEditorImpl(this);
	dlg->show();
}

void Tray::slotEnableWireless()
{
	NMProxy* nm = NMProxy::getInstance();
	QDBusError err;
	if (!nm) return;

	nm->setWirelessEnabled(true, err);
}

void Tray::slotDisableWireless()
{
	NMProxy* nm = NMProxy::getInstance();
	QDBusError err;
	if (!nm) return;

	nm->setWirelessEnabled(false, err);
}

void Tray::slotOfflineMode()
{
	NMProxy* nm = NMProxy::getInstance();
	QDBusError err;
	if (!nm) return;

	nm->Sleep(true, err);
}

void Tray::slotOnlineMode()
{
	NMProxy* nm = NMProxy::getInstance();
	QDBusError err;
	if (!nm) return;

	nm->Sleep(false, err);
}

void Tray::contextMenuAboutToShow (KPopupMenu* menu)
{
	QDBusError err;
	NMProxy* nm = NMProxy::getInstance();

	// clear menu
	menu->clear();

	if (nm->isNMRunning())
	{

    // actions for each Device
		for (QValueList<TrayComponent*>::Iterator it = d->trayComponents.begin();
  	          it != d->trayComponents.end();
    	        ++it)
  	  {
  	      (*it)->addMenuItems(menu);
  	  }

		// New connection
		KAction * newConnAction = 0;
		int devices =  d->trayComponents.count();
		if ( devices > 1 ) {
			newConnAction = actionCollection ()->action ("new_connection_menu");
			KActionMenu* newConnActionMenu = static_cast<KActionMenu*>(newConnAction);
			newConnActionMenu->popupMenu()->clear();
			for (QValueList<TrayComponent*>::Iterator it = d->trayComponents.begin();
					it != d->trayComponents.end();
					++it)
			{
				DeviceTrayComponent* dev_comp = dynamic_cast<DeviceTrayComponent*> (*it);
				KAction * deviceNewConnAction = 0;
				if (dev_comp)
				{
					QString actionName = QString("new_connection_%1").arg(dev_comp->device()->getInterface());
					deviceNewConnAction = actionCollection ()->action (actionName);
					if (!deviceNewConnAction) {
						deviceNewConnAction = new KAction (dev_comp->device()->getInterface(), 0, (*it), SLOT(newConnection()), actionCollection(), actionName);
					}
					newConnActionMenu->insert(deviceNewConnAction);
				}
			}
 		} else if ( devices == 1 ) {
			newConnAction = actionCollection ()->action ("new_connection");
			QObject::disconnect( newConnAction, SIGNAL(activated()) );
			QObject::connect( newConnAction, SIGNAL(activated()), d->trayComponents[0], SLOT(newConnection()));
		}
		if (newConnAction) {
			newConnAction->plug(menu);
		}
	
	  // turn things off
		if (nm)
		{
			KActionMenu* disableStuffActionMenu = static_cast<KActionMenu*>(actionCollection ()->action ("deactivate_menu") );
			disableStuffActionMenu->popupMenu()->clear();
			QValueList<QPair<ConnectionSettings::Connection*, Device*> > map = nm->getActiveConnectionsMap();
			d->act_conn_map.clear();
	
			for (QValueList<QPair<ConnectionSettings::Connection*, Device*> >::Iterator it = map.begin(); it != map.end(); ++it)
			{
				ConnectionSettings::GenericConnection* conn = dynamic_cast<ConnectionSettings::GenericConnection*>((*it).first);
				Device* dev = (*it).second;

				if (!conn)
					continue;

				QString actionName = QString("disable_connection_%1_%2").arg(conn->getID()).arg(dev ? dev->getInterface() : "");
				KAction * deviceNewConnAction = actionCollection ()->action (actionName);
				QString actionText = conn->getInfoSetting()->getName();
				if (dev)
					actionText += QString(" (%1)").arg(dev->getInterface());

				if (!deviceNewConnAction) {
					deviceNewConnAction = new KAction (actionText, 0, &d->signalMapper, SLOT(map()), actionCollection(), actionName);
				}
				d->signalMapper.setMapping(deviceNewConnAction, d->current_idx);
				d->act_conn_map.insert(d->current_idx, QPair<ConnectionSettings::Connection*, Device*> (conn, dev));
				d->current_idx++;
				disableStuffActionMenu->insert(deviceNewConnAction);	
			}

			// disable wireless
			if (nm->getWirelessHardwareEnabled(err))
			{
				KAction* wireless = NULL;
				if (nm->getWirelessEnabled(err)) {
					wireless = actionCollection ()->action ("disable_wireless");
				} else {
					wireless = actionCollection ()->action ("enable_wireless");
				}
				disableStuffActionMenu->insert(wireless);
			}

			// offline vs. online mode
			KAction* switch_mode = NULL;
			if (nm->getState(err) != NM_STATE_ASLEEP) {
				switch_mode = actionCollection ()->action ("offline_mode");
			}
			else {
				switch_mode = actionCollection ()->action ("online_mode");
			}
			disableStuffActionMenu->insert(switch_mode);

			disableStuffActionMenu->plug(menu);
		}
	}
	else
	{
		Subhead* subhead = new Subhead (menu, "subhead", i18n("NetworkManager is not running"), SmallIcon("stop", QIconSet::Automatic));
		menu->insertItem (subhead, -1, -1);
	}

	// Notifications
	KAction* notif = actionCollection()->action("configure_notifications");
	notif->plug(menu);

	// Connection Editor
	KAction* edit = actionCollection ()->action ("edit_connections");
	edit->plug(menu);

	// quit
	menu->insertSeparator ();
	KAction* quitAction = actionCollection ()->action (KStdAction::name (KStdAction::Quit));
	if (quitAction)
		quitAction->plug (menu);
}

void
Tray::slotStateChanged(Q_UINT32 state)
{
	NMState nm_state = (NMState) state;
	// change tray icon according to NM's state
	switch(nm_state)
	{
		case NM_STATE_UNKNOWN:
		case NM_STATE_ASLEEP:
		case NM_STATE_CONNECTING:
		case NM_STATE_DISCONNECTED:
			setPixmap (loadIcon ("knetworkmanager_disabled"));
			break;
		case NM_STATE_CONNECTED:
			setPixmap (loadIcon ("knetworkmanager"));
			break;
	}
}

void
Tray::enterEvent (QEvent* /*e*/)
{
	// show tooltip
	QToolTip::remove (this);
	QString tooltip = "";

	// build up the tooltip from all tray components
	for (QValueList<TrayComponent*>::Iterator it = d->trayComponents.begin(); it != d->trayComponents.end(); ++it)
	{
		TrayComponent* comp = *it;
		if (comp->getToolTipText().isEmpty())
			continue;
		if (!tooltip.isEmpty())
			tooltip += "\n\n";
		tooltip += comp->getToolTipText().join("\n");
	}
	if (!tooltip.isEmpty())
		QToolTip::add (this, tooltip);
}

void 
Tray::slotVPNSecretsNeeded(ConnectionSettings::Connection* connection, ConnectionSettings::ConnectionSetting* setting, const QStringList& hints, bool request_new)
{
#warning Implement Tray::slotVPNSecretsNeeded to handle parms properly
	Q_UNUSED(setting);
	Q_UNUSED(hints);
	Q_UNUSED(request_new);

	kdDebug() << "Tray::slotVPNSecretsNeeded" << endl;
	ConnectionSettings::VPNConnection* conn = dynamic_cast<ConnectionSettings::VPNConnection*>(connection);
	VPNAuthenticationDialog* auth = new VPNAuthenticationDialog(conn, this, "vpnauth");
	auth->show();
}

void 
Tray::slotSecretsNeeded(ConnectionSettings::Connection* connection, ConnectionSettings::ConnectionSetting* setting, const QStringList& hints, bool request_new)
{
	Storage* storage = Storage::getInstance();
	bool hasSecretsStored = storage->hasSecretsStored(connection, setting);

	// FIXME ugly secrets handling for VPN
	if (connection->getType() == NM_SETTING_VPN_SETTING_NAME)
	{
		slotVPNSecretsNeeded(connection, setting, hints, request_new);
		return;
	}

	// default secrets handling for all other connection types
	// 1) if we have secrets stored, restore them and send them back to NM
	// 2) if NM requests new secrets we should allow the user to retry the
	//    connection or to edit it

	if (hasSecretsStored && !request_new)
	{
		// We have secrets stored, restore them
		if (storage->restoreSecrets(connection, setting))
		{
			connection->slotSecretsProvided(setting);
		}
	}
	else
	{
		// NM wants completely new secrets
		// FIXME: not implemented yet
		connection->slotSecretsError();

		//ConnectionSettingsDialogImpl* dlg = new ConnectionSettingsDialogImpl(NULL, connection, setting, this, "connect_something", false, Qt::WDestructiveClose);
		//dlg->show();
	}
}

void Tray::slotAddDeviceTrayComponent(Device* dev)
{
	if (dev)
		createDeviceTrayComponent(dev);
}

void Tray::slotRemoveDeviceTrayComponent(Device* dev)
{
	for (QValueList<TrayComponent*>::Iterator it = d->trayComponents.begin(); it != d->trayComponents.end(); ++it)
	{
		DeviceTrayComponent* dev_comp = dynamic_cast<DeviceTrayComponent*>(*it);
		if (!dev_comp)
			continue;

		if (dev_comp->device() == dev)
		{
			if (d->foregroundTrayComponent && dev_comp->device() == d->foregroundTrayComponent->device() ) {
				d->foregroundTrayComponent = 0;
			}

			// remove the appropriate action
			QString actionName = QString("new_connection_%1").arg(dev_comp->device()->getInterface());
			KAction * deviceNewConnAction = actionCollection ()->action (actionName);
			
			if (!deviceNewConnAction)
			{
				delete deviceNewConnAction;
				deviceNewConnAction = NULL;
			}
			// remove device_tray and delete it
			d->trayComponents.remove(it);
			delete dev_comp;

			if (contextMenu()->isVisible()) {
				contextMenu()->hide();
			}

			break;
		}
	}
}

void Tray::createDeviceTrayComponent(Device* dev)
{
	bool trayExists = false;

	if (!dev) return;

	// check if we have already a trayicon for this device
	for (QValueList<TrayComponent*>::Iterator it = d->trayComponents.begin(); it != d->trayComponents.end(); ++it)
	{	
		DeviceTrayComponent* dev_comp = dynamic_cast<DeviceTrayComponent*> (*it);
		if (dev_comp)
			if (dev_comp->device() == dev)
			{
				trayExists = true;
				break;
			}
	}

	// create the appropriate device tray icon
	if (!trayExists)
	{
		DeviceTrayComponent* devTray = 0;
		// different tray icons for different device types!
		switch (dev->getDeviceType())
		{
			case DEVICE_TYPE_802_3_ETHERNET:
                devTray = new WiredDeviceTray(dynamic_cast<WiredDevice*>(dev), this, "wired_device_tray");
				break;
			case DEVICE_TYPE_802_11_WIRELESS:
                devTray = new WirelessDeviceTray(static_cast<WirelessDevice*>(dev), this, "wireless_device_tray");
				break;
			case DEVICE_TYPE_GSM:
			case DEVICE_TYPE_CDMA:
                devTray = new CellularDeviceTray(static_cast<CellularDevice*>(dev), this, "cellular_device_tray");
				break;
			default:
				kdWarning() << k_funcinfo << "UDI: " << dev->getUdi() << " has unknown devicetype: " << dev->getDeviceType() << endl;
		}
		if(devTray)
		{
			connect( devTray, SIGNAL(needsCenterStage(TrayComponent*,bool)),
					SLOT(trayComponentNeedsCenterStage(TrayComponent*,bool)));
			connect( devTray, SIGNAL(uiUpdated()), SLOT(trayUiChanged()));
			d->trayComponents.append(devTray);
            //WILLTODO: sort
		}
	}
}

void Tray::createVPNTrayComponent()
{
	bool trayExists = false;

	// check if we have already a trayicon for this device
	for (QValueList<TrayComponent*>::Iterator it = d->trayComponents.begin(); it != d->trayComponents.end(); ++it)
	{	
		VPNTrayComponent* vpn_comp = dynamic_cast<VPNTrayComponent*> (*it);
		if (vpn_comp)
		{
			trayExists = true;
			break;
		}
	}

	// create the appropriate device tray icon
	if (!trayExists)
	{
		TrayComponent* devTray = new VPNTrayComponent(this, "vpn_device_tray");
		if(devTray)
		{
			d->trayComponents.append(devTray);
            //WILLTODO: sort
		}
	}
}

void Tray::updateDeviceTrays()
{
	// create one tray-icon for each device
	DeviceStore* store = DeviceStore::getInstance();	
	QValueList<Device*> devices = store->getDevices();

	// check for newly added devices
	for (QValueList<Device*>::iterator it = devices.begin(); it != devices.end(); ++it)
	{
		Device* dev = (*it);
		if (dev)
			createDeviceTrayComponent(dev);
		else
			kdWarning() << k_funcinfo << "got a NULL-Device" << endl;
	}

	// add the VPN componenet as it is not associated with a device
	createVPNTrayComponent();
}

void Tray::mousePressEvent( QMouseEvent *e )
{
    if ( !rect().contains( e->pos() ) ) {
        return;
    }
    switch ( e->button() ) {
        case LeftButton:
            contextMenuAboutToShow(contextMenu());
            contextMenu()->popup(e->globalPos());
            break;
        default:
            KSystemTray::mousePressEvent( e );
            break;
    }
}

void Tray::slotDeactivateConnection(int index)
{
	ConnectionSettings::Connection* conn = d->act_conn_map[index].first;
	Device* dev = d->act_conn_map[index].second;
	NMProxy* nm = NMProxy::getInstance();

	if (conn)
		nm->deactivateConnection(conn, dev);
}

void Tray::trayComponentNeedsCenterStage(TrayComponent *component, bool needsIt)
{
	DeviceTrayComponent * dtc = dynamic_cast<DeviceTrayComponent*>(component);
	if (dtc) {
		kdDebug() << k_funcinfo << dtc->device()->getInterface() << " : " << needsIt << endl;
		Device * device = dtc->device();
		if (needsIt) {
			if (d->foregroundTrayComponent) {
				disconnect(d->foregroundTrayComponent->device(), SIGNAL(StateChanged(NMDeviceState)), this, 0 );
			}
			d->foregroundTrayComponent = dtc;
			connect(device, SIGNAL(StateChanged(NMDeviceState)),
					SLOT(slotUpdateDeviceState(NMDeviceState)));
		} else {
			disconnect(device, SIGNAL(StateChanged(NMDeviceState)), this, 0 );
			//use active default
			NMProxy* nm = NMProxy::getInstance();
			device = nm->getDefaultDevice();
			if ( device ) {
				// identify the new foreground
				for (QValueList<TrayComponent*>::Iterator it = d->trayComponents.begin(); it != d->trayComponents.end(); ++it)
				{	
					DeviceTrayComponent* newDtc = dynamic_cast<DeviceTrayComponent*> (*it);
					if ( newDtc && newDtc->device() == device ) {
						d->foregroundTrayComponent = newDtc;
						break;
					}
				}
				kdDebug() << "  Device " << dtc->device()->getInterface() << " background, new foreground device: " << device->getInterface() << endl;
				connect(device, SIGNAL(StateChanged(NMDeviceState)),
						SLOT(slotUpdateDeviceState(NMDeviceState)));
				slotUpdateDeviceState(device->getState());
			}
		}
	}
}

void Tray::slotUpdateDeviceState(NMDeviceState state)
{
	updateTrayIcon(state);
	updateActiveConnection(state);
}

void Tray::trayUiChanged()
{
	DeviceTrayComponent * dtc = d->foregroundTrayComponent;
	if (dtc) {
		updateTrayIcon(dtc->device()->getState());
	}
}
void Tray::updateTrayIcon(NMDeviceState state)
{
	// stop the old movie to avoid unnecessary wakups
	DeviceTrayComponent * dtc = d->foregroundTrayComponent;

	if (movie())
		movie()->pause();

	if (dtc) {

		if (!dtc->movieForState(state).isNull())
		{
			// animation desired
			int frame = -1;
			if (movie())
				frame = movie()->frameNumber();

			// set the movie
			setMovie(dtc->movieForState(state));

			// start at the same frame as the movie before
			if (frame > 0)
				movie()->step(frame);

			// start the animation
			movie()->unpause();
		}
		else if (!dtc->pixmapForState(state).isNull())
			setPixmap(dtc->pixmapForState(state));
		else
			setPixmap(loadIcon("knetworkmanager"));
	}
	else
		setPixmap(loadIcon("knetworkmanager"));
}

void Tray::updateActiveConnection(NMDeviceState state)
{
	if (state != NM_DEVICE_STATE_ACTIVATED)
		return;

	NMProxy* nm = NMProxy::getInstance();
	if (d->foregroundTrayComponent) {
		Connection* active_conn = nm->getActiveConnection(d->foregroundTrayComponent->device());
		if (active_conn)
		{
			Info* info = dynamic_cast<Info*>(active_conn->getSetting(NM_SETTING_CONNECTION_SETTING_NAME));
			if (info)
				info->setTimestamp(QDateTime::currentDateTime());
		}
	}
}

void Tray::slotDeviceAddedNotify(Device* dev)
{
	kdDebug() << "Tray::slotDeviceAddedNotify" << endl;
	KNotifyClient::event( winId(), "knm-nm-device-added", i18n("New network device %1 found").arg(dev->getInterface()) );
}

void Tray::slotDeviceRemovedNotify(Device* dev)
{
	kdDebug() << "Tray::slotDeviceRemovedNotify" << endl;
	KNotifyClient::event( winId(), "knm-nm-device-removed", i18n("Network device %1 removed").arg(dev->getInterface()) );
}

void Tray::slotStateChangedNotify(Q_UINT32 state)
{
	NMState nm_state = (NMState) state;
	// change tray icon according to NM's state
	switch(nm_state)
	{
		case NM_STATE_CONNECTING:
			KNotifyClient::event( winId(), "knm-nm-connecting", i18n("NetworkManager is connecting") );
			break;
		case NM_STATE_DISCONNECTED:
			KNotifyClient::event( winId(), "knm-nm-disconnected", i18n("NetworkManager is now disconnected") );
			break;
		case NM_STATE_CONNECTED:
			KNotifyClient::event( winId(), "knm-nm-connected", i18n("NetworkManager is now connected") );
			break;
		case NM_STATE_ASLEEP:
			KNotifyClient::event( winId(), "knm-nm-sleeping", i18n("KNetworkManager Offline") );
			break;
		case NM_STATE_UNKNOWN:

		default:
			break;
	}
}

void Tray::slotEditNotifications()
{
	KNotifyDialog::configure(this);
}

Tray::Tray () : KSystemTray ()
{
	d = new TrayPrivate(this);

	connect(&d->signalMapper, SIGNAL(mapped(int)), this, SLOT(slotDeactivateConnection(int)));

	setPixmap (loadIcon ("knetworkmanager"));
	setMouseTracking (true);

	// Actions used for plugging into the menu
	new KAction (i18n ("Switch to offline mode"),
					     SmallIcon ("no",  QIconSet::Automatic), 0,
					     this, SLOT (slotOfflineMode()), actionCollection (), "offline_mode");

	new KAction (i18n ("Switch to online mode"),
					     SmallIcon ("ok",  QIconSet::Automatic), 0,
					     this, SLOT (slotOnlineMode()), actionCollection (), "online_mode");

	new KAction (i18n ("Disable Wireless"),
					     SmallIcon ("wireless_off",  QIconSet::Automatic), 0,
					     this, SLOT (slotDisableWireless()), actionCollection (), "disable_wireless");

	new KAction (i18n ("Enable Wireless"),
					     SmallIcon ("wireless",  QIconSet::Automatic), 0,
					     this, SLOT (slotEnableWireless()), actionCollection (), "enable_wireless");

	new KAction (i18n ("Edit Connections"),
					     SmallIcon ("edit",  QIconSet::Automatic), 0,
					     this, SLOT (slotEditConnections()), actionCollection (), "edit_connections");

	new KAction (i18n ("Configure Notifications"),
					     SmallIcon ("knotify",  QIconSet::Automatic), 0,
					     this, SLOT (slotEditNotifications()), actionCollection (), "configure_notifications");

	// this action is only connected when the menu is shown, hence the 0 receiver
	new KAction (i18n ("New connection ..."),
					     SmallIcon ("filenew",  QIconSet::Automatic), 0,
					     this, 0, actionCollection (), "new_connection");

	new KActionMenu (i18n ("New connection ..."),
					     SmallIcon ("filenew",  QIconSet::Automatic),
					     actionCollection(), "new_connection_menu");

	new KActionMenu (i18n ("Deactivate connection..."),
			SmallIcon ("no",  QIconSet::Automatic),
			actionCollection (), "deactivate_menu");

	// get notified when NM's state changes
	NMProxy* nm = NMProxy::getInstance();
	connect(nm, SIGNAL(StateChange(Q_UINT32)), this, SLOT(slotStateChanged(Q_UINT32)));

	// get notifier when NM requests new secrets
	ConnectionStore* cstore = ConnectionStore::getInstance();
	connect(cstore, SIGNAL(SecretsNeeded(ConnectionSettings::Connection*, ConnectionSettings::ConnectionSetting*, const QStringList&, bool)), this, SLOT(slotSecretsNeeded(ConnectionSettings::Connection*, ConnectionSettings::ConnectionSetting*, const QStringList&, bool)));

	// get notified about new/removed devices
	DeviceStore* store = DeviceStore::getInstance();
	connect(store, SIGNAL(DeviceStoreChanged()), this, SLOT(updateDeviceTrays()));	
	connect(store, SIGNAL(DeviceAdded(Device*)), this, SLOT(slotAddDeviceTrayComponent(Device*)));	
	connect(store, SIGNAL(DeviceRemoved(Device*)), this, SLOT(slotRemoveDeviceTrayComponent(Device*)));	

	// Notifications
	connect(store, SIGNAL(DeviceAdded(Device*)), this, SLOT(slotDeviceAddedNotify(Device*)));	
	connect(store, SIGNAL(DeviceRemoved(Device*)), this, SLOT(slotDeviceRemovedNotify(Device*)));	
	connect(nm, SIGNAL(StateChange(Q_UINT32)), this, SLOT(slotStateChangedNotify(Q_UINT32)));


	// initial setup of the device-trays
	updateDeviceTrays();

	QDBusError err;
	slotStateChanged(nm->getState(err));
}

Tray::~Tray ()
{
	delete d;
}

#include "knetworkmanager-tray.moc"

