• Skip to content
  • Skip to link menu
KDE 4.1 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

Applets

devicenotifier.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (C) 2007 by Alexis Ménard <darktears31@gmail.com>           *
00003  *                                                                         *
00004  *   This program is free software; you can redistribute it and/or modify  *
00005  *   it under the terms of the GNU General Public License as published by  *
00006  *   the Free Software Foundation; either version 2 of the License, or     *
00007  *   (at your option) any later version.                                   *
00008  *                                                                         *
00009  *   This program is distributed in the hope that it will be useful,       *
00010  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00011  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00012  *   GNU General Public License for more details.                          *
00013  *                                                                         *
00014  *   You should have received a copy of the GNU General Public License     *
00015  *   along with this program; if not, write to the                         *
00016  *   Free Software Foundation, Inc.,                                       *
00017  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA .        *
00018  ***************************************************************************/
00019 
00020 #include "devicenotifier.h"
00021 #include "notifierview.h"
00022 
00023 #include <QPainter>
00024 #include <QColor>
00025 #include <QTreeView>
00026 #include <QApplication>
00027 #include <QStandardItemModel>
00028 #include <QGraphicsLinearLayout>
00029 #include <QtDBus/QDBusInterface>
00030 #include <QtDBus/QDBusReply>
00031 
00032 #include <KConfigDialog>
00033 #include <KMessageBox>
00034 #include <KRun>
00035 #include <KStandardDirs>
00036 #include <KDesktopFile>
00037 #include <kdesktopfileactions.h>
00038 #include <KGlobalSettings>
00039 #include <KColorScheme>
00040 
00041 #include <plasma/svg.h>
00042 #include <plasma/containment.h>
00043 #include <plasma/dialog.h>
00044 #include <plasma/animator.h>
00045 #include <plasma/delegate.h>
00046 
00047 //use for desktop view
00048 #include <plasma/widgets/icon.h>
00049 #include <plasma/theme.h>
00050 
00051 #include <solid/device.h>
00052 #include <solid/opticaldisc.h>
00053 #include <solid/storageaccess.h>
00054 #include <solid/opticaldrive.h>
00055 
00056 using namespace Plasma;
00057 using namespace Notifier;
00058 
00059 DeviceNotifier::DeviceNotifier(QObject *parent, const QVariantList &args)
00060     : Plasma::Applet(parent, args),
00061       m_solidEngine(0),
00062       m_hotplugModel(0),
00063       m_widget(0),
00064       m_icon(0),
00065       m_label(0),
00066       m_proxy(0),
00067       m_displayTime(0),
00068       m_numberItems(0),
00069       m_itemsValidity(0),
00070       m_timer(0)
00071 {
00072     setHasConfigurationInterface(true);
00073     int iconSize = IconSize(KIconLoader::Desktop);
00074     resize(iconSize, iconSize);
00075 }
00076 
00077 void DeviceNotifier::init()
00078 {
00079     KConfigGroup cg = config();
00080     m_timer = new QTimer();
00081     m_displayTime = cg.readEntry("TimeDisplayed", 8);
00082     m_numberItems = cg.readEntry("NumberItems", 4);
00083     m_itemsValidity = cg.readEntry("ItemsValidity", 5);
00084 
00085     //main layout, used both in desktop and panel mode
00086     m_layout = new QGraphicsLinearLayout(this);
00087     m_layout->setContentsMargins(0, 0, 0, 0);
00088     m_layout->setSpacing(0);
00089     setLayout(m_layout);
00090 
00091     m_solidEngine = dataEngine("hotplug");
00092     m_solidDeviceEngine = dataEngine("soliddevice");
00093     m_widget = new Dialog();
00094     m_widget->setFocusPolicy(Qt::NoFocus);
00095     m_widget->setWindowFlags(Qt::Popup);   
00096 
00097     QVBoxLayout *l_layout = new QVBoxLayout(m_widget);
00098     l_layout->setSpacing(0);
00099     l_layout->setMargin(0);
00100 
00101     m_hotplugModel = new QStandardItemModel(this);
00102 
00103     m_label = new QLabel(m_widget);
00104     updateColors();
00105     QLabel *icon = new QLabel(m_widget);
00106     icon->setPixmap(KIcon("emblem-mounted").pixmap(KIconLoader::SizeMedium, KIconLoader::SizeMedium));
00107 
00108     QHBoxLayout *l_layout2 = new QHBoxLayout(m_widget);
00109     l_layout2->setSpacing(0);
00110     l_layout2->setMargin(0);
00111 
00112     l_layout2->addWidget(icon);
00113     l_layout2->addWidget(m_label);
00114 
00115     m_notifierView= new NotifierView(m_widget);
00116     m_notifierView->setModel(m_hotplugModel);
00117     Plasma::Delegate *delegate = new Delegate(this);
00118     //map the roles of m_hotplugModel into the standard Plasma::Delegate roles
00119     delegate->setRoleMapping(Plasma::Delegate::SubTitleRole, ActionRole);
00120     delegate->setRoleMapping(Plasma::Delegate::ColumnTypeRole, ScopeRole);
00121     delegate->setRoleMapping(Plasma::Delegate::SubTitleMandatoryRole, SubTitleMandatoryRole);
00122     m_notifierView->setItemDelegate(delegate);
00123 
00124     l_layout->addLayout(l_layout2);
00125     l_layout->addWidget(m_notifierView);
00126     m_widget->setLayout(l_layout);
00127 
00128     m_widget->adjustSize();
00129 
00130     //feed the list with what is already reported by the engine
00131     isNotificationEnabled = false;
00132     foreach (const QString &source, m_solidEngine->sources()) {
00133         onSourceAdded(source);
00134     }
00135     isNotificationEnabled = true;
00136 
00137     //connect to engine when a device is plug
00138     connect(m_solidEngine, SIGNAL(sourceAdded(const QString&)),
00139             this, SLOT(onSourceAdded(const QString&)));
00140     connect(m_solidEngine, SIGNAL(sourceRemoved(const QString&)),
00141             this, SLOT(onSourceRemoved(const QString&)));
00142 
00143     connect(m_notifierView, SIGNAL(clicked(const QModelIndex&)), this, SLOT(slotOnItemClicked(const QModelIndex&)));
00144     connect(m_timer, SIGNAL(timeout()), this, SLOT(onTimerExpired()));
00145     connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), this, SLOT(updateColors()));    // allows updating of colors automatically
00146 }
00147 
00148 
00149 void DeviceNotifier::initSysTray()
00150 {
00151     if (m_icon) {
00152         return;
00153     }
00154 
00155     //we display the icon corresponding to the computer
00156     QList<Solid::Device> list = Solid::Device::allDevices();
00157 
00158     if (list.size() > 0) {
00159         Solid::Device device=list[0];
00160 
00161         while (device.parent().isValid()) {
00162             device = device.parent();
00163         }
00164         m_icon = new Plasma::Icon(KIcon(device.icon()), QString(), this);
00165     } else {
00166         //default icon if problem
00167         m_icon = new Plasma::Icon(KIcon("computer"), QString(), this);
00168     }
00169     connect(m_icon, SIGNAL(clicked()), this, SLOT(onClickNotifier()));
00170 
00171     setAspectRatioMode(Plasma::ConstrainedSquare);
00172 
00173     m_layout->addItem(m_icon);
00174 }
00175 
00176 DeviceNotifier::~DeviceNotifier()
00177 {
00178     delete m_widget;
00179     delete m_hotplugModel;
00180     delete m_timer;
00181 }
00182 
00183 void DeviceNotifier::constraintsEvent(Plasma::Constraints constraints)
00184 {
00185     // on the panel we don't want a background, and our proxy widget in Planar has one
00186     setBackgroundHints(NoBackground);
00187     bool isSizeConstrained = formFactor() != Plasma::Planar && formFactor() != Plasma::MediaCenter;
00188 
00189     if (constraints & FormFactorConstraint) {
00190         if (isSizeConstrained) {
00191             if (m_proxy) {
00192                 m_proxy->setWidget(0);
00193                 m_layout->removeItem(m_proxy);
00194                 delete m_proxy;
00195                 m_proxy = 0;
00196             }
00197 
00198             initSysTray();
00199         } else {
00200             delete m_icon;
00201             m_icon = 0;
00202 
00203             m_proxy = new QGraphicsProxyWidget(this);
00204             m_proxy->setWidget(m_widget);
00205             m_proxy->show();
00206             m_layout->addItem(m_proxy);
00207         }
00208     }
00209 
00210  }
00211 
00212 void DeviceNotifier::paintInterface(QPainter *p, const QStyleOptionGraphicsItem *option, const QRect &rect)
00213 {
00214     Applet::paintInterface(p,option,rect);
00215 }
00216 
00217 void DeviceNotifier::dataUpdated(const QString &source, Plasma::DataEngine::Data data)
00218 {
00219     if (data.size() > 0) {
00220         //data from hotplug engine
00221         if (!data["predicateFiles"].isNull()) {
00222             int nb_actions = 0;
00223             QString last_action_label;
00224             foreach (const QString &desktop, data["predicateFiles"].toStringList()) {
00225                 QString filePath = KStandardDirs::locate("data", "solid/actions/" + desktop);
00226                 QList<KServiceAction> services = KDesktopFileActions::userDefinedServices(filePath, true);
00227                 nb_actions += services.size();
00228                 if (services.size() > 0) {
00229                     last_action_label = QString(services[0].text());
00230                 }
00231             }
00232 
00233             QModelIndex index = indexForUdi(source);
00234 
00235             if (index.isValid()) {
00236                 m_hotplugModel->setData(index, data["predicateFiles"], PredicateFilesRole);
00237                 m_hotplugModel->setData(index, data["text"], Qt::DisplayRole);
00238 
00239                 //icon name
00240                 m_hotplugModel->setData(index, data["icon"], IconNameRole);
00241                 //icon data
00242                 m_hotplugModel->setData(index, KIcon(data["icon"].toString()), Qt::DecorationRole);
00243 
00244                 if (nb_actions > 1) {
00245                     QString s = i18np("1 action for this device",
00246                             "%1 actions for this device",
00247                             nb_actions);
00248                     m_hotplugModel->setData(index, s, ActionRole);
00249                 } else {
00250                     m_hotplugModel->setData(index,last_action_label, ActionRole);
00251                 }
00252                 if (m_icon && isNotificationEnabled) {
00253                     m_widget->move(popupPosition(m_widget->sizeHint()));
00254                     m_widget->show();
00255                     m_timer->start(m_displayTime*1000);
00256                 }
00257             }
00258             //data from soliddevice engine
00259         } else {
00260             kDebug() << "DeviceNotifier::solidDeviceEngine updated" << source;
00261             QModelIndex index = indexForUdi(source);
00262             if (index.isValid()) {
00263                 QModelIndex actionIndex = m_hotplugModel->index(index.row(), 1, QModelIndex());
00264 
00265                 if (data["Device Types"].toStringList().contains("Storage Access")) {
00266                     if (data["Accessible"].toBool() == true) {
00267                         m_hotplugModel->setData(actionIndex, KIcon("media-eject"), Qt::DecorationRole);
00268 
00269                         //set icon to mounted device
00270                         QStringList overlays;
00271                         overlays << "emblem-mounted";
00272                         m_hotplugModel->setData(index, KIcon(index.data(IconNameRole).toString(), NULL, overlays), Qt::DecorationRole);
00273                     //Unmounted optical drive
00274                     } else if (data["Device Types"].toStringList().contains("OpticalDisc")) {
00275                         m_hotplugModel->setData(actionIndex, KIcon("media-eject"), Qt::DecorationRole);
00276                         //set icon to unmounted device
00277                         m_hotplugModel->setData(index, KIcon(index.data(IconNameRole).toString()), Qt::DecorationRole);
00278                     } else {
00279                         m_hotplugModel->setData(actionIndex, KIcon(), Qt::DecorationRole);
00280 
00281                         //set icon to unmounted device
00282                         m_hotplugModel->setData(index, KIcon(index.data(IconNameRole).toString()), Qt::DecorationRole);
00283                     }
00284                 }
00285             }
00286             // actions specific for other types of devices will go here
00287         }
00288    }
00289 }
00290 
00291 void DeviceNotifier::onSourceAdded(const QString &name)
00292 {
00293     kDebug() << "DeviceNotifier:: source added" << name;
00294     if (m_hotplugModel->rowCount() == m_numberItems && m_numberItems != 0) {
00295         QModelIndex index = m_hotplugModel->index(m_hotplugModel->rowCount() - 1, 0);
00296         QString itemUdi = m_hotplugModel->data(index, SolidUdiRole).toString();
00297 
00298         //disconnect sources and after (important) remove the row
00299         m_solidDeviceEngine->disconnectSource(itemUdi, this);
00300         m_solidEngine->disconnectSource(itemUdi, this);
00301         m_hotplugModel->removeRow(m_hotplugModel->rowCount() - 1);
00302     }
00303     QStandardItem *item = new QStandardItem();
00304     item->setData(name, SolidUdiRole);
00305     item->setData(Plasma::Delegate::MainColumn, ScopeRole);
00306     item->setData(false, SubTitleMandatoryRole);
00307 
00308     m_hotplugModel->insertRow(0, item);
00309     m_solidEngine->connectSource(name, this);
00310 
00311     m_solidDeviceEngine->connectSource(name, this);
00312 
00313     //sets the "action" column
00314     QStandardItem *actionItem = new QStandardItem();
00315     actionItem->setData(name, SolidUdiRole);
00316     actionItem->setData(Plasma::Delegate::SecondaryActionColumn, ScopeRole);
00317 
00318     m_hotplugModel->setItem(0, 1, actionItem);
00319 
00320 }
00321 
00322 void DeviceNotifier::onSourceRemoved(const QString &name)
00323 {
00324     m_solidEngine->disconnectSource(name, this);
00325     m_solidDeviceEngine->disconnectSource(name, this);
00326 
00327     QModelIndex index = indexForUdi(name);
00328     if (index.isValid()) {
00329         m_hotplugModel->removeRow(index.row());
00330     }
00331 
00332     if (m_icon && m_hotplugModel->rowCount() == 0) {
00333         m_widget->hide();
00334     }
00335 }
00336 
00337 QModelIndex DeviceNotifier::indexForUdi(const QString &udi) const
00338 {
00339     int rowCount = m_hotplugModel->rowCount();
00340     for (int i=0; i < rowCount; ++i) {
00341         QModelIndex index = m_hotplugModel->index(i, 0);
00342         QString itemUdi = m_hotplugModel->data(index, SolidUdiRole).toString();
00343         if (itemUdi == udi) {
00344             return index;
00345         }
00346     }
00347     //Is it possible to go here?no...
00348     kDebug() << "We should not be here!";
00349     return QModelIndex();
00350 }
00351 
00352 void DeviceNotifier::onClickNotifier()
00353 {
00354     if (m_widget->isVisible()) {
00355         m_widget->hide();
00356     } else {
00357         m_widget->move(popupPosition(m_widget->sizeHint()));
00358         m_widget->show();
00359     }    
00360 }
00361 
00362 void DeviceNotifier::createConfigurationInterface(KConfigDialog *parent)
00363 {
00364     QWidget *widget = new QWidget;
00365     ui.setupUi(widget);
00366     parent->setButtons(KDialog::Ok | KDialog::Cancel | KDialog::Apply);
00367     connect(parent, SIGNAL(applyClicked()), this, SLOT(configAccepted()));
00368     connect(parent, SIGNAL(okClicked()), this, SLOT(configAccepted()));
00369     parent->addPage(widget, parent->windowTitle(), icon());
00370 
00371     ui.spinTime->setValue(m_displayTime);
00372     ui.spinItems->setValue(m_numberItems);
00373     ui.spinTimeItems->setValue(m_itemsValidity);
00374 }
00375 
00376 void DeviceNotifier::configAccepted()
00377 {
00378     kDebug() << "DeviceNotifier:: Config Accepted with params" << ui.spinTime->value() \
00379              << "," << ui.spinItems->value() \
00380              << "," << ui.spinTimeItems->value();
00381     m_displayTime = ui.spinTime->value();
00382     m_numberItems = ui.spinItems->value();
00383     m_itemsValidity = ui.spinTimeItems->value();
00384     KConfigGroup cg = config();
00385     cg.writeEntry("TimeDisplayed", m_displayTime);
00386     cg.writeEntry("NumberItems", m_numberItems);
00387     cg.writeEntry("ItemsValidity", m_itemsValidity);
00388     emit configNeedsSaving();
00389 }
00390 
00391 void DeviceNotifier::slotOnItemClicked(const QModelIndex &index)
00392 {
00393     kDebug() << index;
00394     if (m_icon) {
00395         m_timer->stop();
00396     }
00397 
00398     QString udi = QString(m_hotplugModel->data(index, SolidUdiRole).toString());
00399 
00400     //unmount (probably in the future different action types for different device types)
00401     if (index.data(ScopeRole).toInt() == Plasma::Delegate::SecondaryActionColumn) {
00402         Solid::Device device(udi);
00403 
00404         if (device.is<Solid::OpticalDisc>()) {
00405             Solid::OpticalDrive *drive = device.parent().as<Solid::OpticalDrive>();
00406 
00407             connect(drive, SIGNAL(ejectDone(Solid::ErrorType, QVariant, const QString &)),
00408                     this, SLOT(storageEjectDone(Solid::ErrorType, QVariant)));
00409             drive->eject();
00410         } else if (device.is<Solid::StorageVolume>()) {
00411             Solid::StorageAccess *access = device.as<Solid::StorageAccess>();
00412 
00413             if (access->isAccessible()) {
00414                 connect(access, SIGNAL(teardownDone(Solid::ErrorType, QVariant, const QString &)),
00415                     this, SLOT(storageTeardownDone(Solid::ErrorType, QVariant)));
00416                 access->teardown();
00417             }
00418         }
00419     //open  (index.data(ScopeRole).toInt() == OpenAction)
00420     } else {
00421         if (m_icon) {
00422           m_widget->hide();
00423         }
00424         QStringList desktop_files = m_hotplugModel->data(index, PredicateFilesRole).toStringList();
00425 
00426         kDebug() << "DeviceNotifier:: call Solid Ui Server with params :" << udi \
00427                 << "," << desktop_files;
00428         QDBusInterface soliduiserver("org.kde.kded", "/modules/soliduiserver", "org.kde.SolidUiServer");
00429         QDBusReply<void> reply = soliduiserver.call("showActionsDialog", udi, desktop_files);
00430     }
00431 }
00432 
00433 void DeviceNotifier::onTimerExpired()
00434 {
00435     if (m_icon) {
00436         m_timer->stop();
00437         m_widget->hide();
00438     }
00439 }
00440 
00441 void DeviceNotifier::storageTeardownDone(Solid::ErrorType error, QVariant errorData)
00442 {
00443     if (error && errorData.isValid()) {
00444         KMessageBox::error(0, i18n("Cannot unmount the device.\nOne or more files on this device are open within an application."), QString());
00445     } else if (m_icon) {
00446         m_icon->setIcon(KIcon("dialog-ok"));
00447         QTimer::singleShot(2000, this, SLOT(resetIcon()));
00448         update();
00449     }
00450 
00451     //show the message only one time
00452     disconnect(sender(), SIGNAL(teardownDone(Solid::ErrorType, QVariant, const QString &)),
00453                this, SLOT(storageTeardownDone(Solid::ErrorType, QVariant)));
00454 }
00455 
00456 void DeviceNotifier::storageEjectDone(Solid::ErrorType error, QVariant errorData)
00457 {
00458     if (error && errorData.isValid()) {
00459         KMessageBox::error(0, i18n("Cannot eject the disc.\nOne or more files on this disc are open within an application."), QString());
00460     } else if (m_icon) {
00461         m_icon->setIcon(KIcon("dialog-ok"));
00462         QTimer::singleShot(2000, this, SLOT(resetIcon()));
00463         update();
00464     }
00465 
00466     //show the message only one time
00467     disconnect(sender(), SIGNAL(ejectDone(Solid::ErrorType, QVariant, const QString &)),
00468                this, SLOT(storageEjectDone(Solid::ErrorType, QVariant)));
00469 }
00470 
00471 void DeviceNotifier::resetIcon()
00472 {
00473     if (m_icon) {
00474         //we display the icon corresponding to the computer
00475         QList<Solid::Device> list = Solid::Device::allDevices();
00476 
00477         if (list.size() > 0) {
00478             Solid::Device device=list[0];
00479 
00480             while (device.parent().isValid()) {
00481                 device = device.parent();
00482             }
00483             m_icon->setIcon(KIcon(device.icon()));
00484         } else {
00485             //default icon if problem
00486             m_icon->setIcon(KIcon("computer"));
00487         }
00488         update();
00489     }
00490 }
00491 
00492 void DeviceNotifier::updateColors()
00493 { 
00494     KColorScheme colorTheme = KColorScheme(QPalette::Active, KColorScheme::View, Plasma::Theme::defaultTheme()->colorScheme());
00495     m_label->setText(i18n("<font color=\"%1\">Devices recently plugged in:</font>",
00496                             colorTheme.foreground(KColorScheme::NormalText).color().name()));
00497 }
00498 
00499 #include "devicenotifier.moc"

Applets

Skip menu "Applets"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members

API Reference

Skip menu "API Reference"
  • KWin
  •   KWin Libraries
  • Libraries
  •   libkworkspace
  •   libplasma
  •   libsolidcontrol
  •   libtaskmanager
  • Plasma
  •   Animators
  •   Applets
  •   Engines
  • Solid Modules
Generated for API Reference by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal