1
/***************************************************************************
3
* knetworkmanager-tray.cpp - A NetworkManager frontend for KDE
5
* Copyright (C) 2005, 2006 Novell, Inc.
7
* Author: Timo Hoenig <thoenig@suse.de>, <thoenig@nouse.net>
8
* Will Stephenson <wstephenson@suse.de>, <wstephenson@kde.org>
9
* Valentine Sinitsyn <e_val@inbox.ru>
10
* Helmut Schaa <hschaa@suse.de>, <helmut.schaa@gmx.de>
12
* This program is free software; you can redistribute it and/or modify
13
* it under the terms of the GNU General Public License as published by
14
* the Free Software Foundation; either version 2 of the License, or
15
* (at your option) any later version.
17
* This program is distributed in the hope that it will be useful,
18
* but WITHOUT ANY WARRANTY; without even the implied warranty of
19
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20
* GNU General Public License for more details.
22
* You should have received a copy of the GNU General Public License
23
* along with this program; if not, write to the Free Software
24
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26
**************************************************************************/
30
#include <qsignalmapper.h>
34
#include <qpushbutton.h>
36
#include <qpixmapcache.h>
39
#include <qvaluelist.h>
40
#include <dcopclient.h>
41
#include <dbus/qdbusobjectpath.h>
43
#include <kdialogbase.h>
44
#include <knotifyclient.h>
45
#include <knotifydialog.h>
47
#include <kstdguiitem.h>
48
#include <khelpmenu.h>
50
#include <kiconloader.h>
52
#include <kmessagebox.h>
54
#include <NetworkManager.h>
56
#include <dbus/qdbuserror.h>
58
#include "vpn_tray_component.h"
59
#include "devicetraycomponent.h"
60
#include "knetworkmanager-cellular_device_tray.h"
61
#include "knetworkmanager-cellular_device.h"
62
#include "knetworkmanager-device.h"
63
#include "knetworkmanager-devicestore.h"
64
#include "knetworkmanager-tray.h"
65
#include "knetworkmanager-menu_subhead.h"
66
#include "knetworkmanager-nm_proxy.h"
67
#include "knetworkmanager-connection_setting_info.h"
68
#include "knetworkmanager-connection_settings_dialog.h"
69
#include "knetworkmanager-connection_store.h"
70
#include "knetworkmanager-vpn_connection.h"
71
#include "knetworkmanager-connection.h"
72
#include "knetworkmanager-storage.h"
73
#include "knetworkmanager-connection_editor.h"
74
#include "knetworkmanager-vpnauthenticationdialog.h"
75
#include "knetworkmanager-wired_device.h"
76
#include "knetworkmanager-wired_device_tray.h"
77
#include "knetworkmanager-wireless_device_tray.h"
78
#include "knetworkmanager-wireless_device.h"
80
#define KDED_NETWORK_NAME "NMNetwork"
85
TrayPrivate(QObject* parent)
86
: foregroundTrayComponent(0)
87
, signalMapper(parent, "signal_mapper")
93
QValueList<TrayComponent*> trayComponents;
94
DeviceTrayComponent * foregroundTrayComponent;
95
QSignalMapper signalMapper;
96
QMap<int, QPair<ConnectionSettings::Connection*, Device*> > act_conn_map;
100
Tray* TrayPrivate::tray = NULL;
102
Tray* Tray::getInstance()
104
if (TrayPrivate::tray)
105
return TrayPrivate::tray;
106
else return (TrayPrivate::tray = new Tray());
109
void Tray::slotEditConnections()
111
ConnectionEditorImpl* dlg = new ConnectionEditorImpl(this);
115
void Tray::slotEnableWireless()
117
NMProxy* nm = NMProxy::getInstance();
121
nm->setWirelessEnabled(true, err);
124
void Tray::slotDisableWireless()
126
NMProxy* nm = NMProxy::getInstance();
130
nm->setWirelessEnabled(false, err);
133
void Tray::slotOfflineMode()
135
NMProxy* nm = NMProxy::getInstance();
139
nm->Sleep(true, err);
142
void Tray::slotOnlineMode()
144
NMProxy* nm = NMProxy::getInstance();
148
nm->Sleep(false, err);
151
void Tray::contextMenuAboutToShow (KPopupMenu* menu)
154
NMProxy* nm = NMProxy::getInstance();
159
if (nm->isNMRunning())
162
// actions for each Device
163
for (QValueList<TrayComponent*>::Iterator it = d->trayComponents.begin();
164
it != d->trayComponents.end();
167
(*it)->addMenuItems(menu);
171
KAction * newConnAction = 0;
172
int devices = d->trayComponents.count();
174
newConnAction = actionCollection ()->action ("new_connection_menu");
175
KActionMenu* newConnActionMenu = static_cast<KActionMenu*>(newConnAction);
176
newConnActionMenu->popupMenu()->clear();
177
for (QValueList<TrayComponent*>::Iterator it = d->trayComponents.begin();
178
it != d->trayComponents.end();
181
DeviceTrayComponent* dev_comp = dynamic_cast<DeviceTrayComponent*> (*it);
182
KAction * deviceNewConnAction = 0;
185
QString actionName = QString("new_connection_%1").arg(dev_comp->device()->getInterface());
186
deviceNewConnAction = actionCollection ()->action (actionName);
187
if (!deviceNewConnAction) {
188
deviceNewConnAction = new KAction (dev_comp->device()->getInterface(), 0, (*it), SLOT(newConnection()), actionCollection(), actionName);
190
newConnActionMenu->insert(deviceNewConnAction);
193
} else if ( devices == 1 ) {
194
newConnAction = actionCollection ()->action ("new_connection");
195
QObject::disconnect( newConnAction, SIGNAL(activated()) );
196
QObject::connect( newConnAction, SIGNAL(activated()), d->trayComponents[0], SLOT(newConnection()));
199
newConnAction->plug(menu);
205
KActionMenu* disableStuffActionMenu = static_cast<KActionMenu*>(actionCollection ()->action ("deactivate_menu") );
206
disableStuffActionMenu->popupMenu()->clear();
207
QValueList<QPair<ConnectionSettings::Connection*, Device*> > map = nm->getActiveConnectionsMap();
208
d->act_conn_map.clear();
210
for (QValueList<QPair<ConnectionSettings::Connection*, Device*> >::Iterator it = map.begin(); it != map.end(); ++it)
212
ConnectionSettings::GenericConnection* conn = dynamic_cast<ConnectionSettings::GenericConnection*>((*it).first);
213
Device* dev = (*it).second;
218
QString actionName = QString("disable_connection_%1_%2").arg(conn->getID()).arg(dev ? dev->getInterface() : "");
219
KAction * deviceNewConnAction = actionCollection ()->action (actionName);
220
QString actionText = conn->getInfoSetting()->getName();
222
actionText += QString(" (%1)").arg(dev->getInterface());
224
if (!deviceNewConnAction) {
225
deviceNewConnAction = new KAction (actionText, 0, &d->signalMapper, SLOT(map()), actionCollection(), actionName);
227
d->signalMapper.setMapping(deviceNewConnAction, d->current_idx);
228
d->act_conn_map.insert(d->current_idx, QPair<ConnectionSettings::Connection*, Device*> (conn, dev));
230
disableStuffActionMenu->insert(deviceNewConnAction);
234
if (nm->getWirelessHardwareEnabled(err))
236
KAction* wireless = NULL;
237
if (nm->getWirelessEnabled(err)) {
238
wireless = actionCollection ()->action ("disable_wireless");
240
wireless = actionCollection ()->action ("enable_wireless");
242
disableStuffActionMenu->insert(wireless);
245
// offline vs. online mode
246
KAction* switch_mode = NULL;
247
if (nm->getState(err) != NM_STATE_ASLEEP) {
248
switch_mode = actionCollection ()->action ("offline_mode");
251
switch_mode = actionCollection ()->action ("online_mode");
253
disableStuffActionMenu->insert(switch_mode);
255
disableStuffActionMenu->plug(menu);
260
Subhead* subhead = new Subhead (menu, "subhead", i18n("NetworkManager is not running"), SmallIcon("stop", QIconSet::Automatic));
261
menu->insertItem (subhead, -1, -1);
265
KAction* notif = actionCollection()->action("configure_notifications");
269
KAction* edit = actionCollection ()->action ("edit_connections");
273
menu->insertSeparator ();
274
KAction* quitAction = actionCollection ()->action (KStdAction::name (KStdAction::Quit));
276
quitAction->plug (menu);
280
Tray::slotStateChanged(Q_UINT32 state)
282
NMState nm_state = (NMState) state;
283
// change tray icon according to NM's state
286
case NM_STATE_UNKNOWN:
287
case NM_STATE_ASLEEP:
288
case NM_STATE_CONNECTING:
289
case NM_STATE_DISCONNECTED:
290
setPixmap (loadIcon ("knetworkmanager_disabled"));
292
case NM_STATE_CONNECTED:
293
setPixmap (loadIcon ("knetworkmanager"));
299
Tray::enterEvent (QEvent* /*e*/)
302
QToolTip::remove (this);
303
QString tooltip = "";
305
// build up the tooltip from all tray components
306
for (QValueList<TrayComponent*>::Iterator it = d->trayComponents.begin(); it != d->trayComponents.end(); ++it)
308
TrayComponent* comp = *it;
309
if (comp->getToolTipText().isEmpty())
311
if (!tooltip.isEmpty())
313
tooltip += comp->getToolTipText().join("\n");
315
if (!tooltip.isEmpty())
316
QToolTip::add (this, tooltip);
320
Tray::slotVPNSecretsNeeded(ConnectionSettings::Connection* connection, ConnectionSettings::ConnectionSetting* setting, const QStringList& hints, bool request_new)
322
#warning Implement Tray::slotVPNSecretsNeeded to handle parms properly
325
Q_UNUSED(request_new);
327
printf("Tray::slotVPNSecretsNeeded\n");
328
ConnectionSettings::VPNConnection* conn = dynamic_cast<ConnectionSettings::VPNConnection*>(connection);
329
VPNAuthenticationDialog* auth = new VPNAuthenticationDialog(conn, this, "vpnauth");
334
Tray::slotSecretsNeeded(ConnectionSettings::Connection* connection, ConnectionSettings::ConnectionSetting* setting, const QStringList& hints, bool request_new)
336
Storage* storage = Storage::getInstance();
337
bool hasSecretsStored = storage->hasSecretsStored(connection, setting);
339
// FIXME ugly secrets handling for VPN
340
if (connection->getType() == NM_SETTING_VPN_SETTING_NAME)
342
slotVPNSecretsNeeded(connection, setting, hints, request_new);
346
// default secrets handling for all other connection types
347
// 1) if we have secrets stored, restore them and send them back to NM
348
// 2) if NM requests new secrets we should allow the user to retry the
349
// connection or to edit it
351
if (hasSecretsStored && !request_new)
353
// We have secrets stored, restore them
354
if (storage->restoreSecrets(connection, setting))
356
connection->slotSecretsProvided(setting);
361
// NM wants completely new secrets
362
// FIXME: not implemented yet
363
connection->slotSecretsError();
365
//ConnectionSettingsDialogImpl* dlg = new ConnectionSettingsDialogImpl(NULL, connection, setting, this, "connect_something", false, Qt::WDestructiveClose);
370
void Tray::slotAddDeviceTrayComponent(Device* dev)
373
createDeviceTrayComponent(dev);
376
void Tray::slotRemoveDeviceTrayComponent(Device* dev)
378
for (QValueList<TrayComponent*>::Iterator it = d->trayComponents.begin(); it != d->trayComponents.end(); ++it)
380
DeviceTrayComponent* dev_comp = dynamic_cast<DeviceTrayComponent*>(*it);
384
if (dev_comp->device() == dev)
386
if (d->foregroundTrayComponent && dev_comp->device() == d->foregroundTrayComponent->device() ) {
387
d->foregroundTrayComponent = 0;
390
// remove the appropriate action
391
QString actionName = QString("new_connection_%1").arg(dev_comp->device()->getInterface());
392
KAction * deviceNewConnAction = actionCollection ()->action (actionName);
394
if (!deviceNewConnAction)
396
delete deviceNewConnAction;
397
deviceNewConnAction = NULL;
399
// remove device_tray and delete it
400
d->trayComponents.remove(it);
403
if (contextMenu()->isVisible()) {
404
contextMenu()->hide();
412
void Tray::createDeviceTrayComponent(Device* dev)
414
bool trayExists = false;
418
// check if we have already a trayicon for this device
419
for (QValueList<TrayComponent*>::Iterator it = d->trayComponents.begin(); it != d->trayComponents.end(); ++it)
421
DeviceTrayComponent* dev_comp = dynamic_cast<DeviceTrayComponent*> (*it);
423
if (dev_comp->device() == dev)
430
// create the appropriate device tray icon
433
DeviceTrayComponent* devTray = 0;
434
// different tray icons for different device types!
435
switch (dev->getDeviceType())
437
case DEVICE_TYPE_802_3_ETHERNET:
438
devTray = new WiredDeviceTray(dynamic_cast<WiredDevice*>(dev), this, "wired_device_tray");
440
case DEVICE_TYPE_802_11_WIRELESS:
441
devTray = new WirelessDeviceTray(static_cast<WirelessDevice*>(dev), this, "wireless_device_tray");
443
case DEVICE_TYPE_GSM:
444
case DEVICE_TYPE_CDMA:
445
devTray = new CellularDeviceTray(static_cast<CellularDevice*>(dev), this, "cellular_device_tray");
448
kdWarning() << k_funcinfo << "UDI: " << dev->getUdi() << " has unknown devicetype: " << dev->getDeviceType() << endl;
452
connect( devTray, SIGNAL(needsCenterStage(TrayComponent*,bool)),
453
SLOT(trayComponentNeedsCenterStage(TrayComponent*,bool)));
454
connect( devTray, SIGNAL(uiUpdated()), SLOT(trayUiChanged()));
455
d->trayComponents.append(devTray);
461
void Tray::createVPNTrayComponent()
463
bool trayExists = false;
465
// check if we have already a trayicon for this device
466
for (QValueList<TrayComponent*>::Iterator it = d->trayComponents.begin(); it != d->trayComponents.end(); ++it)
468
VPNTrayComponent* vpn_comp = dynamic_cast<VPNTrayComponent*> (*it);
476
// create the appropriate device tray icon
479
TrayComponent* devTray = new VPNTrayComponent(this, "vpn_device_tray");
482
d->trayComponents.append(devTray);
488
void Tray::updateDeviceTrays()
490
// create one tray-icon for each device
491
DeviceStore* store = DeviceStore::getInstance();
492
QValueList<Device*> devices = store->getDevices();
494
// check for newly added devices
495
for (QValueList<Device*>::iterator it = devices.begin(); it != devices.end(); ++it)
499
createDeviceTrayComponent(dev);
501
kdWarning() << k_funcinfo << "got a NULL-Device" << endl;
504
// add the VPN componenet as it is not associated with a device
505
createVPNTrayComponent();
508
void Tray::mousePressEvent( QMouseEvent *e )
510
if ( !rect().contains( e->pos() ) ) {
513
switch ( e->button() ) {
515
contextMenuAboutToShow(contextMenu());
516
contextMenu()->popup(e->globalPos());
519
KSystemTray::mousePressEvent( e );
524
void Tray::slotDeactivateConnection(int index)
526
ConnectionSettings::Connection* conn = d->act_conn_map[index].first;
527
Device* dev = d->act_conn_map[index].second;
528
NMProxy* nm = NMProxy::getInstance();
531
nm->deactivateConnection(conn, dev);
534
void Tray::trayComponentNeedsCenterStage(TrayComponent *component, bool needsIt)
536
DeviceTrayComponent * dtc = dynamic_cast<DeviceTrayComponent*>(component);
538
kdDebug() << k_funcinfo << dtc->device()->getInterface() << " : " << needsIt << endl;
539
Device * device = dtc->device();
541
if (d->foregroundTrayComponent) {
542
disconnect(d->foregroundTrayComponent->device(), SIGNAL(StateChanged(NMDeviceState)), this, 0 );
544
d->foregroundTrayComponent = dtc;
545
connect(device, SIGNAL(StateChanged(NMDeviceState)),
546
SLOT(slotUpdateDeviceState(NMDeviceState)));
548
disconnect(device, SIGNAL(StateChanged(NMDeviceState)), this, 0 );
550
NMProxy* nm = NMProxy::getInstance();
551
device = nm->getDefaultDevice();
553
// identify the new foreground
554
for (QValueList<TrayComponent*>::Iterator it = d->trayComponents.begin(); it != d->trayComponents.end(); ++it)
556
DeviceTrayComponent* newDtc = dynamic_cast<DeviceTrayComponent*> (*it);
557
if ( newDtc && newDtc->device() == device ) {
558
d->foregroundTrayComponent = newDtc;
562
kdDebug() << " Device " << dtc->device()->getInterface() << " background, new foreground device: " << device->getInterface() << endl;
563
connect(device, SIGNAL(StateChanged(NMDeviceState)),
564
SLOT(slotUpdateDeviceState(NMDeviceState)));
565
slotUpdateDeviceState(device->getState());
571
void Tray::slotUpdateDeviceState(NMDeviceState state)
573
updateTrayIcon(state);
574
updateActiveConnection(state);
577
void Tray::trayUiChanged()
579
DeviceTrayComponent * dtc = d->foregroundTrayComponent;
581
updateTrayIcon(dtc->device()->getState());
584
void Tray::updateTrayIcon(NMDeviceState state)
586
// stop the old movie to avoid unnecessary wakups
587
DeviceTrayComponent * dtc = d->foregroundTrayComponent;
594
if (!dtc->movieForState(state).isNull())
599
frame = movie()->frameNumber();
602
setMovie(dtc->movieForState(state));
604
// start at the same frame as the movie before
606
movie()->step(frame);
608
// start the animation
611
else if (!dtc->pixmapForState(state).isNull())
612
setPixmap(dtc->pixmapForState(state));
614
setPixmap(loadIcon("knetworkmanager"));
617
setPixmap(loadIcon("knetworkmanager"));
620
void Tray::updateActiveConnection(NMDeviceState state)
622
if (state != NM_DEVICE_STATE_ACTIVATED)
625
NMProxy* nm = NMProxy::getInstance();
626
if (d->foregroundTrayComponent) {
627
Connection* active_conn = nm->getActiveConnection(d->foregroundTrayComponent->device());
630
Info* info = dynamic_cast<Info*>(active_conn->getSetting(NM_SETTING_CONNECTION_SETTING_NAME));
632
info->setTimestamp(QDateTime::currentDateTime());
637
void Tray::slotDeviceAddedNotify(Device* dev)
639
printf("Tray::slotDeviceAddedNotify\n");
640
KNotifyClient::event( winId(), "knm-nm-device-added", i18n("New network device %1 found").arg(dev->getInterface()) );
643
void Tray::slotDeviceRemovedNotify(Device* dev)
645
printf("Tray::slotDeviceRemovedNotify\n");
646
KNotifyClient::event( winId(), "knm-nm-device-removed", i18n("Network device %1 removed").arg(dev->getInterface()) );
649
void Tray::slotStateChangedNotify(Q_UINT32 state)
651
NMState nm_state = (NMState) state;
652
// change tray icon according to NM's state
655
case NM_STATE_CONNECTING:
656
KNotifyClient::event( winId(), "knm-nm-connecting", i18n("NetworkManager is connecting") );
658
case NM_STATE_DISCONNECTED:
659
KNotifyClient::event( winId(), "knm-nm-disconnected", i18n("NetworkManager is now disconnected") );
661
case NM_STATE_CONNECTED:
662
KNotifyClient::event( winId(), "knm-nm-connected", i18n("NetworkManager is now connected") );
664
case NM_STATE_ASLEEP:
665
KNotifyClient::event( winId(), "knm-nm-sleeping", i18n("KNetworkManager Offline") );
667
case NM_STATE_UNKNOWN:
674
void Tray::slotEditNotifications()
676
KNotifyDialog::configure(this);
679
Tray::Tray () : KSystemTray ()
681
d = new TrayPrivate(this);
683
connect(&d->signalMapper, SIGNAL(mapped(int)), this, SLOT(slotDeactivateConnection(int)));
685
setPixmap (loadIcon ("knetworkmanager"));
686
setMouseTracking (true);
688
// Actions used for plugging into the menu
689
new KAction (i18n ("Switch to offline mode"),
690
SmallIcon ("no", QIconSet::Automatic), 0,
691
this, SLOT (slotOfflineMode()), actionCollection (), "offline_mode");
693
new KAction (i18n ("Switch to online mode"),
694
SmallIcon ("ok", QIconSet::Automatic), 0,
695
this, SLOT (slotOnlineMode()), actionCollection (), "online_mode");
697
new KAction (i18n ("Disable Wireless"),
698
SmallIcon ("wireless_off", QIconSet::Automatic), 0,
699
this, SLOT (slotDisableWireless()), actionCollection (), "disable_wireless");
701
new KAction (i18n ("Enable Wireless"),
702
SmallIcon ("wireless", QIconSet::Automatic), 0,
703
this, SLOT (slotEnableWireless()), actionCollection (), "enable_wireless");
705
new KAction (i18n ("Edit Connections"),
706
SmallIcon ("edit", QIconSet::Automatic), 0,
707
this, SLOT (slotEditConnections()), actionCollection (), "edit_connections");
709
new KAction (i18n ("Configure Notifications"),
710
SmallIcon ("knotify", QIconSet::Automatic), 0,
711
this, SLOT (slotEditNotifications()), actionCollection (), "configure_notifications");
713
// this action is only connected when the menu is shown, hence the 0 receiver
714
new KAction (i18n ("New connection ..."),
715
SmallIcon ("filenew", QIconSet::Automatic), 0,
716
this, 0, actionCollection (), "new_connection");
718
new KActionMenu (i18n ("New connection ..."),
719
SmallIcon ("filenew", QIconSet::Automatic),
720
actionCollection(), "new_connection_menu");
722
new KActionMenu (i18n ("Deactivate connection..."),
723
SmallIcon ("no", QIconSet::Automatic),
724
actionCollection (), "deactivate_menu");
726
// get notified when NM's state changes
727
NMProxy* nm = NMProxy::getInstance();
728
connect(nm, SIGNAL(StateChange(Q_UINT32)), this, SLOT(slotStateChanged(Q_UINT32)));
730
// get notifier when NM requests new secrets
731
ConnectionStore* cstore = ConnectionStore::getInstance();
732
connect(cstore, SIGNAL(SecretsNeeded(ConnectionSettings::Connection*, ConnectionSettings::ConnectionSetting*, const QStringList&, bool)), this, SLOT(slotSecretsNeeded(ConnectionSettings::Connection*, ConnectionSettings::ConnectionSetting*, const QStringList&, bool)));
734
// get notified about new/removed devices
735
DeviceStore* store = DeviceStore::getInstance();
736
connect(store, SIGNAL(DeviceStoreChanged()), this, SLOT(updateDeviceTrays()));
737
connect(store, SIGNAL(DeviceAdded(Device*)), this, SLOT(slotAddDeviceTrayComponent(Device*)));
738
connect(store, SIGNAL(DeviceRemoved(Device*)), this, SLOT(slotRemoveDeviceTrayComponent(Device*)));
741
connect(store, SIGNAL(DeviceAdded(Device*)), this, SLOT(slotDeviceAddedNotify(Device*)));
742
connect(store, SIGNAL(DeviceRemoved(Device*)), this, SLOT(slotDeviceRemovedNotify(Device*)));
743
connect(nm, SIGNAL(StateChange(Q_UINT32)), this, SLOT(slotStateChangedNotify(Q_UINT32)));
746
// initial setup of the device-trays
750
slotStateChanged(nm->getState(err));
758
#include "knetworkmanager-tray.moc"