diff --git a/le-device-notifier/README b/le-device-notifier/README new file mode 100644 index 0000000000000000000000000000000000000000..a46f6d1c10cb510678f3501221239b835259fd41 --- /dev/null +++ b/le-device-notifier/README @@ -0,0 +1,15 @@ +Instructions to compile the source code: + +1. Download and install the following packages: +- cmake +- libphonon-dev +- build-essential +- libplasma-dev + +2. Create a folder called build and cd to: +mkdir build +cd build + +3. Compile using the commands: +cmake ../src +make diff --git a/le-device-notifier/VERSAO b/le-device-notifier/VERSAO new file mode 100644 index 0000000000000000000000000000000000000000..21e8796a09d4f26935ffc4879147879a153f0193 --- /dev/null +++ b/le-device-notifier/VERSAO @@ -0,0 +1 @@ +1.0.3 diff --git a/le-device-notifier/gerar.sh b/le-device-notifier/gerar.sh new file mode 100755 index 0000000000000000000000000000000000000000..1729c6830fc9b35895ea794550b1849935523105 --- /dev/null +++ b/le-device-notifier/gerar.sh @@ -0,0 +1,62 @@ +#!/bin/bash +# gerar.sh +# Copyright (c) 2006 by Bruno Ribas <ribas@ufpr.br> + +DIRTMP=$(mktemp -d) +VERSAO=$(cat VERSAO) + +#arrumar versao +#$1 tipo de incremento +MAJOR=$(echo $VERSAO| cut -d'.' -f1) +MINOR=$(echo $VERSAO| cut -d'.' -f2) +REVISION=$(echo $VERSAO| cut -d'.' -f3) + +case $1 in + Minor) + ((MINOR++)) + REVISION=0 + ;; + Major) + ((MAJOR++)) + MINOR=0 + REVISION=0 + ;; + help) + echo "Uso: $0 Major|Minor|Revision" + echo ' Major - Altera versao Major' + echo ' Minor - Altera versao Minor' + exit + ;; + *) + ((REVISION++)) + ;; +esac + +VERSAO="${MAJOR}.${MINOR}.${REVISION}" +echo "$VERSAO" > VERSAO + +#Compila a documentacao do pacote no diretorio doc/ +#cd doc/ +#hevea -text *.tex +#hevea -text *.tex +#cd ../ + +cp -r pacote $DIRTMP + +#Copia a documentacao compilada para dentro do pacote. +#cp doc/*.txt $DIRTMP/pacote/usr/share/doc/prd-* + +cd $DIRTMP +find . -name ".svn" -exec rm -rf {} \; &>/dev/null +sed -i -e "s/Version:/Version: $VERSAO/" pacote/DEBIAN/control + +fakeroot dpkg -b pacote . + +cd - + +cp $DIRTMP/*deb . +rm -rf $DIRTMP + + +# vim:tabstop=4:shiftwidth=4:encoding=iso-8859-1 + diff --git a/le-device-notifier/pacote/DEBIAN/control b/le-device-notifier/pacote/DEBIAN/control new file mode 100644 index 0000000000000000000000000000000000000000..c7c0512cae355946002d0e58b5a8da0bd982dfa7 --- /dev/null +++ b/le-device-notifier/pacote/DEBIAN/control @@ -0,0 +1,10 @@ +Package: le-device-notifier +Section: main +Priority: important +Version: +Architecture: i386 +Depends: le-interface | le-light-interface +Maintainer: LE Maintainer <le-maintainer@c3sl.ufpr.br> +Description: Device notifier for Linux Educacional + This is an adapted version of device-notifier-automount 0.4alpha1 + created by Achim Strobelt. diff --git a/le-device-notifier/pacote/DEBIAN/postinst b/le-device-notifier/pacote/DEBIAN/postinst new file mode 100755 index 0000000000000000000000000000000000000000..c39ac9ce8e8ad276120aeaf850332636464ee21a --- /dev/null +++ b/le-device-notifier/pacote/DEBIAN/postinst @@ -0,0 +1,25 @@ +#!/bin/bash +# +# Copyright (C) 2004-2011 Centro de Computacao Cientifica e Software Livre +# Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR +# +# This file is part of le-device-notifier +# +# le-device-notifier 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +# USA. + +APPLETSRC=/etc/skel/.kde/share/config/plasma-desktop-appletsrc + +sed -i s@"notifier"@"notifier_automount"@g ${APPLETSRC} diff --git a/le-device-notifier/pacote/DEBIAN/postrm b/le-device-notifier/pacote/DEBIAN/postrm new file mode 100755 index 0000000000000000000000000000000000000000..42de7338b0ee19e71efb0d2b5cbb918014908787 --- /dev/null +++ b/le-device-notifier/pacote/DEBIAN/postrm @@ -0,0 +1,38 @@ +#!/bin/bash +# +# Copyright (C) 2004-2011 Centro de Computacao Cientifica e Software Livre +# Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR +# +# This file is part of le-device-notifier +# +# le-device-notifier 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +# USA. + +# List of files to divert +divertList=" +/usr/lib/kde4/plasma_applet_devicenotifier.so \ +/usr/share/kde4/services/plasma-applet-devicenotifier.desktop \ +" + +# Divert files +if [[ "$1" != "upgrade" ]]; then + for file in $divertList; do + if test -e $file.real; then + rm -f $file + dpkg-divert --package le-device-notifier --remove --rename \ + --divert $file{.real,} + fi + done +fi diff --git a/le-device-notifier/pacote/DEBIAN/preinst b/le-device-notifier/pacote/DEBIAN/preinst new file mode 100755 index 0000000000000000000000000000000000000000..b91b3d5db57ac6be26f1f764341f622eece17048 --- /dev/null +++ b/le-device-notifier/pacote/DEBIAN/preinst @@ -0,0 +1,34 @@ +#!/bin/bash +# +# Copyright (C) 2004-2011 Centro de Computacao Cientifica e Software Livre +# Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR +# +# This file is part of le-device-notifier +# +# le-device-notifier 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +# USA. + +# List of files to divert +divertList=" +/usr/lib/kde4/plasma_applet_devicenotifier.so \ +/usr/share/kde4/services/plasma-applet-devicenotifier.desktop \ +" +# Divert files +for file in $divertList; do + if test -f $file; then + dpkg-divert --package le-device-notifier --add --rename \ + --divert $file{.real,} + fi +done diff --git a/le-device-notifier/pacote/usr/lib/kde4/plasma_applet_devicenotifier_automount.so b/le-device-notifier/pacote/usr/lib/kde4/plasma_applet_devicenotifier_automount.so new file mode 100755 index 0000000000000000000000000000000000000000..44d6930135ad0d0e1cb34b0e44aa8ea73deddb28 Binary files /dev/null and b/le-device-notifier/pacote/usr/lib/kde4/plasma_applet_devicenotifier_automount.so differ diff --git a/le-device-notifier/pacote/usr/share/kde4/services/plasma-applet-devicenotifier_automount.desktop b/le-device-notifier/pacote/usr/share/kde4/services/plasma-applet-devicenotifier_automount.desktop new file mode 100644 index 0000000000000000000000000000000000000000..587f00ef1105cc2e6ca6a42bc013844cf3a379c6 --- /dev/null +++ b/le-device-notifier/pacote/usr/share/kde4/services/plasma-applet-devicenotifier_automount.desktop @@ -0,0 +1,24 @@ +[Desktop Entry] +Name[en]=Device Notifier (Automount) +Name[de]=Geräteüberwachung (Automount) +Name=Notificador de Dispositivos (Montagem Automática) +Comment[en]=Notifications and access for new devices with automount +Comment[de]=Benachrichtigungen über neue Geräte und automatisches Einbinden +Comment=Notificação e acesso a novos dispositivos +Icon=device-notifier +Type=Service +X-KDE-ServiceTypes=Plasma/Applet + +X-KDE-Library=plasma_applet_devicenotifier_automount +X-KDE-PluginInfo-Author=Achim Strobelt +X-KDE-PluginInfo-Email=mail@achimstrobelt.de +X-KDE-PluginInfo-Name=notifier_automount +X-KDE-PluginInfo-Version=0.4alpha1 +X-KDE-PluginInfo-Website=http://www.kde-look.org/content/show.php?content=91517 +X-KDE-PluginInfo-Category=System Information +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=true + +X-Plasma-Requires-FileDialog=Unused +X-Plasma-Requires-LaunchApp=Required diff --git a/le-device-notifier/src/CMakeLists.txt b/le-device-notifier/src/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..0f2f5448934724191b72a3d7ed493346e7f168e4 --- /dev/null +++ b/le-device-notifier/src/CMakeLists.txt @@ -0,0 +1,31 @@ +# Devicenotifier Automount 0.4alpha1 +project(plasma-devicenotifier-automount) + +# Find the required Libaries +find_package(KDE4 REQUIRED) +include(KDE4Defaults) + +add_definitions (${QT_DEFINITIONS} ${KDE4_DEFINITIONS}) + +include_directories( + ${CMAKE_SOURCE_DIR} + ${CMAKE_BINARY_DIR} + ${KDE4_INCLUDES} + ) + +set(devicenotifier_automount_SRCS + devicenotifier_automount.cpp + notifierdialog_automount.cpp + notifierview_automount.cpp + automountGui_config.cpp + deviceoptions.cpp) + +kde4_add_ui_files(devicenotifier_automount_SRCS devicenotifier_automountConfig.ui ) +kde4_add_ui_files(devicenotifier_automount_SRCS devicenotifier_mountOptionsConfig.ui ) +kde4_add_ui_files(devicenotifier_automount_SRCS automountGui_configDialog.ui ) +kde4_add_plugin(plasma_applet_devicenotifier_automount ${devicenotifier_automount_SRCS} ) +target_link_libraries(plasma_applet_devicenotifier_automount ${KDE4_PLASMA_LIBS} ${KDE4_KIO_LIBS} ${KDE4_SOLID_LIBS}) + +install(TARGETS plasma_applet_devicenotifier_automount DESTINATION ${PLUGIN_INSTALL_DIR}) +install(FILES plasma-applet-devicenotifier_automount.desktop DESTINATION ${SERVICES_INSTALL_DIR}) +install(FILES automountoptionsrc DESTINATION ${CONFIG_INSTALL_DIR}) diff --git a/le-device-notifier/src/automountGui_config.cpp b/le-device-notifier/src/automountGui_config.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8b83ee9a729800bb1c6c8ee5cc3afe9643d553bc --- /dev/null +++ b/le-device-notifier/src/automountGui_config.cpp @@ -0,0 +1,157 @@ +/*************************************************************************** + * Copyright (C) 2009 by Achim Strobelt <mail@achimstrobelt.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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + ***************************************************************************/ + +#include <KLocale> +#include <KMessageBox> +#include <KDebug> + +// include the header file of the dialog +#include "automountGui_config.h" + +AutomountConfigDialog::AutomountConfigDialog( const QStringList& fsOptions, const QString& fs, QWidget *parent ) +: KDialog( parent ) +{ + QWidget *widget = new QWidget( this ); + + // create the user interface, the parent widget is "widget" + ui.setupUi(widget); // this is the important part + + // temmporary fsOptions + QStringList tempOptions = fsOptions; + + // set the widget with all its gui elements as the dialog's + // main widget + setMainWidget( widget ); + + // other KDialog options + setCaption( i18n("Mount options") + ": " + fs ); + setButtons( KDialog::Close | KDialog::Ok ); + + // setup controls + ui.standardOptions->setTitle(i18n("Standard options")); + ui.uidBox->setText(i18n("User ID")); + if (tempOptions.contains("setUid=true")) { + ui.uidBox->setCheckState(Qt::Checked); + tempOptions.removeAll("setUid=true"); + } else { + ui.uidBox->setCheckState(Qt::Unchecked); + } + ui.noexecBox->setText(i18n("Execute programs")); + if (tempOptions.contains("setNoexec=true")) + { + ui.noexecBox->setCheckState(Qt::Unchecked); + tempOptions.removeAll("setNoexec=true"); + } else { + ui.noexecBox->setCheckState(Qt::Checked); + } + + // Special options + ui.specialOptions->setTitle(i18n("Special options")); + ui.specialOptionsTable->clear(); + QStringList headerLabels; + headerLabels << i18n("Option") << i18n("Value"); + ui.specialOptionsTable->setHorizontalHeaderLabels(headerLabels); + ui.specialOptionsTable->setColumnCount(2); + ui.specialOptionsTable->setRowCount(tempOptions.count()); + int row = 0; + QTableWidgetItem *newItem; + foreach (const QString &option, tempOptions) { + kDebug() << option; + if (option.contains("=")) { + QStringList optionList = option.split("="); + newItem = new QTableWidgetItem(optionList.takeFirst()); + ui.specialOptionsTable->setItem(row, 0, newItem); + newItem = new QTableWidgetItem(optionList.takeFirst()); + ui.specialOptionsTable->setItem(row, 1, newItem); + } else { + newItem = new QTableWidgetItem(option); + ui.specialOptionsTable->setItem(row, 0, newItem); + } + row++; + } + connect(ui.specialOptionsTable, SIGNAL(currentCellChanged(int , int, int, int)), this, SLOT(specialOptionsCellChanged())); + + // Option buttons + ui.addOptionButton->setText(i18n("Add option")); + ui.addOptionButton->setIcon(KIcon("list-add")); + connect(ui.addOptionButton, SIGNAL(clicked()), this, SLOT(addNewOption())); + ui.removeOptionButton->setText(i18n("Remove option")); + ui.removeOptionButton->setIcon(KIcon("list-remove")); + ui.removeOptionButton->setEnabled(false); + connect(ui.removeOptionButton, SIGNAL(clicked()), this, SLOT(removeOption())); + +} + +AutomountConfigDialog::~AutomountConfigDialog(void) +{ +} + +void AutomountConfigDialog::addNewOption(void) +{ + kDebug() << "Add new option"; + int rowCount = ui.specialOptionsTable->rowCount(); + ui.specialOptionsTable->setRowCount(rowCount + 1); +} + +void AutomountConfigDialog::removeOption(void) +{ + kDebug() << "Remove option"; + if (ui.specialOptionsTable->currentRow() >= 0) { + ui.specialOptionsTable->removeRow(ui.specialOptionsTable->currentRow()); + } +} + +void AutomountConfigDialog::specialOptionsCellChanged(void) +{ + kDebug() << "Current cell changed"; + // After cell changed a cell is selected and the remove button can be enabled + ui.removeOptionButton->setEnabled(true); +} + +QStringList AutomountConfigDialog::getFsOptions(void) +{ + QStringList returnValue; + + // set UID? + kDebug() << "UID"; + if (ui.uidBox->checkState() == Qt::Checked) { + returnValue << "setUid=true"; + } + + // noexec? + kDebug() << "NoExec"; + if (ui.noexecBox->checkState() == Qt::Unchecked) { + returnValue << "setNoexec=true"; + } + + // read special Options + for (int row = 0; row < ui.specialOptionsTable->rowCount(); row++) { + if (ui.specialOptionsTable->item(row, 0) != 0) { + if (ui.specialOptionsTable->item(row, 1) != 0) { + returnValue << ui.specialOptionsTable->item(row, 0)->text() + "=" + ui.specialOptionsTable->item(row, 1)->text(); + } else { + returnValue << ui.specialOptionsTable->item(row, 0)->text(); + } + } + } + + return returnValue; +} + +#include "automountGui_config.moc" diff --git a/le-device-notifier/src/automountGui_config.h b/le-device-notifier/src/automountGui_config.h new file mode 100644 index 0000000000000000000000000000000000000000..78e3aeed3f17dca23e8f4a5e980be2abb5b06088 --- /dev/null +++ b/le-device-notifier/src/automountGui_config.h @@ -0,0 +1,50 @@ +/*************************************************************************** + * Copyright (C) 2009 by Achim Strobelt <mail@achimstrobelt.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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + ***************************************************************************/ + +#ifndef AUTOMOUNTGUI_CONFIG_H +#define AUTOMOUNTGUI_CONFIG_H + +#include <KDialog> + +// include the automatically generated header file for the ui-file +#include "ui_automountGui_configDialog.h" + +class AutomountConfigDialog : public KDialog +{ + Q_OBJECT + public: + AutomountConfigDialog( const QStringList& fsOptions, const QString& fs, QWidget *parent=0 ); + ~AutomountConfigDialog(void); + + QStringList getFsOptions(void); + + private slots: + void addNewOption(void); + void removeOption(void); + void specialOptionsCellChanged(void); + + private: + // accessor to the ui. we can access all gui elements + // specified in Designer. If mydialog.ui contains a + // button "myButton", we will be able to access it + // with ui.myButton in the cpp file. + Ui::automountGui_configDialog ui; +}; + +#endif diff --git a/le-device-notifier/src/automountGui_configDialog.ui b/le-device-notifier/src/automountGui_configDialog.ui new file mode 100644 index 0000000000000000000000000000000000000000..fd06312d4b93bab2a0bab57b114089d0c38e1f15 --- /dev/null +++ b/le-device-notifier/src/automountGui_configDialog.ui @@ -0,0 +1,101 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>automountGui_configDialog</class> + <widget class="QWidget" name="automountGui_configDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>490</width> + <height>536</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <property name="locale"> + <locale language="English" country="UnitedStates"/> + </property> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <item> + <widget class="QGroupBox" name="standardOptions"> + <property name="title"> + <string>standardOptions</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QCheckBox" name="uidBox"> + <property name="text"> + <string>uidBox</string> + </property> + <property name="checked"> + <bool>false</bool> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="noexecBox"> + <property name="text"> + <string>noexecBox</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="specialOptions"> + <property name="title"> + <string>specialOptions</string> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0" rowspan="3"> + <widget class="QTableWidget" name="specialOptionsTable"> + <property name="selectionMode"> + <enum>QAbstractItemView::SingleSelection</enum> + </property> + <property name="selectionBehavior"> + <enum>QAbstractItemView::SelectRows</enum> + </property> + <property name="columnCount"> + <number>2</number> + </property> + <column/> + <column/> + </widget> + </item> + <item row="0" column="1"> + <widget class="QPushButton" name="addOptionButton"> + <property name="text"> + <string>addOptionButton</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QPushButton" name="removeOptionButton"> + <property name="text"> + <string>removeOptionButton</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>42</width> + <height>354</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/le-device-notifier/src/automountoptionsrc b/le-device-notifier/src/automountoptionsrc new file mode 100644 index 0000000000000000000000000000000000000000..d2042bcb3f73e6d782186ce6943ff202adabecd2 --- /dev/null +++ b/le-device-notifier/src/automountoptionsrc @@ -0,0 +1,5 @@ +[Devices] +Filesystems=iso9660,vfat,udf +iso9660=setNoexec=true,mode=0444 +udf= +vfat=setUid=true,setNoexec=true,fmask=0133,dmask=0022 diff --git a/le-device-notifier/src/devicenotifier_automount.cpp b/le-device-notifier/src/devicenotifier_automount.cpp new file mode 100644 index 0000000000000000000000000000000000000000..425b3c9dd505020363993bb503bccef746361ecc --- /dev/null +++ b/le-device-notifier/src/devicenotifier_automount.cpp @@ -0,0 +1,482 @@ +/*************************************************************************** + * Copyright (C) 2007 by Alexis Ménard <darktears31@gmail.com> * + * Copyright (C) 2009 by Achim Strobelt <mail@achimstrobelt.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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + ***************************************************************************/ + +//own +#include "devicenotifier_automount.h" +#include "notifierview_automount.h" +#include "notifierdialog_automount.h" +#include "automountGui_config.h" + +//Qt +#include <QGraphicsLinearLayout> +#include <QGraphicsProxyWidget> +#include <QTimer> + +//KDE +#include <KIcon> +#include <KConfigDialog> +#include <KStandardDirs> +#include <KDesktopFile> +#include <kdesktopfileactions.h> +#include <KIconLoader> +#include <KMimeType> +#include <KService> +#include <KMimeTypeTrader> +#include <KMessageBox> +#include <KRun> +#include <KUrl> + +//plasma +#include <Plasma/Dialog> +//use for desktop view +#include <Plasma/IconWidget> +#include <Plasma/Theme> + +//solid +#include <solid/device.h> +#include <solid/storagedrive.h> +#include <solid/opticaldisc.h> +#include <solid/storageaccess.h> +#include <solid/opticaldrive.h> + +#include <QtDBus/QDBusInterface> +#include <QtDBus/QDBusReply> + +#include <unistd.h> + +using namespace Plasma; +using namespace Notifier; + +K_EXPORT_PLASMA_APPLET(devicenotifier, DeviceNotifier) + +DeviceNotifier::DeviceNotifier(QObject *parent, const QVariantList &args) + : Plasma::PopupApplet(parent, args), + m_solidEngine(0), + m_solidDeviceEngine(0), + m_icon(0), + m_iconName(""), + m_dialog(0), + m_numberItems(0), + m_itemsValidity(0) +{ + setBackgroundHints(StandardBackground); + setAspectRatioMode(IgnoreAspectRatio); + + setHasConfigurationInterface(true); + + // let's initialize the widget + (void)widget(); + + resize(widget()->sizeHint()); +} + +DeviceNotifier::~DeviceNotifier() +{ + delete m_icon; + delete m_dialog; +} + +void DeviceNotifier::createConfigurationInterface(KConfigDialog *parent) +{ + // General configuration + QWidget *confWidget = new QWidget(); + configUi.setupUi(confWidget); + parent->addPage(confWidget, i18n("General"), icon()); + + if (m_mountDevice) { + configUi.automountCheckbox->setCheckState(Qt::Checked); + } else { + configUi.automountCheckbox->setCheckState(Qt::Unchecked); + } + + // Mount options + QWidget *mountWidget = new QWidget(); + mountConfigUi.setupUi(mountWidget); + parent->addPage(mountWidget, i18n("Mount options"), "drive-harddisk"); + + // filesystem tab + mountConfigUi.tabWidget->setTabText(0, i18n("Filesystems")); + mountConfigUi.fsAddButton->setIcon(KIcon("list-add")); + mountConfigUi.fsAddButton->setText(i18n("Add filesystem")); + mountConfigUi.fsAddButton->setEnabled(false); + // add filesystems to list + mountConfigUi.fsAddList->clear(); + foreach (const QString &source, m_solidEngine->sources()) { + Solid::Device device = Solid::Device(source); + // Only storage volumes + if (device.is<Solid::StorageVolume>()) { + Solid::StorageVolume *sv = device.as<Solid::StorageVolume>(); + QString filesystem = sv->fsType(); + // Check if filesystem is in list and add it if necessary + if (mountConfigUi.fsAddList->findItems(filesystem, Qt::MatchExactly).isEmpty()) { + mountConfigUi.fsAddList->addItem(filesystem); + } + } + } + // Setup fsAddList + if (mountConfigUi.fsAddList->count() > 0) { + mountConfigUi.fsAddList->setCurrentRow(0); + mountConfigUi.fsAddButton->setEnabled(true); + } + // fsSaveList buttons + mountConfigUi.fsRemoveButton->setIcon(KIcon("list-remove")); + mountConfigUi.fsRemoveButton->setText(i18n("Remove filesystem")); + mountConfigUi.fsRemoveButton->setEnabled(false); + mountConfigUi.fsEditButton->setIcon(KIcon("document-edit")); + mountConfigUi.fsEditButton->setText(i18n("Edit options")); + mountConfigUi.fsEditButton->setEnabled(false); + // setup fsSaveList + foreach (const QString &fsSaved, m_deviceOptions.getFilesystems()) { + mountConfigUi.fsSaveList->addItem(fsSaved); + } + if (mountConfigUi.fsSaveList->count() > 0) { + mountConfigUi.fsEditButton->setEnabled(true); + mountConfigUi.fsRemoveButton->setEnabled(true); + } + if (mountConfigUi.fsSaveList->currentRow() == -1) { + mountConfigUi.fsSaveList->setCurrentRow(0); + } + // Connect signals + connect(parent, SIGNAL(applyClicked()), this, SLOT(configAccepted())); + connect(parent, SIGNAL(okClicked()), this, SLOT(configAccepted())); + connect(parent, SIGNAL(cancelClicked()), this, SLOT(configRejected())); + connect(mountConfigUi.fsAddButton, SIGNAL(clicked()), this, SLOT(mountOptionsFsAdded())); + connect(mountConfigUi.fsRemoveButton, SIGNAL(clicked()), this, SLOT(mountOptionsFsRemoved())); + connect(mountConfigUi.fsEditButton, SIGNAL(clicked()), this, SLOT(mountOptionsFsEdit())); +} + +void DeviceNotifier::mountOptionsFsAdded() +{ + QString filesystem = mountConfigUi.fsAddList->currentItem()->text(); + kDebug() << filesystem; + // Check if filesystem is in list and add it if necessary + if (mountConfigUi.fsSaveList->findItems(filesystem, Qt::MatchExactly).isEmpty()) { + mountConfigUi.fsSaveList->addItem(filesystem); + } + if (mountConfigUi.fsSaveList->count() > 0) { + mountConfigUi.fsEditButton->setEnabled(true); + mountConfigUi.fsRemoveButton->setEnabled(true); + } + if (mountConfigUi.fsSaveList->currentRow() == -1) { + mountConfigUi.fsSaveList->setCurrentRow(0); + } +} + +void DeviceNotifier::mountOptionsFsRemoved() +{ + kDebug() << "Remove"; + kDebug() << "Row: " << mountConfigUi.fsSaveList->currentRow(); + m_deviceOptions.removeFsOptions(mountConfigUi.fsSaveList->currentItem()->text()); + delete mountConfigUi.fsSaveList->currentItem(); + if (mountConfigUi.fsSaveList->count() == 0) { + mountConfigUi.fsRemoveButton->setEnabled(false); + mountConfigUi.fsEditButton->setEnabled(false); + } + +} + +void DeviceNotifier::mountOptionsFsEdit() +{ + kDebug() << "Edit"; + QString fs = mountConfigUi.fsSaveList->currentItem()->text(); + AutomountConfigDialog settingsDialog(m_deviceOptions.getFsOptions(fs), fs, NULL); + if (settingsDialog.exec() == QDialog::Accepted) { + kDebug() << "Read options from dialog"; + m_deviceOptions.setFsOptions(fs, settingsDialog.getFsOptions()); + kDebug() << "Mountoptions changed"; + } else { + kDebug() << "Mountoptions not changed"; + } +} + +void DeviceNotifier::configAccepted() +{ + KConfigGroup cg = config(); + + m_mountDevice = configUi.automountCheckbox->isChecked(); + cg.writeEntry("mountDevices", m_mountDevice); + emit configNeedsSaving(); + // Save automount options in own filePath + m_deviceOptions.saveOptions(); +} + +void DeviceNotifier::configRejected() +{ + kDebug() << "Cancel"; + // Workaraound + m_deviceOptions.loadOptions(); +} + +void DeviceNotifier::init() +{ + KConfigGroup cg = config(); + m_numberItems = cg.readEntry("NumberItems", 4); + m_itemsValidity = cg.readEntry("ItemsValidity", 5); + + m_solidEngine = dataEngine("hotplug"); + m_solidDeviceEngine = dataEngine("soliddevice"); + + m_icon = new Plasma::IconWidget(KIcon("device-notifier",NULL), QString()); + m_iconName = QString("device-notifier"); + + m_mountDevice = cg.readEntry("mountDevices", true); + + Plasma::ToolTipManager::self()->registerWidget(this); + + setPopupIcon(m_icon->icon()); + + //feed the list with what is already reported by the engine + + //connect to engine when a device is plug + connect(m_solidEngine, SIGNAL(sourceAdded(const QString&)), + this, SLOT(onSourceAdded(const QString&))); + connect(m_solidEngine, SIGNAL(sourceRemoved(const QString&)), + this, SLOT(onSourceRemoved(const QString&))); + + fillPreviousDevices(); +} + +QWidget *DeviceNotifier::widget() +{ + if (!m_dialog) { + m_dialog = new NotifierDialog(this); + connect(m_dialog, SIGNAL(itemSelected()), this, SLOT(hidePopup())); + } + + return m_dialog->dialog(); +} + +void DeviceNotifier::fillPreviousDevices() +{ + m_fillingPreviousDevices = true; + foreach (const QString &source, m_solidEngine->sources()) { + Solid::Device device = Solid::Device(source); + Solid::Device parentDevice = device.parent(); + Solid::StorageDrive *drive = parentDevice.as<Solid::StorageDrive>(); + if (drive && (drive->isHotpluggable() || drive->isRemovable())) { + onSourceAdded(source); + } + } + m_fillingPreviousDevices = false; +} + +void DeviceNotifier::changeNotifierIcon(const QString& name) +{ + if (m_icon && name.isNull()) { + m_icon->setIcon(m_iconName); + } else if (m_icon) { + m_icon->setIcon(name); + } + + setPopupIcon(m_icon->icon()); +} + +void DeviceNotifier::popupEvent(bool show) +{ + if (show) { + Plasma::ToolTipManager::self()->clearContent(this); + } +} + +void DeviceNotifier::dataUpdated(const QString &source, Plasma::DataEngine::Data data) +{ + if (data.size() > 0) { + //data from hotplug engine + if (!data["predicateFiles"].isNull()) { + int nb_actions = 0; + QString lastActionLabel; + foreach (const QString &desktop, data["predicateFiles"].toStringList()) { + QString filePath = KStandardDirs::locate("data", "solid/actions/" + desktop); + QList<KServiceAction> services = KDesktopFileActions::userDefinedServices(filePath, true); + nb_actions += services.size(); + if (services.size() > 0) { + bool serviceFound = false; + QString startOptions = getStartOptions(source); + for (int i = 0; i < services.size(); i++) { + if (startOptions == services[i].exec()) { + serviceFound = true; + kDebug() << "Service: " << startOptions; + lastActionLabel = services[i].text(); + kDebug() << services[i].name(); + } + } + if (!serviceFound) { + if (startOptions == "") { + if (nb_actions > 1) { + lastActionLabel = i18np("1 action for this device", + "%1 actions for this device", + nb_actions); + } else { + lastActionLabel = services[0].text(); + } + } else { + lastActionLabel = startOptions; + } + } + } + } + m_dialog->setDeviceData(source,data["predicateFiles"],NotifierDialog::PredicateFilesRole); + m_dialog->setDeviceData(source,data["text"], Qt::DisplayRole); + + //icon name + m_dialog->setDeviceData(source,data["icon"], NotifierDialog::IconNameRole); + //icon data + m_dialog->setDeviceData(source,KIcon(data["icon"].toString()), Qt::DecorationRole); + + // Todo: get standard action for device and desplay action + m_dialog->setDeviceData(source, lastActionLabel, NotifierDialog::ActionRole); + //data from soliddevice engine + } else { + kDebug() << "DeviceNotifier::solidDeviceEngine updated" << source; + if (data["Device Types"].toStringList().contains("Storage Access")) { + if (data["Accessible"].toBool() == true) { + m_dialog->setUnMount(true,source,false); + + //set icon to mounted device + QStringList overlays; + overlays << "emblem-mounted"; + m_dialog->setDeviceData(source, KIcon(m_dialog->getDeviceData(source,NotifierDialog::IconNameRole).toString(), NULL, overlays), Qt::DecorationRole); + } else if (data["Device Types"].toStringList().contains("OpticalDisc")) { + //Unmounted optical drive + m_dialog->setDeviceData(source, KIcon("media-eject"), Qt::DecorationRole); + //set icon to unmounted device + m_dialog->setUnMount(true,source,false); + m_dialog->setDeviceData(source, KIcon(m_dialog->getDeviceData(source,NotifierDialog::IconNameRole).toString()), Qt::DecorationRole); + } else { + m_dialog->setUnMount(false,source,false); + //set icon to unmounted device + m_dialog->setDeviceData(source, KIcon(m_dialog->getDeviceData(source,NotifierDialog::IconNameRole).toString()), Qt::DecorationRole); + } + } + // actions specific for other types of devices will go here + } + } +} + +void DeviceNotifier::notifyDevice(const QString &name) +{ + m_lastPlugged<<name; + + if (!m_fillingPreviousDevices) { + showPopup(); + } +} + +void DeviceNotifier::toolTipAboutToShow() +{ + Plasma::ToolTipContent toolTip; + if (!m_lastPlugged.isEmpty()) { + Solid::Device device(m_lastPlugged.last()); + + toolTip.setSubText(i18n("Last plugged in device: %1", device.product())); + toolTip.setImage(KIcon(device.icon())); + } else { + toolTip.setSubText(i18n("No devices plugged in")); + toolTip.setImage(KIcon("device-notifier")); + } + + Plasma::ToolTipManager::self()->setContent(this, toolTip); +} + +void DeviceNotifier::toolTipHidden() +{ + Plasma::ToolTipManager::self()->clearContent(this); +} + +void DeviceNotifier::removeLastDeviceNotification(const QString &name) +{ + m_lastPlugged.removeAll(name); +} + +void DeviceNotifier::onSourceAdded(const QString &name) +{ + kDebug() << "DeviceNotifier:: source added" << name; + if (m_dialog->countDevices() == m_numberItems && m_numberItems != 0) { + QString itemUdi = m_dialog->getDeviceUdi(m_dialog->countDevices() - 1); + //disconnect sources and after (important) remove the row + m_solidDeviceEngine->disconnectSource(itemUdi, this); + m_solidEngine->disconnectSource(itemUdi, this); + + m_dialog->removeDevice(m_dialog->countDevices() - 1); + } + + m_dialog->insertDevice(name); + notifyDevice(name); + + m_solidEngine->connectSource(name, this); + m_solidDeviceEngine->connectSource(name, this); + m_dialog->setUnMount(false,name,true); + // Mount device if necessary + mountDevice(name); +} + +void DeviceNotifier::mountDevice(const QString &name) +{ + if (m_mountDevice) { + Solid::Device device(name); + + // only storage volumes with filesystem + if ((device.is<Solid::StorageVolume>()) && device.is<Solid::StorageAccess>()) { + Solid::StorageVolume *sv = device.as<Solid::StorageVolume>(); + Solid::StorageAccess *sa = device.as<Solid::StorageAccess>(); + + // only unmounted devices + if (!sa->isAccessible()) { + // get filesystem + QString filesystem = sv->fsType(); + + // dbus-connection + QDBusConnection c = QDBusConnection::systemBus(); + QDBusMessage msg = QDBusMessage::createMethodCall("org.freedesktop.Hal", name, "org.freedesktop.Hal.Device.Volume", "Mount"); + QStringList options; + + // Get mount options for device + //options = getMountOptions(name); + options = m_deviceOptions.getMountOptions(name); + + // mount device + msg << "" << "" << options; + c.call(msg); + } + } + } + +} + +void DeviceNotifier::onSourceRemoved(const QString &name) +{ + m_solidEngine->disconnectSource(name, this); + m_solidDeviceEngine->disconnectSource(name, this); + + m_dialog->removeDevice(name); + removeLastDeviceNotification(name); +} + +QString DeviceNotifier::getStartOptions(const QString &udi) +{ + QString commandString = ""; + if (udi == "/org/freedesktop/Hal/devices/volume_uuid_4706_4E11") + { + commandString = "kioclient exec %f"; + } + return commandString; +} + +#include "devicenotifier_automount.moc" diff --git a/le-device-notifier/src/devicenotifier_automount.h b/le-device-notifier/src/devicenotifier_automount.h new file mode 100644 index 0000000000000000000000000000000000000000..9c7722b293e92b9b024d6bed8e36a08dbe2594d1 --- /dev/null +++ b/le-device-notifier/src/devicenotifier_automount.h @@ -0,0 +1,229 @@ +/*************************************************************************** + * Copyright (C) 2007 by Alexis Ménard <darktears31@gmail.com> * + * Copyright (C) 2009 by Achim Strobelt <mail@achimstrobelt.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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + ***************************************************************************/ + +#ifndef DEVICENOTIFIER_H +#define DEVICENOTIFIER_H + +//Solid +#include <solid/solidnamespace.h> + +//Plasma +#include <Plasma/PopupApplet> +#include <Plasma/DataEngine> +#include <Plasma/ToolTipManager> + +// User interface +#include "ui_devicenotifier_automountConfig.h" +#include "ui_devicenotifier_mountOptionsConfig.h" +#include "deviceoptions.h" + +class QStandardItemModel; +class QGraphicsLinearLayout; +class QGraphicsProxyWidget; +class QTimer; + +class KIcon; + +namespace Notifier +{ + class NotifierDialog; +} + +//desktop view +namespace Plasma +{ + class IconWidget; +} + +/** +* @short Applet used to display hot plug devices +* +*/ +class DeviceNotifier : public Plasma::PopupApplet +{ + Q_OBJECT + + public: + /** + * Constructor of the applet + * @param parent the parent of this object + **/ + DeviceNotifier(QObject *parent, const QVariantList &args); + + /** + * Default destructor + **/ + ~DeviceNotifier(); + + /** + * initialize the applet (called by plasma automatically) + **/ + void init(); + + /** + * allow to change the icon of the notifier if this applet is in icon mode + **/ + void changeNotifierIcon(const QString& name = QString()); + + /** + * The widget that displays the list of devices. + */ + QWidget *widget(); + + /** + * @internal get starting options for device + */ + QString getStartOptions(const QString &udi); + + /** + * @internal mount device + */ + void mountDevice(const QString &name); + + protected: + void popupEvent(bool show); + + /** + * Configuration interface + */ + void createConfigurationInterface(KConfigDialog *parent); + + public slots: + /** + * @internal Sets the tooltip content properly before showing. + */ + void toolTipAboutToShow(); + + /** + * @internal Clears memory when needed. + */ + void toolTipHidden(); + + protected slots: + /** + * slot called when a source/device is added in the hotplug engine + * @param name the name of the new source + **/ + void onSourceAdded(const QString &name); + + /** + * @internal slot called when a source/device is removed in the hotplug engine + * @param name the name of the removed source + **/ + void onSourceRemoved(const QString &name); + + /** + * slot called when a source of the hotplug engine is updated + * @param source the name of the source + * @param data the data of the source + **/ + void dataUpdated(const QString &source, Plasma::DataEngine::Data data); + + /** + * @internal slot called when the configuration dialog is accepted + **/ + void configAccepted(); + + /** + * @internal slot called when the configuration dialog is rejected + **/ + void configRejected(); + + /** + * @internal slot called when a filesystem is added to the mountoptions list + **/ + void mountOptionsFsAdded(); + + /** + * @internal slot called when a filesystem is removed from the mountoptions list + **/ + void mountOptionsFsRemoved(); + + /** + * @internal slot called when the configuration of a filesystem is called + **/ + void mountOptionsFsEdit(); + + + private: + /** + * @internal Used to fill the notifier from previous plugged devices + **/ + void fillPreviousDevices(); + + /** + * @internal Used to popup the device view. + */ + void notifyDevice(const QString &name); + + /** + * @internal Used to remove the last device notification. + */ + void removeLastDeviceNotification(const QString &name); + + /// Is automount enabled? + bool m_mountDevice; + + ///the engine used to get hot plug devices + Plasma::DataEngine *m_solidEngine; + + ///The engine used to manage devices in the applet (unmount,...) + Plasma::DataEngine *m_solidDeviceEngine; + + ///the icon used when the applet is in the taskbar + Plasma::IconWidget *m_icon; + + ///default icon of the notifier + QString m_iconName; + + ///The dialog where devices are displayed + Notifier::NotifierDialog * m_dialog; + + ///the time durin when the dialog will be show + int m_displayTime; + + ///the number of items displayed in the dialog + int m_numberItems; + + ///the time during when the item will be displayed + int m_itemsValidity; + + ///the timer for different use cases + QTimer *m_timer; + + ///bool to know if notifications are enabled + bool isNotificationEnabled; + + ///last plugged udi + QList<QString> m_lastPlugged; + + ///true if fillPreviousDevices is running + bool m_fillingPreviousDevices; + + /// Designer Config file + Ui::devicenotifierConfig configUi; + Ui::mountOptionsConfig mountConfigUi; + + ///device options + DeviceOptions m_deviceOptions; + +}; + +#endif diff --git a/le-device-notifier/src/devicenotifier_automountConfig.ui b/le-device-notifier/src/devicenotifier_automountConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..de0b08255b2249e2bda26152175e2d532e220550 --- /dev/null +++ b/le-device-notifier/src/devicenotifier_automountConfig.ui @@ -0,0 +1,40 @@ +<ui version="4.0" > + <class>devicenotifierConfig</class> + <widget class="QWidget" name="devicenotifierConfig" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>300</height> + </rect> + </property> + <property name="windowTitle" > + <string>Form</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout" > + <item> + <widget class="QCheckBox" name="automountCheckbox" > + <property name="text" > + <string>Mount devices automatically</string> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer" > + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0" > + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/le-device-notifier/src/devicenotifier_mountOptionsConfig.ui b/le-device-notifier/src/devicenotifier_mountOptionsConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..406b3c88528e6cf85d0e98f60feea8fdb960591c --- /dev/null +++ b/le-device-notifier/src/devicenotifier_mountOptionsConfig.ui @@ -0,0 +1,116 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>mountOptionsConfig</class> + <widget class="QWidget" name="mountOptionsConfig"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>482</width> + <height>562</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <property name="locale"> + <locale language="English" country="UnitedStates"/> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QTabWidget" name="tabWidget"> + <property name="currentIndex"> + <number>0</number> + </property> + <widget class="QWidget" name="fsTab"> + <attribute name="title"> + <string>fsTab</string> + </attribute> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0" rowspan="2"> + <widget class="QListWidget" name="fsAddList"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="MinimumExpanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="sortingEnabled"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QPushButton" name="fsAddButton"> + <property name="text"> + <string>fsAddButton</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <spacer name="verticalSpacer_2"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>209</height> + </size> + </property> + </spacer> + </item> + <item row="2" column="0" rowspan="3"> + <widget class="QListWidget" name="fsSaveList"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="MinimumExpanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="sortingEnabled"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QPushButton" name="fsRemoveButton"> + <property name="text"> + <string>fsRemoveButton</string> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="QPushButton" name="fsEditButton"> + <property name="text"> + <string>fsEditButton</string> + </property> + </widget> + </item> + <item row="4" column="1"> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <widget class="QWidget" name="devicesTab"> + <attribute name="title"> + <string>Devices</string> + </attribute> + </widget> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/le-device-notifier/src/deviceoptions.cpp b/le-device-notifier/src/deviceoptions.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8a9fa6b5488b8a89135d0a31deff64acb5d78d6d --- /dev/null +++ b/le-device-notifier/src/deviceoptions.cpp @@ -0,0 +1,174 @@ +/*************************************************************************** + * Copyright (C) 2009 by Achim Strobelt <mail@achimstrobelt.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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + ***************************************************************************/ + +#include "deviceoptions.h" +#include <KDebug> +#include <KConfig> +#include <KConfigGroup> + +//solid +#include <solid/device.h> +#include <solid/storagedrive.h> +#include <solid/opticaldisc.h> +#include <solid/storageaccess.h> +#include <solid/opticaldrive.h> + +// getuid +#include <unistd.h> + +DeviceOptions::DeviceOptions(void) +{ + loadOptions(); +} + +DeviceOptions::~DeviceOptions(void) +{ +} + +void DeviceOptions::setFsOptions(const QString& filesystem, const QStringList& fsOptions) +{ + kDebug() << "setFsOptions: " + filesystem; + // Check if filesystem already has settings + int index = -1; + for (int i = 0; i < fsSettings.size(); ++i) { + if (fsSettings.at(i).first() == filesystem) { + index = i; + } + } + + // Prepare settings to store + QStringList tempOptions = fsOptions; + tempOptions.prepend(filesystem); + + // Store settings + if (index >= 0) { + fsSettings.replace(index, tempOptions); + kDebug() << "Changed " + filesystem; + } else { + fsSettings.append(tempOptions); + kDebug() << "Added " + filesystem; + } +} + +void DeviceOptions::removeFsOptions(const QString& filesystem) +{ + kDebug() << "removeFsOptions: " + filesystem; + + int index = -1; + for (int i = 0; i < fsSettings.size(); ++i) { + if (fsSettings.at(i).first() == filesystem) { + index = i; + } + } + + // remove filesystem + fsSettings.removeAt(index); +} + +QStringList DeviceOptions::getFsOptions(const QString& filesystem) +{ + QStringList returnList; + + // search filesystem + for (int i = 0; i < fsSettings.size(); ++i) { + if (fsSettings.at(i).first() == filesystem) { + returnList = fsSettings.value(i); + returnList.removeFirst(); + } + } + return returnList; +} + +QStringList DeviceOptions::getMountOptions(const QString& udi) +{ + QStringList returnList; + + // get filesystem + QString filesystem; + Solid::Device device = Solid::Device(udi); + if (device.is<Solid::StorageVolume>()) { + Solid::StorageVolume *sv = device.as<Solid::StorageVolume>(); + filesystem = sv->fsType(); + } else { + filesystem = "ERROR_NO_STORAGE_DEVICE"; + kDebug() << filesystem; + } + + // search options for filesystem + for (int i = 0; i < fsSettings.size(); ++i) { + if (fsSettings.at(i).first() == filesystem) { + returnList = fsSettings.value(i); + returnList.removeFirst(); + } + } + + // TODO: search device specific options + + // process internal commands + if (returnList.contains("setUid=true")) { + returnList.removeAll("setUid=true"); + returnList << "uid=" + QString::number(getuid()); + } + if (returnList.contains("setNoexec=true")) { + returnList.removeAll("setNoexec=true"); + returnList << "noexec"; + } + + return returnList; +} + +void DeviceOptions::saveOptions(void) +{ + kDebug() << "Save options"; + KConfig config("automountoptionsrc"); + KConfigGroup deviceConfig = config.group("Devices"); + deviceConfig.writeEntry("Filesystems", getFilesystems()); + foreach (const QString &filesystem, getFilesystems()) { + deviceConfig.writeEntry(filesystem, getFsOptions(filesystem)); + } + config.sync(); +} + +void DeviceOptions::loadOptions(void) +{ + kDebug() << "Read Options"; + // Delete options + fsSettings.clear(); + // Read options + KConfig config("automountoptionsrc", KConfig::FullConfig); + KConfigGroup deviceConfig = config.group("Devices"); + QStringList filesystems = deviceConfig.readEntry("Filesystems", QStringList()); + foreach (const QString &filesystem, filesystems) { + QStringList fsOptions = deviceConfig.readEntry(filesystem, QStringList()); + setFsOptions(filesystem, fsOptions); + } +} + +QStringList DeviceOptions::getFilesystems(void) +{ + QStringList returnList; + // Get all filesystems + for (int i = 0; i < fsSettings.size(); ++i) { + returnList << fsSettings.at(i).first(); + } + + return returnList; +} + +#include "deviceoptions.moc" diff --git a/le-device-notifier/src/deviceoptions.h b/le-device-notifier/src/deviceoptions.h new file mode 100644 index 0000000000000000000000000000000000000000..434137a7ba7c78db6e4de724e5fdcb58afba6514 --- /dev/null +++ b/le-device-notifier/src/deviceoptions.h @@ -0,0 +1,86 @@ +/*************************************************************************** + * Copyright (C) 2009 by Achim Strobelt <mail@achimstrobelt.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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + ***************************************************************************/ + +#ifndef DEVICEOPTIONS_H +#define DEVICEOPTIONS_H + +#include <QObject> + +#include <KStandardDirs> + +class DeviceOptions : public QObject +{ + Q_OBJECT + + private: + QList<QStringList> fsSettings; + + public: + /** + * Constructor of the deviceoptions object + **/ + DeviceOptions(void); + + /** + * Default destructor + **/ + ~DeviceOptions(void); + + /** + * Get options for filesystem + * @param filesystem: get options for specific filesystem + **/ + QStringList getFsOptions(const QString& filesystem); + + /** + * Set options for filesystem + * @param filesystem: set options for specific filesystem + * @param fsOptions: new options + **/ + void setFsOptions(const QString& filesystem, const QStringList& fsOptions); + + /** + * Remove options for filesystem + * @param filesystem: filesystem to remove + **/ + void removeFsOptions(const QString& filesystem); + + /** + * Get mountoptions for device + * @param udi: device identifier + **/ + QStringList getMountOptions(const QString& udi); + + /** + * Save options + **/ + void saveOptions(void); + + /** + * Load options + **/ + void loadOptions(void); + + /** + * Get filesystems + **/ + QStringList getFilesystems(void); +}; + +#endif diff --git a/le-device-notifier/src/notifierdialog_automount.cpp b/le-device-notifier/src/notifierdialog_automount.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3edb21ef82c87ecacb6c5e30b38c88cd757bf0fc --- /dev/null +++ b/le-device-notifier/src/notifierdialog_automount.cpp @@ -0,0 +1,525 @@ +/******************************************************************************** +* Copyright 2008 by Alexis Ménard <darktears31@gmail.com> * +* Copyright (C) 2009 by Achim Strobelt <mail@achimstrobelt.de> * +* * +* * +* This library is free software; you can redistribute it and/or * +* modify it under the terms of the GNU Library General Public * +* License as published by the Free Software Foundation; either * +* version 2 of the License, or (at your option) any later version. * +* * +* This library 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 * +* Library General Public License for more details. * +* * +* You should have received a copy of the GNU Library General Public License * +* along with this library; see the file COPYING.LIB. If not, write to * +* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * +* Boston, MA 02110-1301, USA. * +********************************************************************************/ + +#include "notifierdialog_automount.h" +#include <stdio.h> +#include <stdlib.h> + + +//Qt +#include <QStandardItemModel> +#include <QModelIndex> +#include <QLabel> +#include <QVBoxLayout> +#include <QtDBus/QDBusInterface> +#include <QtDBus/QDBusReply> +#include <QHeaderView> +#include <QTimer> +#include <QMetaEnum> + +//KDE +#include <KDebug> +#include <KColorScheme> +#include <KIcon> +#include <KIconLoader> +#include <KGlobalSettings> +#include <KMessageBox> +#include <kdesktopfileactions.h> +#include <KNotification> + +//plasma +#include <Plasma/Dialog> +#include <Plasma/Delegate> +#include <Plasma/Theme> + +//solid +#include <solid/device.h> +#include <solid/opticaldisc.h> +#include <solid/storageaccess.h> +#include <solid/opticaldrive.h> +#include <solid/deviceinterface.h> + +//own +#include "notifierview_automount.h" +#include "devicenotifier_automount.h" + +using namespace Notifier; +using namespace Plasma; + +NotifierDialog::NotifierDialog(DeviceNotifier * notifier,QObject *parent) + : QObject(parent), + m_hotplugModel(0), + m_widget(0), + m_notifierView(0), + m_label(0), + m_notifier(notifier), + m_rootItem(0) +{ + m_hotplugModel = new QStandardItemModel(this); + buildDialog(); + //make the invisible root for tree device + m_rootItem = m_hotplugModel->invisibleRootItem(); +} + +NotifierDialog::~NotifierDialog() +{ + +} + +QWidget * NotifierDialog::dialog() +{ + return m_widget; +} + +void NotifierDialog::hide() +{ + m_widget->hide(); +} + +void NotifierDialog::show() +{ + m_widget->show(); +} + +QStandardItem* NotifierDialog::searchOrCreateDeviceCategory(const QString &categoryName) +{ + int rowCount = m_hotplugModel->rowCount(); + if(rowCount > 0) + { + int i = 0; + while (i<rowCount) + { + QModelIndex index = m_hotplugModel->index(i, 0); + QString itemUdi = m_hotplugModel->data(index, SolidUdiRole).toString(); + QStandardItem *currentItem = m_hotplugModel->itemFromIndex(index); + if(currentItem) + { + QString currentItemName = currentItem->text(); + if (currentItemName == categoryName) + { + //the category is find... we have to return the pointer on this category + return m_hotplugModel->itemFromIndex(index); + } + } + i++; + } + } + //insert a new category for device if not find and return the pointer + QStandardItem *newCategory = new QStandardItem(QString(categoryName)); + m_hotplugModel->setData(newCategory->index(),categoryName,Qt::DisplayRole); + m_rootItem->insertRow(0,newCategory); + m_hotplugModel->setItem(0, 1, NULL); + m_hotplugModel->setHeaderData(0, Qt::Horizontal,QString(""),Qt::EditRole); + m_hotplugModel->setHeaderData(1, Qt::Horizontal,QString(""),Qt::EditRole); + return newCategory; +} + +void NotifierDialog::insertDevice(const QString &name) +{ + QStandardItem *item = new QStandardItem(); + item->setData(name, SolidUdiRole); + item->setData(Plasma::Delegate::MainColumn, ScopeRole); + item->setData(false, SubTitleMandatoryRole); + + QStandardItem *actionItem = new QStandardItem(); + actionItem->setData(name, SolidUdiRole); + actionItem->setData(Plasma::Delegate::SecondaryActionColumn, ScopeRole); + + //search or create the category for inserted device + QString udi = item->data(SolidUdiRole).toString(); + if(!udi.isNull()) { + Solid::Device device(udi); + QString categoryOfInsertedDevice = getCategoryNameOfDevice(device); + QStandardItem *currentCategory = searchOrCreateDeviceCategory(categoryOfInsertedDevice); + if(currentCategory) + { + currentCategory->insertRow(0,item); + currentCategory->setChild(0, 1, actionItem); + } + else + { + delete item; + delete actionItem; + } + } + else + { + delete item; + delete actionItem; + } + + m_notifierView->calculateRects(); + +} + +// Display unmount icon +void NotifierDialog::setUnMount(bool unmount, const QString &name, bool cdrom) +{ + QModelIndex index = indexForUdi(name); + if (!index.isValid()) { + printf("Invalid index\n"); + return; + } + QStandardItem *currentItem = m_hotplugModel->itemFromIndex(index); + QStandardItem *childAction = currentItem->parent()->child(currentItem->row(), 1); + QVariant icon; + if (unmount) { + icon = KIcon("media-eject"); + } + else { + icon = KIcon(); + } + if (cdrom) { + if (system("ls -l /dev/disk/by-uuid/$(echo " + name.toAscii() + " | cut -d \"_\" -f3- | sed s@\"_\"@\"-\"@g) | grep sda")) { + this->itemClicked(index); + } + } + m_hotplugModel->setData(childAction->index(),icon,Qt::DecorationRole); +} + +void NotifierDialog::setDeviceData(const QString &name, QVariant data, int role) +{ + QModelIndex index = indexForUdi(name); + if (!index.isValid()) { + return; + } + if (role == Qt::DecorationRole) { + QStandardItem *device = m_hotplugModel->itemFromIndex(index); + QStandardItem *category = device->parent(); + QModelIndex parentIndex = category->index(); + if (!parentIndex.data(Qt::DecorationRole).isValid()) { + m_hotplugModel->setData(parentIndex,data,role); + } + } + m_hotplugModel->setData(index,data,role); +} + +QVariant NotifierDialog::getDeviceData(const QString &name, int role) +{ + QModelIndex index = indexForUdi(name); + if (!index.isValid()) { + return QVariant(); + } + else { + return index.data(role); + } +} + +void NotifierDialog::removeDevice(const QString &name) +{ + QModelIndex index = indexForUdi(name); + if (!index.isValid()) { + return; + } + + QStandardItem *device = m_hotplugModel->itemFromIndex(index); + QStandardItem *category = device->parent(); + + //removing device + category->removeRow(device->row()); + + //remove category if there's no devices into it + if (!category->hasChildren()) { + m_rootItem->removeRow(category->row()); + } + + m_notifierView->calculateRects(); +} + +void NotifierDialog::removeDevice(int index) +{ + m_hotplugModel->removeRow(index); + m_notifierView->calculateRects(); +} + +int NotifierDialog::countDevices() +{ + return m_hotplugModel->rowCount(); +} + +QString NotifierDialog::getDeviceUdi(int index) +{ + QModelIndex modelIndex = m_hotplugModel->index(index, 0); + return m_hotplugModel->data(modelIndex, SolidUdiRole).toString(); +} + +void NotifierDialog::buildDialog() +{ + m_widget = new QWidget(); + + QVBoxLayout *l_layout = new QVBoxLayout(m_widget); + l_layout->setSpacing(0); + l_layout->setMargin(0); + + m_label = new QLabel(m_widget); + updateColors(); + + QLabel *icon = new QLabel(m_widget); + icon->setPixmap(KIcon("emblem-mounted").pixmap(KIconLoader::SizeMedium, KIconLoader::SizeMedium)); + + QHBoxLayout *l_layout2 = new QHBoxLayout(m_widget); + l_layout2->setSpacing(0); + l_layout2->setMargin(0); + + l_layout2->addWidget(icon); + l_layout2->addWidget(m_label); + + l_layout2->setAlignment(Qt::AlignCenter); + + + m_notifierView = new NotifierView(m_widget); + m_notifierView->setModel(m_hotplugModel); + m_notifierView->setMinimumSize(150,300); + m_notifierView->setFocusPolicy(Qt::NoFocus); + + Plasma::Delegate *delegate = new Delegate(this); + //map the roles of m_hotplugModel into the standard Plasma::Delegate roles + delegate->setRoleMapping(Plasma::Delegate::SubTitleRole, ActionRole); + delegate->setRoleMapping(Plasma::Delegate::ColumnTypeRole, ScopeRole); + delegate->setRoleMapping(Plasma::Delegate::SubTitleMandatoryRole, SubTitleMandatoryRole); + m_notifierView->setItemDelegate(delegate); + + l_layout->addLayout(l_layout2); + l_layout->addWidget(m_notifierView); + m_widget->setLayout(l_layout); + + connect(m_notifierView, SIGNAL(clicked(const QModelIndex&)),this,SLOT(itemClicked(const QModelIndex&))); + + connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), this, SLOT(updateColors())); // allows updating of colors automatically +} + +void NotifierDialog::storageTeardownDone(Solid::ErrorType error, QVariant errorData) +{ + if (error && errorData.isValid()) { + QTimer::singleShot(0, this, SLOT(showTeardownError())); + } else { + m_notifier->changeNotifierIcon("dialog-ok"); + m_notifier->update(); + QTimer::singleShot(5000, this, SLOT(resetNotifierIcon())); + } + + //show the message only one time + disconnect(sender(), SIGNAL(teardownDone(Solid::ErrorType, QVariant, const QString &)), + this, SLOT(storageTeardownDone(Solid::ErrorType, QVariant))); +} + +void NotifierDialog::showTeardownError() +{ + //FIXME: modal dialog are bad m'kay + KMessageBox::error(0, i18n("Não foi possível desmontar o dispositivo.\nUm ou mais arquivos deste disco está sendo usado por um aplicativo."), QString()); +} + +void NotifierDialog::storageEjectDone(Solid::ErrorType error, QVariant errorData) +{ + if (error && errorData.isValid()) { + QTimer::singleShot(0, this, SLOT(showStorageEjectDoneError())); + } else { + m_notifier->changeNotifierIcon("dialog-ok"); + m_notifier->update(); + QTimer::singleShot(2000, this, SLOT(resetNotifierIcon())); + } + //show the message only one time + disconnect(sender(), SIGNAL(ejectDone(Solid::ErrorType, QVariant, const QString &)), + this, SLOT(storageEjectDone(Solid::ErrorType, QVariant))); +} + +void NotifierDialog::showStorageEjectDoneError() +{ + KMessageBox::error(0, i18n("Não foi possível ejetar o disco.\nUm ou mais arquivos deste disco está sendo usado por um aplicativo."), QString()); +} + +QModelIndex NotifierDialog::indexForUdi(const QString &udi) const +{ + int rowCount = m_hotplugModel->rowCount(); + for (int i=0; i < rowCount; ++i) { + QModelIndex index = m_hotplugModel->index(i, 0); + QStandardItem *currentItem = m_hotplugModel->itemFromIndex(index); + for (int j=0; j < currentItem->rowCount(); ++j) { + QStandardItem *childItem = currentItem->child(j, 0); + QString itemUdi = m_hotplugModel->data(childItem->index(), SolidUdiRole).toString(); + if (itemUdi == udi) { + return childItem->index(); + } + } + } + //Is it possible to go here?no... + kDebug() << "We should not be here!"; + return QModelIndex(); +} + +void NotifierDialog::itemClicked(const QModelIndex &index) +{ + QString udi = QString(m_hotplugModel->data(index, SolidUdiRole).toString()); + + //unmount (probably in the future different action types for different device types) + if (index.data(ScopeRole).toInt() == Plasma::Delegate::SecondaryActionColumn) { + Solid::Device device(udi); + + if (device.is<Solid::OpticalDisc>()) { + Solid::OpticalDrive *drive = device.parent().as<Solid::OpticalDrive>(); + if (drive!=0) { + connect(drive, SIGNAL(ejectDone(Solid::ErrorType, QVariant, const QString &)), + this, SLOT(storageEjectDone(Solid::ErrorType, QVariant))); + drive->eject(); + } + } else if (device.is<Solid::StorageVolume>()) { + Solid::StorageAccess *access = device.as<Solid::StorageAccess>(); + if (access && access->isAccessible()) { + connect(access, SIGNAL(teardownDone(Solid::ErrorType, QVariant, const QString &)),this, SLOT(storageTeardownDone(Solid::ErrorType, QVariant))); + access->teardown(); + } + } + //open (index.data(ScopeRole).toInt() == OpenAction) + } else { + QString startOptions = m_notifier->getStartOptions(udi); + bool serviceFound = false; + QStringList desktopFiles; + QString desktopFile; + if (startOptions != "") { + kDebug() << udi << ": " << startOptions; + desktopFiles = m_hotplugModel->data(index, PredicateFilesRole).toStringList(); + foreach (const QString &desktop, desktopFiles) { + QString filePath = KStandardDirs::locate("data", "solid/actions/" + desktop); + QList<KServiceAction> services = KDesktopFileActions::userDefinedServices(filePath, true); + if (services.size() > 0) { + for (int i = 0; i < services.size(); i++) { + if (startOptions == services[i].exec()) { + serviceFound = true; + // save service + desktopFile = desktop; + } + } + } + } + } + if (serviceFound) { + desktopFiles = QStringList(desktopFile); + kDebug() << desktopFile; + } else { + desktopFiles = m_hotplugModel->data(index, PredicateFilesRole).toStringList(); + } + + // Check if device is mounted + m_notifier->mountDevice(udi); + + kDebug() << "DeviceNotifier:: call Solid Ui Server with params :" << udi \ + << "," << desktopFiles; + QDBusInterface soliduiserver("org.kde.kded", "/modules/soliduiserver", "org.kde.SolidUiServer"); + QDBusReply<void> reply = soliduiserver.call("showActionsDialog", udi, desktopFiles); + } + emit itemSelected(); +} +void NotifierDialog::showPopupAuto(const QModelIndex &index){ + QString udi = QString(m_hotplugModel->data(index, SolidUdiRole).toString()); + + //unmount (probably in the future different action types for different device types) + if (index.data(ScopeRole).toInt() == Plasma::Delegate::SecondaryActionColumn) { + Solid::Device device(udi); + + if (device.is<Solid::OpticalDisc>()) { + Solid::OpticalDrive *drive = device.parent().as<Solid::OpticalDrive>(); + if (drive!=0) { + connect(drive, SIGNAL(ejectDone(Solid::ErrorType, QVariant, const QString &)), + this, SLOT(storageEjectDone(Solid::ErrorType, QVariant))); + drive->eject(); + } + } else if (device.is<Solid::StorageVolume>()) { + Solid::StorageAccess *access = device.as<Solid::StorageAccess>(); + if (access && access->isAccessible()) { + connect(access, SIGNAL(teardownDone(Solid::ErrorType, QVariant, const QString &)),this, SLOT(storageTeardownDone(Solid::ErrorType, QVariant))); + access->teardown(); + } + } + //open (index.data(ScopeRole).toInt() == OpenAction) + } else { + QString startOptions = m_notifier->getStartOptions(udi); + bool serviceFound = false; + QStringList desktopFiles; + QString desktopFile; + if (startOptions != "") { + kDebug() << udi << ": " << startOptions; + desktopFiles = m_hotplugModel->data(index, PredicateFilesRole).toStringList(); + foreach (const QString &desktop, desktopFiles) { + QString filePath = KStandardDirs::locate("data", "solid/actions/" + desktop); + QList<KServiceAction> services = KDesktopFileActions::userDefinedServices(filePath, true); + if (services.size() > 0) { + for (int i = 0; i < services.size(); i++) { + if (startOptions == services[i].exec()) { + serviceFound = true; + // save service + desktopFile = desktop; + } + } + } + } + } + if (serviceFound) { + desktopFiles = QStringList(desktopFile); + kDebug() << desktopFile; + } else { + desktopFiles = m_hotplugModel->data(index, PredicateFilesRole).toStringList(); + } + + // Check if device is mounted + m_notifier->mountDevice(udi); + + kDebug() << "DeviceNotifier:: call Solid Ui Server with params :" << udi \ + << "," << desktopFiles; + QDBusInterface soliduiserver("org.kde.kded", "/modules/soliduiserver", "org.kde.SolidUiServer"); + QDBusReply<void> reply = soliduiserver.call("showActionsDialog", udi, desktopFiles); + } + emit itemSelected(); +} + +QString NotifierDialog::getCategoryNameOfDevice(const Solid::Device& device) +{ + int index = Solid::DeviceInterface::staticMetaObject.indexOfEnumerator("Type"); + QMetaEnum typeEnum = Solid::DeviceInterface::staticMetaObject.enumerator(index); + for (int i = typeEnum.keyCount() - 1 ; i > 0; i--) + { + Solid::DeviceInterface::Type type = (Solid::DeviceInterface::Type)typeEnum.value(i); + const Solid::DeviceInterface *interface = device.asDeviceInterface(type); + if (interface) + { + // Todo: Translation? + return Solid::DeviceInterface::typeToString(type); + } + } + return 0; +} + +void NotifierDialog::resetNotifierIcon() +{ + m_notifier->changeNotifierIcon(); + m_notifier->update(); +} + +void NotifierDialog::updateColors() +{ + KColorScheme colorTheme = KColorScheme(QPalette::Active, KColorScheme::View,Plasma::Theme::defaultTheme()->colorScheme()); + m_label->setText(i18n("<font color=\"%1\">Dispositivos plugados recentemente:</font>",colorTheme.foreground(KColorScheme::NormalText).color().name())); + + QPalette p = m_widget->palette(); + p.setColor(QPalette::Window, Plasma::Theme::defaultTheme()->color(Plasma::Theme::BackgroundColor)); + m_widget->setPalette(p); +} + +#include "notifierdialog_automount.moc" diff --git a/le-device-notifier/src/notifierdialog_automount.h b/le-device-notifier/src/notifierdialog_automount.h new file mode 100644 index 0000000000000000000000000000000000000000..2c7191ee013e179dcd89ae9b4c3268d1046c32f7 --- /dev/null +++ b/le-device-notifier/src/notifierdialog_automount.h @@ -0,0 +1,244 @@ +/*************************************************************************** + * Copyright (C) 2008 by Alexis Ménard <darktears31@gmail.com> * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + ***************************************************************************/ + +#ifndef NOTIFIERDIALOG_H +#define NOTIFIERDIALOG_H + +//Qt +#include <QWidget> +#include <QStringList> + +//solid +#include <solid/solidnamespace.h> + + +//to remove +#include <QTreeView> + +class QModelIndex; +class QStandardItemModel; +class QStandardItem; +class QLabel; + +//own +class DeviceNotifier; + +//desktop view +namespace Plasma +{ + class Icon; + class Dialog; +} +namespace Solid +{ + class Device; +} +namespace Notifier +{ + class NotifierView; + + /** + * @short The panel used to display devices in a popup + * + */ + class NotifierDialog : public QObject + { + Q_OBJECT + + public: + + void showPopupAuto(const QModelIndex &index); + ///Specific role for the data-model + enum SpecificRoles { + SolidUdiRole = Qt::UserRole + 1, + PredicateFilesRole = Qt::UserRole + 2, + ActionRole = Qt::UserRole + 3, + IconNameRole = Qt::UserRole + 4, + ScopeRole = Qt::UserRole + 5, + SubTitleMandatoryRole = Qt::UserRole + 6 + }; + + /** + * Constructor of the dialog + * @param notifier the notifier attached to this dialog + * @param area where the dialog is displayed + * @param parent the parent of this object + **/ + NotifierDialog(DeviceNotifier * notifier,QObject *parent = 0); + + /** + * Default destructor + **/ + virtual ~NotifierDialog(); + + /** + * Returns the related QWidget. + **/ + QWidget * dialog(); + + /** + * Hide the dialog + **/ + void hide(); + + /** + * Show the dialog + **/ + void show(); + + /** + * insert a device in the data-model of the dialog + * @param name the name of the device + **/ + void insertDevice(const QString &name); + + void setUnMount(bool unmount,const QString &name,bool cdrom); + + /** + * Allow to set data which will be displayed by the view + * @param name the name of the device + * @param data the data + * @param role the role in the data-model + **/ + void setDeviceData(const QString &name, QVariant data, int role); + + /** + * Allow to get a data display by the view + * @param name the name of the device + * @param role the role where is the data + **/ + QVariant getDeviceData(const QString &name, int role); + + /** + * Remove a device in the dialog + * @param name the name of the device + **/ + void removeDevice(const QString &name); + + /** + * Remove a device in the view (provided by convenience) + * @param index the index where the data will be delete + **/ + void removeDevice(int index); + + /** + * Return the number of items displayed + * + **/ + int countDevices(); + + /** + * get the udi of a device displayed in the dialog + * @param index the index of the device + **/ + QString getDeviceUdi(int index); + + signals : + + void itemSelected(); + + private slots: + /** + * @internal called when a teardown error occurs + */ + void showTeardownError(); + + /** + * @internal called when an eject error occurs + */ + void showStorageEjectDoneError(); + + /** + * @internal slot called when user has click on a item in the dialog + * @param index the model index which is clicked + **/ + void itemClicked(const QModelIndex & index); + + /** + * @internal slot called when an eject is finished + * @param errorData the error if problem + * @param error type of error given by solid + **/ + void storageEjectDone(Solid::ErrorType error, QVariant errorData); + + /** + * @internal slot called when a storage tear is finished + * @param errorData the error if problem + * @param error type of error given by solid + **/ + void storageTeardownDone(Solid::ErrorType error, QVariant errorData); + + /** + * @internal slot called to restore to the notifier his icon + **/ + void resetNotifierIcon(); + + /** + * @internal update the color of the label to follow plasma theme + * + **/ + void updateColors(); + + + private : + /** + * @internal build the dialog depending where it is + **/ + void buildDialog(); + + /** + * @internal get the model index in the data-model by using the udi in parameter + * @param udi the udi used to find the model index + **/ + QModelIndex indexForUdi(const QString &udi) const; + + ///The data-model used to store devices + QStandardItemModel *m_hotplugModel; + + // The widget which display the panel + QWidget *m_widget; + ///The tree view used to display the content + NotifierView *m_notifierView; + + ///QLabel which represent the title + QLabel * m_label; + + ///The applet attached to this item + DeviceNotifier * m_notifier; + + ///Root item in treeview + QStandardItem *m_rootItem; + + /** + * @internal Search a category with same name. If not find, create a new category in top of treeview + * @param categoryName the name of the category for device + **/ + QStandardItem* searchOrCreateDeviceCategory(const QString &categoryName); + + /** + * @internal get The category name of a device plugged + * @param device the solid device plugged in hardware + **/ + QString getCategoryNameOfDevice(const Solid::Device& device); + }; + +} + +#endif + diff --git a/le-device-notifier/src/notifierview_automount.cpp b/le-device-notifier/src/notifierview_automount.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0d55638f6646a9c95cb9731ee8b969af9db4d4d8 --- /dev/null +++ b/le-device-notifier/src/notifierview_automount.cpp @@ -0,0 +1,290 @@ +/*************************************************************************** + * Copyright (C) 2007 by Alexis Ménard <darktears31@gmail.com> * + * Copyright (C) 2009 by Achim Strobelt <mail@achimstrobelt.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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + ***************************************************************************/ + +#include "notifierview_automount.h" + +// Qt + +#include <QtGui/QMouseEvent> +#include <QtGui/QPainter> +#include <QtGui/QPaintEvent> +#include <QtGui/QScrollBar> +#include <QtGui/QHeaderView> +#include <QtGui/QStandardItemModel> + +//KDE +#include <KDebug> +#include <KIconLoader> +#include <KColorScheme> +#include <KGlobalSettings> + +//Plasma +#include <Plasma/Delegate> +#include <Plasma/Theme> + +using namespace Notifier; + +NotifierView::NotifierView(QWidget *parent) + : QTreeView(parent) +{ + setIconSize(QSize(KIconLoader::SizeMedium, KIconLoader::SizeMedium)); + setRootIsDecorated(true); + setHeaderHidden(true); + setMouseTracking(true); + viewport()->setAutoFillBackground(true); + QPalette p(palette()); + p.setColor(QPalette::Base, Qt::transparent); + viewport()->setAttribute(Qt::WA_NoSystemBackground, true); + setPalette(p); + setFrameShape(QFrame::NoFrame); +} + +NotifierView::~NotifierView() +{ + +} + +QModelIndex NotifierView::indexAt(const QPoint& point) const +{ + // simple linear search through the item rects, this will + // be inefficient when the viewport is large + QHashIterator<QModelIndex,QRect> iter(itemRects); + while (iter.hasNext()) { + iter.next(); + if (iter.value().contains(point + QPoint(0, verticalOffset()))) { + return iter.key(); + } + } + return QModelIndex(); +} + +void NotifierView::resizeEvent(QResizeEvent * event) +{ + //the columns after the first are squares KIconLoader::SizeMedium x KIconLoader::SizeMedium, + //the first column takes all the remaining space + calculateRects(); + + if (header()->count() > 0) { + const int newWidth = event->size().width() - + (header()->count()-1)*(sizeHintForRow(0)); + header()->resizeSection(0, newWidth); + } +} + +void NotifierView::mouseMoveEvent(QMouseEvent *event) +{ + const QModelIndex itemUnderMouse = indexAt(event->pos()); + if (itemUnderMouse != m_hoveredIndex && itemUnderMouse.isValid() && + state() == NoState) { + update(); + m_hoveredIndex = itemUnderMouse; + setCurrentIndex(m_hoveredIndex); + } else if (!itemUnderMouse.isValid()) { + m_hoveredIndex = QModelIndex(); + setCurrentIndex(m_hoveredIndex); + } + + QAbstractItemView::mouseMoveEvent(event); +} + +void NotifierView::mousePressEvent(QMouseEvent *event) +{ + const QModelIndex itemUnderMouse = indexAt(event->pos()); + //don't pass click for header + if (event->button() != Qt::LeftButton || model()->hasChildren(itemUnderMouse)) { + return; + } + + QAbstractItemView::mousePressEvent(event); +} + +void NotifierView::mouseReleaseEvent(QMouseEvent *event) +{ + const QModelIndex itemUnderMouse = indexAt(event->pos()); + //don't pass click for header + if (event->button() != Qt::LeftButton || model()->hasChildren(itemUnderMouse)) { + return; + } + + QAbstractItemView::mouseReleaseEvent(event); +} + +void NotifierView::leaveEvent(QEvent *event) +{ + Q_UNUSED(event) + if (m_hoveredIndex.isValid()) { + const QModelIndex oldHoveredIndex = m_hoveredIndex; + m_hoveredIndex = QModelIndex(); + setCurrentIndex(m_hoveredIndex); + update(oldHoveredIndex); + } +} + +QModelIndex NotifierView::moveCursor(CursorAction cursorAction,Qt::KeyboardModifiers modifiers ) +{ + m_hoveredIndex = QModelIndex(); + + return QTreeView::moveCursor(cursorAction, modifiers ); +} + +void NotifierView::calculateRects() +{ + if (!model()) { + return; + } + + itemRects.clear(); + int verticalOffset = TOP_OFFSET; + + const int rows = model()->rowCount(rootIndex()); + const int cols = header()->count(); + kDebug() << "painting" << rows << "rows" << cols << "columns"; + + + for (int i = 0; i < rows; ++i) { + for (int j = 0; j < cols; ++j) { + const QModelIndex index = model()->index(i, j, rootIndex()); + if (model()->hasChildren(index)) { + QRect itemRect(QPoint(HEADER_LEFT_MARGIN, verticalOffset), + QSize(width() - HEADER_LEFT_MARGIN, HEADER_HEIGHT)); + verticalOffset += itemRect.size().height(); + itemRects.insert(index, itemRect); + + QStandardItemModel * currentModel = dynamic_cast<QStandardItemModel *>(model()); + QStandardItem *currentItem = currentModel->itemFromIndex(index); + // we display the children of this item + for (int k = 0; k < currentItem->rowCount(); ++k) { + for (int l = 0; l < currentItem->columnCount(); ++l) { + QStandardItem *childItem = currentItem->child(k, l); + + if (!childItem) { + continue; + } + QModelIndex childIndex = childItem->index(); + QRect itemChildRect; + if (l % 2 == 0) { + QSize size(width() - COLUMN_EJECT_SIZE, sizeHintForIndex(index).height()); + itemChildRect = QRect(QPoint(HEADER_LEFT_MARGIN, verticalOffset), size); + itemRects.insert(childIndex, itemChildRect); + } else { + QSize size(COLUMN_EJECT_SIZE - style()->pixelMetric(QStyle::PM_ScrollBarExtent) + 2, + sizeHintForIndex(index).height()); + itemChildRect = QRect(QPoint(width() - (COLUMN_EJECT_SIZE - COLUMN_EJECT_MARGIN ), + verticalOffset), size); + itemRects.insert(childIndex, itemChildRect); + verticalOffset += itemChildRect.size().height(); + } + } + } + } + } + } +} + +void NotifierView::paintEvent(QPaintEvent *event) +{ + Q_UNUSED(event); + if (!model()) { + return; + } + + QPainter painter(viewport()); + painter.setRenderHint(QPainter::Antialiasing); + + QHashIterator<QModelIndex, QRect> it(itemRects); + while (it.hasNext()) { + it.next(); + QRect itemRect = it.value(); + QRect rect(itemRect.x(), itemRect.y() - verticalOffset(), itemRect.width(), itemRect.height()); + if (event->region().contains(rect)) { + QModelIndex index = it.key(); + if (model()->hasChildren(index)) { + //kDebug()<<"header"<<rect; + paintHeaderItem(painter, rect, index); + } else { + paintItem(painter, rect, index); + } + } + } +} + +QRect NotifierView::visualRect(const QModelIndex &index) const +{ + return itemRects[index]; +} + +// device group headline (e.g. storage device, ...) +void NotifierView::paintHeaderItem(QPainter &painter, const QRect &itemRect, const QModelIndex &index) +{ + QStyleOptionViewItem option = viewOptions(); + option.rect = itemRect; + const int rightMargin = style()->pixelMetric(QStyle::PM_ScrollBarExtent) + 6; + const int dy = HEADER_TOP_MARGIN; + + painter.save(); + painter.setRenderHint(QPainter::Antialiasing, false); + + // Line over device groups + QLinearGradient gradient(option.rect.topLeft(), option.rect.topRight()); + gradient.setColorAt(0.0, Qt::transparent); + gradient.setColorAt(0.5, Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor)); + gradient.setColorAt(1.0, Qt::transparent); + painter.setPen(QPen(gradient, 1)); + + painter.drawLine(option.rect.x() + 6, option.rect.y() + dy + 2, + option.rect.right() - rightMargin , option.rect.y() + dy + 2); + + gradient.setColorAt(0.5, Plasma::Theme::defaultTheme()->color(Plasma::Theme::BackgroundColor)); + painter.setPen(QPen(gradient, 1)); + painter.drawLine(option.rect.x() + 6, option.rect.y() + dy + 3, + option.rect.right() - rightMargin , option.rect.y() + dy + 3); + + painter.setFont(KGlobalSettings::smallestReadableFont()); + QColor textColor = Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor); + textColor.setAlphaF(0.6); + painter.setPen(textColor); + // device group headline + QString text = index.data(Qt::DisplayRole).value<QString>(); + painter.drawText(option.rect.adjusted(0, dy, -rightMargin, 0), + Qt::AlignVCenter|Qt::AlignRight, text); + painter.restore(); +} + +void NotifierView::paintItem(QPainter &painter, const QRect &itemRect, const QModelIndex &index) +{ + QStyleOptionViewItem option = viewOptions(); + option.rect = itemRect; + + if (selectionModel()->isSelected(index)) { + option.state |= QStyle::State_Selected; + } + + if (index == m_hoveredIndex) { + option.state |= QStyle::State_MouseOver; + } + + if (index == currentIndex()) { + option.state |= QStyle::State_HasFocus; + } + + itemDelegate(index)->paint(&painter,option,index); +} + +#include "notifierview_automount.moc" diff --git a/le-device-notifier/src/notifierview_automount.h b/le-device-notifier/src/notifierview_automount.h new file mode 100644 index 0000000000000000000000000000000000000000..bdaa3f41e60702ab202aab9bbc42110f9025f60f --- /dev/null +++ b/le-device-notifier/src/notifierview_automount.h @@ -0,0 +1,138 @@ +/* Copyright 2007 by Alexis Ménard <darktears31@gmail.com> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#ifndef NOTIFIERVIEW_H +#define NOTIFIERVIEW_H + +// Qt +#include <QTreeView> + +class QModelIndex; + +namespace Notifier +{ + /** + * @short The view used to display information in a device popup + * + */ + class NotifierView : public QTreeView + { + Q_OBJECT + + public: + /** + * Constructor of view + * @param parent the parent of this object + **/ + NotifierView(QWidget *parent = 0); + + /** + * Default destructor + **/ + virtual ~NotifierView(); + + /** + * Creates rects in widget coordinates for the model + */ + void calculateRects(); + + /** + * Reimplemented from QTreeView + */ + QRect visualRect(const QModelIndex &index) const; + + protected: + /** + * Call when the view is resized + * @param event the resize event + **/ + void resizeEvent(QResizeEvent * event); + + /** + * Call when a mouse move event occurs + * @param event the mouse event + **/ + void mouseMoveEvent(QMouseEvent *event); + + /** + * Call when a mouse press event occurs + * @param event the mouse event + **/ + void mousePressEvent(QMouseEvent *event); + + /** + * Call when a mouse release event occurs + * @param event the mouse event + **/ + void mouseReleaseEvent(QMouseEvent *event); + + /** + * Call when cursor leave the widget + * @param event the leave event + **/ + void leaveEvent(QEvent *event); + + /** + * Move the cursor in the way describe by cursorAction + * @param cursorAction the cursor action + **/ + QModelIndex moveCursor(CursorAction cursorAction,Qt::KeyboardModifiers ); + + /** + * Call when the view is paint + * @param event the paint event + **/ + void paintEvent(QPaintEvent *event); + + /** + * Paint a header item + * @param painter the painter used to paint + * @param itemRect the rect where the item will be paint + * @param index the QModelIndex that represent the item to paint + **/ + void paintHeaderItem(QPainter &painter,const QRect &itemRect,const QModelIndex &index); + + /** + * Paint an item in the view by using the delegate + * @param painter the painter used to paint + * @param itemRect the rect where the item will be paint + * @param index the QModelIndex that represent the item to paint + **/ + void paintItem(QPainter &painter,const QRect &itemRect,const QModelIndex &index); + + /** + * Return an index at the position "point" if exist otherwise return a default + * constructed value of QModelIndex + * @param point the point where we will looking for an item + **/ + QModelIndex indexAt(const QPoint& point) const; + + static const int HEADER_LEFT_MARGIN = 5; + static const int HEADER_TOP_MARGIN = 5; + static const int HEADER_HEIGHT = 35; + static const int COLUMN_EJECT_MARGIN = 5; + static const int COLUMN_EJECT_SIZE = 50; + static const int TOP_OFFSET = 5; + + private: + ///The hovered index + QPersistentModelIndex m_hoveredIndex; + QHash<QModelIndex,QRect> itemRects; + }; + +} +#endif // NOTIFIERVIEW_H diff --git a/le-device-notifier/src/plasma-applet-devicenotifier_automount.desktop b/le-device-notifier/src/plasma-applet-devicenotifier_automount.desktop new file mode 100644 index 0000000000000000000000000000000000000000..587f00ef1105cc2e6ca6a42bc013844cf3a379c6 --- /dev/null +++ b/le-device-notifier/src/plasma-applet-devicenotifier_automount.desktop @@ -0,0 +1,24 @@ +[Desktop Entry] +Name[en]=Device Notifier (Automount) +Name[de]=Geräteüberwachung (Automount) +Name=Notificador de Dispositivos (Montagem Automática) +Comment[en]=Notifications and access for new devices with automount +Comment[de]=Benachrichtigungen über neue Geräte und automatisches Einbinden +Comment=Notificação e acesso a novos dispositivos +Icon=device-notifier +Type=Service +X-KDE-ServiceTypes=Plasma/Applet + +X-KDE-Library=plasma_applet_devicenotifier_automount +X-KDE-PluginInfo-Author=Achim Strobelt +X-KDE-PluginInfo-Email=mail@achimstrobelt.de +X-KDE-PluginInfo-Name=notifier_automount +X-KDE-PluginInfo-Version=0.4alpha1 +X-KDE-PluginInfo-Website=http://www.kde-look.org/content/show.php?content=91517 +X-KDE-PluginInfo-Category=System Information +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=true + +X-Plasma-Requires-FileDialog=Unused +X-Plasma-Requires-LaunchApp=Required