public inbox for gentoo-commits@lists.gentoo.org
 help / color / mirror / Atom feed
* [gentoo-commits] dev/dilfridge:master commit in: kde-base/plasma-workspace/files/, kde-base/plasma-workspace/
@ 2013-10-09 12:02 Andreas Hüttel
  0 siblings, 0 replies; 2+ messages in thread
From: Andreas Hüttel @ 2013-10-09 12:02 UTC (permalink / raw
  To: gentoo-commits

commit:     bc6ae00719b0b577cc0814f167a55211fec65003
Author:     Andreas K. Huettel <dilfridge <AT> gentoo <DOT> org>
AuthorDate: Wed Oct  9 12:00:44 2013 +0000
Commit:     Andreas Hüttel <dilfridge <AT> gentoo <DOT> org>
CommitDate: Wed Oct  9 12:01:48 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=dev/dilfridge.git;a=commit;h=bc6ae007

[kde-base/plasma-workspace] add version with old notify code, to avoid crash bug
https://bugs.kde.org/show_bug.cgi?id=311871

---
 kde-base/plasma-workspace/Manifest                 |    1 +
 kde-base/plasma-workspace/files/oldnotify.patch    | 8557 ++++++++++++++++++++
 .../plasma-workspace-4.10.1-noplasmalock.patch     |   11 +
 kde-base/plasma-workspace/metadata.xml             |    9 +
 .../plasma-workspace-4.11.2-r2.ebuild              |  125 +
 5 files changed, 8703 insertions(+)

diff --git a/kde-base/plasma-workspace/Manifest b/kde-base/plasma-workspace/Manifest
new file mode 100644
index 0000000..48cd387
--- /dev/null
+++ b/kde-base/plasma-workspace/Manifest
@@ -0,0 +1 @@
+DIST kde-workspace-4.11.2.tar.xz 13870828 SHA256 260e46f30b8faaa1ad834d9fa69465ab1f565cb18a174bd814327083bb28d917 SHA512 8d034e147ebb630941465b77e302aa2385c2f1419847e8a65ac19d445846435b61d78323fdb094b9a71089ab183c96af141db93c7c9c53a9b30c84ae69bddf2a WHIRLPOOL 0db07ef64caf873c0aa6398a28b92fdc9334eb04897c9a71ed0e3c54ad77e9e8dc23b13b6343844650a2ec7c2784664185f01cf64424d694a8c33167affb5720

diff --git a/kde-base/plasma-workspace/files/oldnotify.patch b/kde-base/plasma-workspace/files/oldnotify.patch
new file mode 100644
index 0000000..c4c5c3b
--- /dev/null
+++ b/kde-base/plasma-workspace/files/oldnotify.patch
@@ -0,0 +1,8557 @@
+diff --git a/plasma/generic/applets/notifications/CMakeLists.txt b/plasma/generic/applets/notifications/CMakeLists.txt
+index 02afb93..a38fe47 100644
+--- a/plasma/generic/applets/notifications/CMakeLists.txt
++++ b/plasma/generic/applets/notifications/CMakeLists.txt
+@@ -1,2 +1,47 @@
+-installPackage(. org.kde.notifications)
++project(plasma-notifications)
++#TODO: see if is still the case
++# 'engineName' causes error
++kde4_no_enable_final(plasma-notifications)
+ 
++set(notifications_SRCS
++
++    core/notificationsmanager.cpp
++    core/protocol.cpp
++    core/notification.cpp
++    core/completedjobnotification.cpp
++    core/job.cpp
++
++    protocols/notifications/dbusnotificationprotocol.cpp
++    protocols/notifications/dbusnotification.cpp
++
++    protocols/jobs/dbusjobprotocol.cpp
++    protocols/jobs/dbusjob.cpp
++
++    ui/busywidget.cpp
++    ui/notifications.cpp
++    ui/notificationwidget.cpp
++    ui/jobtotalswidget.cpp
++    ui/jobwidget.cpp
++    ui/notificationgroup.cpp
++    ui/notificationstack.cpp
++    ui/stackdialog.cpp
++    )
++
++kde4_add_ui_files(notifications_SRCS
++                  ui/notificationsconfig.ui)
++
++
++include (CheckLibraryExists)
++check_library_exists (Xss XScreenSaverQueryInfo "" HAVE_LIBXSS)
++configure_file (${CMAKE_CURRENT_SOURCE_DIR}/config-notifications.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-notifications.h)
++IF (HAVE_LIBXSS)
++   SET (IDLE_DETECTION_LIB "Xss")
++ENDIF (HAVE_LIBXSS)
++
++
++kde4_add_plugin(plasma_applet_notifications ${notifications_SRCS})
++include_directories(${CMAKE_SOURCE_DIR})
++target_link_libraries(plasma_applet_notifications ${KDE4_KDEUI_LIBS} ${KDE4_PLASMA_LIBS} ${X11_LIBRARIES} ${X11_Xrender_LIB} ${X11_Xfixes_LIB} ${X11_Xdamage_LIB} ${X11_Xcomposite_LIB} ${KDE4_SOLID_LIBS} ${IDLE_DETECTION_LIB})
++
++install(TARGETS plasma_applet_notifications DESTINATION ${PLUGIN_INSTALL_DIR})
++install(FILES plasma-applet-notifications.desktop DESTINATION ${SERVICES_INSTALL_DIR})
+diff --git a/plasma/generic/applets/notifications/Messages.sh b/plasma/generic/applets/notifications/Messages.sh
+old mode 100644
+new mode 100755
+index bd3e2d9..5582bc6
+--- a/plasma/generic/applets/notifications/Messages.sh
++++ b/plasma/generic/applets/notifications/Messages.sh
+@@ -1,5 +1,4 @@
+ #! /usr/bin/env bash
+-$EXTRACTRC `find . -name \*.rc -o -name \*.ui -o -name \*.kcfg` >> rc.cpp
+-$XGETTEXT `find . -name \*.qml` -L Java -o $podir/plasma_applet_org.kde.notifications.pot
+-$XGETTEXT rc.cpp -jo $podir/plasma_applet_org.kde.notifications.pot
++$EXTRACTRC `find . -name '*.ui'` >> rc.cpp
++$XGETTEXT  `find . -name '*.cpp'` -o $podir/plasma_applet_notifications.pot
+ rm -f rc.cpp
+diff --git a/plasma/generic/applets/notifications/config-notifications.h.cmake b/plasma/generic/applets/notifications/config-notifications.h.cmake
+new file mode 100644
+index 0000000..aac3113
+--- /dev/null
++++ b/plasma/generic/applets/notifications/config-notifications.h.cmake
+@@ -0,0 +1 @@
++#cmakedefine HAVE_LIBXSS
+diff --git a/plasma/generic/applets/notifications/contents/config/main.xml b/plasma/generic/applets/notifications/contents/config/main.xml
+deleted file mode 100644
+index 399159d..0000000
+--- a/plasma/generic/applets/notifications/contents/config/main.xml
++++ /dev/null
+@@ -1,23 +0,0 @@
+-<?xml version="1.0" encoding="UTF-8"?>
+-<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
+-      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+-      xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
+-      http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
+-  <kcfgfile name=""/>
+-
+-  <group name="General">
+-    <entry name="CustomPosition" type="Point">
+-      <label>where the notification popup will be</label>
+-      <default>-1,-1</default>
+-    </entry>
+-    <entry name="ShowNotifications" type="Bool">
+-      <label>Show the notifications</label>
+-      <default>true</default>
+-    </entry>
+-    <entry name="ShowJobs" type="Bool">
+-      <label>Show the jobs progress</label>
+-      <default>true</default>
+-    </entry>
+-  </group>
+-
+-</kcfg>
+diff --git a/plasma/generic/applets/notifications/contents/ui/JobDelegate.qml b/plasma/generic/applets/notifications/contents/ui/JobDelegate.qml
+deleted file mode 100644
+index e94866d..0000000
+--- a/plasma/generic/applets/notifications/contents/ui/JobDelegate.qml
++++ /dev/null
+@@ -1,310 +0,0 @@
+-/*
+- *   Copyright 2011 Marco Martin <notmart@gmail.com>
+- *
+- *   This program 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, 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 Library General Public License for more details
+- *
+- *   You should have received a copy of the GNU Library 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.
+- */
+-
+-import QtQuick 1.0
+-import org.kde.plasma.core 0.1 as PlasmaCore
+-import org.kde.plasma.components 0.1 as PlasmaComponents
+-import org.kde.plasma.graphicswidgets 0.1 as PlasmaWidgets
+-import org.kde.qtextracomponents 0.1
+-
+-PlasmaComponents.ListItem {
+-    id: notificationItem
+-    width: popupFlickable.width
+-
+-    property int toolIconSize: theme.smallMediumIconSize
+-    property int layoutSpacing: 4
+-
+-    function getData(data, name, defaultValue) {
+-        return data[modelData] ? (data[modelData][name] ? data[modelData][name] : defaultValue) : defaultValue;
+-    }
+-
+-    property string labelName0: getData(jobsSource.data, "labelName0", '')
+-    property string label0: getData(jobsSource.data, "label0", '')
+-    property string labelName1: getData(jobsSource.data, "labelName1", '')
+-    property string label1: getData(jobsSource.data, "label1", '')
+-    property string jobstate: getData(jobsSource.data, "state", '')
+-    property int eta: getData(jobsSource.data, "eta", 0)
+-    property string speed: getData(jobsSource.data, "speed", '')
+-
+-    Column {
+-        spacing: notificationItem.layoutSpacing
+-        width: parent.width
+-        PlasmaComponents.Label {
+-            text: getData(jobsSource.data, "infoMessage", '')
+-            font.bold: true
+-            color: theme.textColor
+-            anchors.horizontalCenter: parent.horizontalCenter
+-        }
+-        Grid {
+-            anchors {
+-                left: parent.left
+-                right: parent.right
+-                rightMargin: notificationItem.layoutSpacing
+-            }
+-            spacing: notificationItem.layoutSpacing
+-            rows: 4
+-            columns: 2
+-
+-            PlasmaComponents.Label {
+-                id: labelName0Text
+-                text: labelName0 ? i18n("%1:", labelName0) : ''
+-                width: Math.max(paintedWidth, labelName1Text.paintedWidth)
+-                horizontalAlignment: Text.AlignRight
+-                visible: labelName0 != ''
+-            }
+-            PlasmaComponents.Label {
+-                id: label0Text
+-                text: label0 ? label0 : ''
+-                width: parent.width - labelName0Text.width
+-                elide: Text.ElideMiddle
+-                visible: label0 != ''
+-
+-                PlasmaCore.ToolTip {
+-                    target: label0Text
+-                    subText: label0Text.truncated ? label0 : ""
+-                }
+-
+-            }
+-            PlasmaComponents.Label {
+-                id: labelName1Text
+-                text: labelName1 ? i18n("%1:", labelName1) : ''
+-                width: Math.max(paintedWidth, labelName0Text.paintedWidth)
+-                horizontalAlignment: Text.AlignRight
+-                visible: labelName1 != ''
+-            }
+-            PlasmaComponents.Label {
+-                id: label1Text
+-                text: label1 ? label1 : ''
+-                width: parent.width - labelName0Text.width
+-                elide: Text.ElideMiddle
+-                visible: label1 != ''
+-
+-                PlasmaCore.ToolTip {
+-                    target: label1Text
+-                    subText: label1Text.truncated ? label1 : ""
+-                }
+-            }
+-            QIconItem {
+-                icon: getData(jobsSource.data, "appIconName", '')
+-                width: notificationItem.toolIconSize
+-                height: width
+-                anchors {
+-                    verticalCenter: progressItem.verticalCenter
+-                    right: progressItem.left
+-                    rightMargin: notificationItem.layoutSpacing
+-                }
+-            }
+-            Item {
+-                id: progressItem
+-                width: parent.width - labelName0Text.width
+-                height: childrenRect.height
+-                PlasmaComponents.ProgressBar {
+-                    width: parent.width - pauseButton.width*2 - theme.largeIconSize - notificationItem.layoutSpacing*3
+-                    height: 16
+-                    orientation: Qt.Horizontal
+-                    minimumValue: 0
+-                    maximumValue: 100
+-                    //percentage doesn't always exist, so doesn't get in the model
+-                    value: getData(jobsSource.data, "percentage", 0)
+-
+-                    anchors {
+-                        left: parent.left
+-                        right: buttonsRow.left
+-                        verticalCenter: parent.verticalCenter
+-                        rightMargin: notificationItem.layoutSpacing
+-                    }
+-                }
+-                Row {
+-                    id: buttonsRow
+-                    spacing: notificationItem.layoutSpacing
+-                    anchors.right: parent.right
+-                    PlasmaComponents.ToolButton {
+-                        id: pauseButton
+-                        width: notificationItem.toolIconSize
+-                        height: width
+-                        iconSource: jobstate == "suspended" ? "media-playback-start" : "media-playback-pause"
+-                        flat: false
+-                        onClicked: {
+-                            var operationName = "suspend"
+-                            if (jobstate == "suspended") {
+-                                operationName = "resume"
+-                            }
+-                            var service = jobsSource.serviceForSource(modelData)
+-                            var operation = service.operationDescription(operationName)
+-                            service.startOperationCall(operation)
+-                        }
+-                    }
+-                    PlasmaComponents.ToolButton {
+-                        id: stopButton
+-                        width: notificationItem.toolIconSize
+-                        height: width
+-                        iconSource: "media-playback-stop"
+-                        flat: false
+-                        onClicked: {
+-                            var service = jobsSource.serviceForSource(modelData)
+-                            var operation = service.operationDescription("stop")
+-                            service.startOperationCall(operation)
+-                        }
+-                    }
+-                }
+-            }
+-            PlasmaComponents.ToolButton {
+-                id: expandButton
+-                width: notificationItem.toolIconSize
+-                height: width
+-                flat: false
+-                iconSource: checked ? "list-remove" : "list-add"
+-                checkable: true
+-                anchors {
+-                    right: speedLabel.left
+-                    rightMargin: notificationItem.layoutSpacing
+-                    verticalCenter: speedLabel.verticalCenter
+-                }
+-            }
+-            PlasmaComponents.Label {
+-                id: speedLabel
+-                text: eta > 0 ? i18nc("Speed and estimated time to completition", "%1 (%2 remaining)", speed, locale.prettyFormatDuration(eta)) : speed
+-            }
+-        }
+-
+-
+-        Item {
+-            id: detailsItem
+-            state: expandButton.checked ? "expanded" : "collapsed"
+-            anchors {
+-                left: parent.left
+-                right: parent.right
+-                leftMargin: speedLabel.x
+-            }
+-            property Item contentsItem
+-            Component {
+-                id: detailsComponent
+-                Column {
+-                    id: detailsColumn
+-                    anchors {
+-                        left: parent.left
+-                        right: parent.right
+-                    }
+-
+-                    function localizeProcessedAmount(id) {
+-                        //if bytes localise the unit
+-                        if (jobsSource.data[modelData]["processedUnit"+id] == "bytes") {
+-                            return i18nc("How much many bytes (or whether unit in the locale has been copied over total", "%1 of %2",
+-                                    locale.formatByteSize(jobsSource.data[modelData]["processedAmount"+id]),
+-                                    locale.formatByteSize(jobsSource.data[modelData]["totalAmount"+id]))
+-                        //else print something only if is interesting data (ie more than one file/directory etc to copy
+-                        } else if (jobsSource.data[modelData]["totalAmount"+id] > 1) {
+-                            return i18n( "%1 of %2 %3",
+-                                    jobsSource.data[modelData]["processedAmount"+id],
+-                                    jobsSource.data[modelData]["totalAmount"+id],
+-                                    jobsSource.data[modelData]["processedUnit"+id])
+-                        } else {
+-                            return ""
+-                        }
+-                    }
+-                    PlasmaComponents.Label {
+-                        text: jobsSource.data[modelData] ? detailsColumn.localizeProcessedAmount(0) : ""
+-                        anchors.left: parent.left
+-                        visible: text != ""
+-                    }
+-                    PlasmaComponents.Label {
+-                        text: jobsSource.data[modelData] ? detailsColumn.localizeProcessedAmount(1) : ""
+-                        anchors.left: parent.left
+-                        visible: text != ""
+-                    }
+-                    PlasmaComponents.Label {
+-                        text: jobsSource.data[modelData] ? detailsColumn.localizeProcessedAmount(2) : ""
+-                        anchors.left: parent.left
+-                        visible: text != ""
+-                    }
+-                    PlasmaWidgets.SignalPlotter {
+-                        id: plotter
+-                        width: parent.width
+-                        useAutoRange: true
+-                        showVerticalLines: false
+-                        unit: i18n("KiB/s")
+-                        height: theme.defaultFont.mSize.height * 5
+-                        Component.onCompleted: plotter.addPlot(theme.highlightColor)
+-                    }
+-                    Connections {
+-                        target: jobsSource
+-                        onDataChanged: {
+-                            plotter.addSample([jobsSource.data[modelData]["numericSpeed"]/1000])
+-                        }
+-                    }
+-                }
+-            }
+-
+-            states: [
+-                State {
+-                    name: "expanded"
+-                    PropertyChanges {
+-                        target: detailsItem
+-                        height: detailsItem.childrenRect.height
+-                    }
+-                },
+-                State {
+-                    name: "collapsed"
+-                    PropertyChanges {
+-                        target: detailsItem
+-                        height: 0
+-                    }
+-                }
+-            ]
+-            transitions : [
+-                Transition {
+-                    from: "collapsed"
+-                    to: "expanded"
+-                    SequentialAnimation {
+-                        ScriptAction {
+-                            script: {
+-                                detailsItem.visible = true
+-                                detailsItem.clip = true
+-                                //create the contents if they don't exist yet
+-                                if (!detailsItem.contentsItem) {
+-                                    detailsItem.contentsItem = detailsComponent.createObject(detailsItem)
+-                                }
+-                            }
+-                        }
+-                        NumberAnimation {
+-                            duration: 250
+-                            properties: "height"
+-                            easing: PropertyAnimation.EaseInOut
+-                        }
+-                        ScriptAction {script: detailsItem.clip = false}
+-                    }
+-                },
+-                Transition {
+-                    from: "expanded"
+-                    to: "collapsed"
+-                    SequentialAnimation {
+-                        ScriptAction {script: detailsItem.clip = true}
+-                        NumberAnimation {
+-                            duration: 250
+-                            properties: "height"
+-                            easing: PropertyAnimation.EaseInOut
+-                        }
+-                        //TODO: delete the details?
+-                        ScriptAction {script: detailsItem.visible = false}
+-                    }
+-                }
+-            ]
+-        }
+-    }
+-}
+diff --git a/plasma/generic/applets/notifications/contents/ui/Jobs.qml b/plasma/generic/applets/notifications/contents/ui/Jobs.qml
+deleted file mode 100644
+index 7e2f2a2..0000000
+--- a/plasma/generic/applets/notifications/contents/ui/Jobs.qml
++++ /dev/null
+@@ -1,105 +0,0 @@
+-/*
+- *   Copyright 2012 Marco Martin <notmart@gmail.com>
+- *
+- *   This program 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, 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 Library General Public License for more details
+- *
+- *   You should have received a copy of the GNU Library 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.
+- */
+-
+-import QtQuick 1.1
+-import org.kde.plasma.core 0.1 as PlasmaCore
+-import org.kde.plasma.components 0.1 as PlasmaComponents
+-
+-Column {
+-    id: jobsRoot
+-    property alias count: jobsRepeater.count
+-    anchors {
+-        left: parent.left
+-        right: parent.right
+-    }
+-
+-    PlasmaCore.DataSource {
+-        id: jobsSource
+-        engine: "applicationjobs"
+-        interval: 0
+-
+-        onSourceAdded: {
+-            connectSource(source);
+-        }
+-        property variant runningJobs
+-
+-        onSourceRemoved: {
+-            if (!notifications) {
+-                return
+-            }
+-            var message = runningJobs[source]["label1"] ? runningJobs[source]["label1"] : runningJobs[source]["label0"]
+-            notifications.addNotification(
+-                source,
+-                runningJobs[source]["appIconName"],
+-                0,
+-                runningJobs[source]["appName"],
+-                i18n("%1 [Finished]", runningJobs[source]["infoMessage"]),
+-                message,
+-                0,
+-                0,
+-                [{"id": message, "text": i18n("Open")}])
+-            delete runningJobs[source]
+-        }
+-        Component.onCompleted: {
+-            jobsSource.runningJobs = new Object
+-            connectedSources = sources
+-        }
+-        onNewData: {
+-            var jobs = runningJobs
+-            jobs[sourceName] = data
+-            runningJobs = jobs
+-        }
+-        onDataChanged: {
+-            var total = 0
+-            for (var i = 0; i < sources.length; ++i) {
+-                if (jobsSource.data[sources[i]]["percentage"]) {
+-                    total += jobsSource.data[sources[i]]["percentage"]
+-                }
+-            }
+-
+-            total /= sources.length
+-            notificationsApplet.globalProgress = total/100
+-        }
+-    }
+-
+-    Title {
+-        visible: jobsRepeater.count > 0 && notifications && notifications.count > 0
+-        text: i18n("Transfers")
+-    }
+-    PlasmaComponents.ListItem {
+-        visible: jobsRepeater.count > 1
+-        PlasmaComponents.ProgressBar {
+-            anchors {
+-                verticalCenter: parent.verticalCenter
+-                left: parent.left
+-                right: parent.right
+-            }
+-            minimumValue: 0
+-            maximumValue: 100
+-            value: notificationsApplet.globalProgress * 100
+-        }
+-    }
+-    Repeater {
+-        id: jobsRepeater
+-        model: jobsSource.sources
+-        delegate: JobDelegate {
+-            toolIconSize: notificationsApplet.toolIconSize
+-        }
+-    }
+-}
+\ No newline at end of file
+diff --git a/plasma/generic/applets/notifications/contents/ui/LastNotificationPopup.qml b/plasma/generic/applets/notifications/contents/ui/LastNotificationPopup.qml
+deleted file mode 100644
+index 26bce0f..0000000
+--- a/plasma/generic/applets/notifications/contents/ui/LastNotificationPopup.qml
++++ /dev/null
+@@ -1,414 +0,0 @@
+-/***************************************************************************
+- *   Copyright 2011 Davide Bettio <davide.bettio@kdemail.net>              *
+- *   Copyright 2011 Marco Martin <mart@kde.org>                            *
+- *                                                                         *
+- *   This program 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 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 Library General Public License for more details.                          *
+- *                                                                         *
+- *   You should have received a copy of the GNU Library 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 .        *
+- ***************************************************************************/
+-
+-import QtQuick 1.1
+-import org.kde.plasma.core 0.1 as PlasmaCore
+-import org.kde.plasma.components 0.1 as PlasmaComponents
+-import org.kde.qtextracomponents 0.1
+-import org.kde.plasma.extras 0.1 as PlasmaExtras
+-
+-
+-PlasmaCore.Dialog {
+-    id: lastNotificationPopup
+-
+-    property variant savedPos
+-    property bool customPosition: false
+-
+-    onHeightChanged:  setCustomPosition(lastNotificationPopup.savedPos, false)
+-    onWidthChanged:   setCustomPosition(lastNotificationPopup.savedPos, false)
+-
+-    function popup(notification)
+-    {
+-        if (!lastNotificationPopup.visible) {
+-            lastNotificationsModel.clear()
+-        }
+-        lastNotificationsModel.append(notification)
+-
+-        setCustomPosition(lastNotificationPopup.savedPos, false)
+-
+-        lastNotificationPopup.visible = true
+-        lastNotificationTimer.interval = Math.max(4000, Math.min(60*1000, notificationsModel.get(0).expireTimeout))
+-        notificationsView.currentIndex = lastNotificationsModel.count - 1
+-        lastNotificationTimer.restart()
+-        mainItem.buttonPressed = false
+-    }
+-
+-    function setCustomPosition(pos, writeConfig)
+-    {
+-        var popupPos = lastNotificationPopup.popupPosition(notificationIcon, Qt.AlignCenter)
+-        var finalPos
+-
+-        //custom
+-        if ((pos.x >= 0 || pos.y >= 0) &&
+-            (Math.abs(popupPos.x - pos.x) > 40 ||
+-            Math.abs(popupPos.y - pos.y) > 40)) {
+-            finalPos = pos
+-            if (writeConfig) {
+-                plasmoid.writeConfig("CustomPosition", pos)
+-                lastNotificationPopup.savedPos = pos
+-                lastNotificationPopup.customPosition = true
+-            }
+-        } else {
+-            finalPos = popupPos
+-            if (writeConfig) {
+-                plasmoid.writeConfig("CustomPosition", QPoint(-1,-1))
+-                lastNotificationPopup.savedPos = QPoint(-1,-1)
+-                lastNotificationPopup.customPosition = false
+-            }
+-        }
+-        lastNotificationPopup.x = finalPos.x
+-        lastNotificationPopup.y = finalPos.y
+-    }
+-
+-    location: customPosition ? Floating : plasmoid.location
+-    windowFlags: Qt.WindowStaysOnTopHint
+-    Component.onCompleted: {
+-        setAttribute(Qt.WA_X11NetWmWindowTypeDock, true)
+-
+-        lastNotificationPopup.savedPos = plasmoid.readConfig("CustomPosition")
+-        setCustomPosition(lastNotificationPopup.savedPos, true)
+-        plasmoid.popupEvent.connect(lastNotificationPopup.popupEvent)
+-    }
+-
+-    function popupEvent(popupShowing)
+-    {
+-        if(popupShowing) {
+-           lastNotificationPopup.visible = false
+-        }
+-    }
+-
+-    mainItem: MouseEventListener {
+-        id: mainItem
+-        width: maximumWidth
+-        height: maximumHeight
+-        property int maximumWidth: theme.defaultFont.mSize.width * 35
+-        property int maximumHeight: theme.defaultFont.mSize.width * 10
+-        property int minimumWidth: maximumWidth
+-        property int minimumHeight: maximumHeight
+-
+-        property int startX: 0
+-        property int startY: 0
+-        property int startScreenX: 0
+-        property int startScreenY: 0
+-        hoverEnabled: true
+-        property bool buttonPressed: false
+-
+-        state: "controlsHidden"
+-        onContainsMouseChanged: {
+-            if (containsMouse) {
+-                mainItem.state = "controlsShown"
+-                lastNotificationTimer.running = false
+-            } else {
+-                mainItem.state = "controlsHidden"
+-                lastNotificationTimer.restart()
+-            }
+-        }
+-        onPressed: {
+-            startX = mouse.x + lastNotificationPopup.margins.left
+-            startY = mouse.y + lastNotificationPopup.margins.top
+-            startScreenX = mouse.screenX
+-            startScreenY = mouse.screenY
+-            lastNotificationTimer.running = false
+-        }
+-        onReleased: {
+-            //FIXME: bind startdragdistance
+-            if ((navigationButtonsColumn.visible && mouse.x < navigationButtonsColumn.width) ||
+-                buttonPressed ||
+-                Math.sqrt(Math.pow(startScreenX - mouse.screenX, 2) + Math.pow(startScreenY - mouse.screenY, 2)) > 4) {
+-            } else {
+-                lastNotificationPopup.visible = false
+-            }
+-
+-            setCustomPosition(QPoint(Math.max(0, mouse.screenX - startX), Math.max(mouse.screenY - startY)), true)
+-        }
+-        onPositionChanged: {
+-            lastNotificationPopup.x = Math.max(0, mouse.screenX - startX)
+-            lastNotificationPopup.y = Math.max(0, mouse.screenY - startY)
+-        }
+-        onWheelMoved: {
+-            if (notificationsView.moving) {
+-                return
+-            }
+-
+-            if (wheel.delta > 0) {
+-                notificationsView.currentIndex = Math.max(0, notificationsView.currentIndex-1)
+-            } else {
+-                notificationsView.currentIndex = Math.min(notificationsView.count-1, notificationsView.currentIndex+1)
+-            }
+-        }
+-
+-        Timer {
+-            id: lastNotificationTimer
+-            interval: 4000
+-            repeat: false
+-            running: false
+-            onTriggered: lastNotificationPopup.visible = false
+-        }
+-
+-        ListView {
+-            id: notificationsView
+-            clip: true
+-            snapMode: ListView.SnapOneItem
+-            orientation: ListView.Horizontal
+-            anchors.fill: parent
+-            model: ListModel {
+-                id: lastNotificationsModel
+-            }
+-            interactive: false
+-            delegate: Item {
+-                height: notificationsView.height
+-                width: notificationsView.width
+-
+-                PlasmaComponents.Label {
+-                    id: titleLabel
+-                    text: model.summary
+-                    //font.weight: Font.Bold
+-                    visible: model.summary.length > 0
+-                    height: model.summary.length > 0 ? paintedHeight : 0
+-                    horizontalAlignment: Text.AlignHCenter
+-                    color: theme.textColor
+-                    elide: Text.ElideRight
+-                    anchors {
+-                        left: appIconItem.y > y + height ? parent.left : appIconItem.right
+-                        right: parent.right
+-                        rightMargin: settingsButton.visible ? settingsButton.width + closeButton.width : closeButton.width
+-                        top: parent.top
+-                        topMargin: 6
+-                        leftMargin: 6
+-                    }
+-                    onLinkActivated: plasmoid.openUrl(link)
+-                }
+-
+-                QIconItem {
+-                    id: appIconItem
+-                    icon: model.appIcon
+-                    width: (model.appIcon.length > 0 || imageItem.visible) ? theme.largeIconSize : 0
+-                    height: theme.largeIconSize
+-                    visible: !imageItem.visible
+-                    anchors {
+-                        left: parent.left
+-                        verticalCenter: parent.verticalCenter
+-                        leftMargin: navigationButtonsColumn.width
+-                    }
+-                }
+-                QImageItem {
+-                    id: imageItem
+-                    anchors.fill: appIconItem
+-                    image: model.image
+-                    smooth: true
+-                    visible: nativeWidth > 0
+-                }
+-               /*
+-                * this extra item is for clip the overflowed body text
+-                * maximumLineCount cannot control the behavior of rich text,
+-                * so manual clip is required.
+-                */
+-                Item {
+-                    id: bodyLabel
+-                    clip: true
+-                    height: Math.min(parent.height - (titleLabel.height+titleLabel.y), lastNotificationText.height)
+-                    property bool tallText: bodyLabel.height >= (bodyLabel.parent.height - (titleLabel.height+titleLabel.y)*2)
+-                    anchors {
+-                        top: tallText ? titleLabel.bottom : undefined
+-                        verticalCenter: tallText ? undefined : parent.verticalCenter
+-                        left: appIconItem.right
+-                        right: actionsColumn.left
+-                        leftMargin: 6
+-                        rightMargin: 6
+-                    }
+-                    PlasmaComponents.Label {
+-                        id: lastNotificationText
+-                        text: model.body
+-                        width: parent.width
+-                        //textFormat: Text.PlainText
+-                        color: theme.textColor
+-                        wrapMode: Text.Wrap
+-                        elide: Text.ElideRight
+-                        maximumLineCount: 4
+-                        onLinkActivated: plasmoid.openUrl(link)
+-                    }
+-                }
+-                Column {
+-                    id: actionsColumn
+-                    spacing: 6
+-                    anchors {
+-                        right: parent.right
+-                        rightMargin: 6
+-                        verticalCenter: parent.verticalCenter
+-                    }
+-                    Repeater {
+-                        model: actions
+-                        PlasmaComponents.Button {
+-                            text: model.text
+-                            width: theme.defaultFont.mSize.width * 8
+-                            height: theme.defaultFont.mSize.width * 2
+-                            onPressedChanged: {
+-                                if (pressed) {
+-                                    mainItem.buttonPressed = true
+-                                } else {
+-                                    mainItem.buttonPressed = false
+-                                }
+-                            }
+-                            onClicked: {
+-                                executeAction(source, model.id)
+-                                actionsColumn.visible = false
+-                            }
+-                        }
+-                    }
+-                }
+-            }
+-        }
+-
+-        Column {
+-            id: navigationButtonsColumn
+-            opacity: 0
+-            visible: backButton.enabled || nextButton.enabled
+-            anchors {
+-                left: parent.left
+-                verticalCenter: parent.verticalCenter
+-            }
+-
+-            PlasmaComponents.ToolButton {
+-                id: nextButton
+-                iconSource: "go-next"
+-                width: theme.smallMediumIconSize
+-                height: mainItem.height/2 - 4
+-                enabled: notificationsView.currentIndex < notificationsView.count-1
+-                onPressedChanged: {
+-                    if (pressed) {
+-                        mainItem.buttonPressed = true
+-                    } else {
+-                        mainItem.buttonPressed = false
+-                    }
+-                }
+-                onClicked: {
+-                    notificationsView.currentIndex = Math.min(notificationsView.count-1, notificationsView.currentIndex+1)
+-                }
+-            }
+-
+-            PlasmaComponents.ToolButton {
+-                id: backButton
+-                iconSource: "go-previous"
+-                width: theme.smallMediumIconSize
+-                height: mainItem.height/2 - 4
+-                enabled: notificationsView.currentIndex > 0
+-                onPressedChanged: {
+-                    if (pressed) {
+-                        mainItem.buttonPressed = true
+-                    } else {
+-                        mainItem.buttonPressed = false
+-                    }
+-                }
+-                onClicked: {
+-                    notificationsView.currentIndex = Math.max(0, notificationsView.currentIndex-1)
+-                }
+-            }
+-        }
+-        PlasmaComponents.ToolButton {
+-            id: closeButton
+-            opacity: 0
+-            iconSource: "window-close"
+-            width: theme.smallMediumIconSize
+-            height: width
+-            anchors {
+-                right: parent.right
+-                top: parent.top
+-            }
+-            onPressedChanged: {
+-                if (pressed) {
+-                    mainItem.buttonPressed = true
+-                } else {
+-                    mainItem.buttonPressed = false
+-                }
+-            }
+-            onClicked: {
+-                lastNotificationPopup.visible = false
+-                lastNotificationTimer.running = false
+-                closeNotification(notificationsModel.get((notificationsView.count-1)-notificationsView.currentIndex).source)
+-                notificationsModel.remove((notificationsView.count-1)-notificationsView.currentIndex)
+-            }
+-        }
+-        PlasmaComponents.ToolButton {
+-            id: settingsButton
+-            opacity: 0
+-            iconSource: "configure"
+-            width: theme.smallMediumIconSize
+-            height: width
+-            visible: notificationsModel.get((notificationsView.count-1)-notificationsView.currentIndex).configurable
+-            anchors {
+-                right: closeButton.left
+-                top: parent.top
+-                rightMargin: 5
+-            }
+-            onPressedChanged: {
+-                if (pressed) {
+-                    mainItem.buttonPressed = true
+-                } else {
+-                    mainItem.buttonPressed = false
+-                }
+-            }
+-            onClicked: {
+-                lastNotificationPopup.visible = false
+-                configureNotification(notificationsModel.get((notificationsView.count-1)-notificationsView.currentIndex).appRealName)
+-            }
+-        }
+-        states: [
+-            State {
+-                name: "controlsShown"
+-                PropertyChanges {
+-                    target: navigationButtonsColumn
+-                    opacity: 1
+-                }
+-                PropertyChanges {
+-                    target: closeButton
+-                    opacity: 1
+-                }
+-                PropertyChanges {
+-                    target: settingsButton
+-                    opacity: 1
+-                }
+-            },
+-            State {
+-                name: "controlsHidden"
+-                PropertyChanges {
+-                    target: navigationButtonsColumn
+-                    opacity: 0
+-                }
+-                PropertyChanges {
+-                    target: closeButton
+-                    opacity: 0
+-                }
+-                PropertyChanges {
+-                    target: settingsButton
+-                    opacity: 0
+-                }
+-            }
+-        ]
+-        transitions: [
+-            Transition {
+-             NumberAnimation {
+-                 properties: "opacity"
+-                 easing.type: Easing.InOutQuad
+-                 duration: 250
+-            }
+-         }
+-        ]
+-    }
+-}
+diff --git a/plasma/generic/applets/notifications/contents/ui/NotificationDelegate/NotificationDelegate.qml b/plasma/generic/applets/notifications/contents/ui/NotificationDelegate/NotificationDelegate.qml
+deleted file mode 100644
+index bf33eb1..0000000
+--- a/plasma/generic/applets/notifications/contents/ui/NotificationDelegate/NotificationDelegate.qml
++++ /dev/null
+@@ -1,253 +0,0 @@
+-/*
+- *   Copyright 2011 Marco Martin <notmart@gmail.com>
+- *
+- *   This program 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, 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 Library General Public License for more details
+- *
+- *   You should have received a copy of the GNU Library 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.
+- */
+-
+-import QtQuick 1.1
+-import org.kde.plasma.core 0.1 as PlasmaCore
+-import org.kde.plasma.components 0.1 as PlasmaComponents
+-import org.kde.qtextracomponents 0.1
+-
+-PlasmaComponents.ListItem {
+-    id: notificationItem
+-    opacity: 1-Math.abs(x)/width
+-    width: popupFlickable.width
+-    property int toolIconSize: theme.smallMediumIconSize
+-    property int layoutSpacing: 4
+-
+-    visible: appTabBar.currentTab == allAppsTab || appTabBar.currentTab.text == appName
+-
+-    Component.onCompleted: {
+-        allApplicationsModel.addApplication(appIcon, appName)
+-        mainScrollArea.height = mainScrollArea.implicitHeight
+-    }
+-    Component.onDestruction: {
+-        allApplicationsModel.removeApplication(model.appName)
+-        mainScrollArea.height = mainScrollArea.implicitHeight
+-    }
+-    Timer {
+-        interval: 10*60*1000
+-        repeat: false
+-        running: !idleTimeSource.idle
+-        onTriggered: {
+-            notificationsModel.remove(index)
+-        }
+-    }
+-
+-    MouseArea {
+-        width: parent.width
+-        height: childrenRect.height
+-        drag {
+-            target: notificationItem
+-            axis: Drag.XAxis
+-            //kind of an hack over Column being too smart
+-            minimumX: -parent.width + 1
+-            maximumX: parent.width - 1
+-        }
+-        onReleased: {
+-            if (notificationItem.x < -notificationItem.width/2) {
+-                removeAnimation.exitFromRight = false
+-                removeAnimation.running = true
+-            } else if (notificationItem.x > notificationItem.width/2 ) {
+-                removeAnimation.exitFromRight = true
+-                removeAnimation.running = true
+-            } else {
+-                resetAnimation.running = true
+-            }
+-        }
+-        SequentialAnimation {
+-            id: removeAnimation
+-            property bool exitFromRight: true
+-            NumberAnimation {
+-                target: notificationItem
+-                properties: "x"
+-                to: removeAnimation.exitFromRight ? notificationItem.width-1 : 1-notificationItem.width
+-                duration: 250
+-                easing.type: Easing.InOutQuad
+-            }
+-            NumberAnimation {
+-                target: notificationItem
+-                properties: "height"
+-                to: 0
+-                duration: 250
+-                easing.type: Easing.InOutQuad
+-            }
+-            ScriptAction {
+-                script: notificationsModel.remove(index)
+-            }
+-        }
+-        SequentialAnimation {
+-            id: resetAnimation
+-            NumberAnimation {
+-                target: notificationItem
+-                properties: "x"
+-                to: 0
+-                duration: 250
+-                easing.type: Easing.InOutQuad
+-            }
+-        }
+-        Column {
+-            spacing: notificationItem.layoutSpacing
+-            width: parent.width
+-            Item {
+-                width: parent.width
+-                height: summaryLabel.height
+-
+-                PlasmaComponents.Label {
+-                    id: summaryLabel
+-                    text: summary
+-                    height: paintedHeight
+-                    anchors {
+-                        left: parent.left
+-                        right: parent.right
+-                        leftMargin: closeButton.width
+-                        rightMargin: settingsButton.visible ? settingsButton.width + closeButton.width : closeButton.width
+-                    }
+-                    horizontalAlignment: Text.AlignHCenter
+-                    elide: Text.ElideRight
+-                    onLinkActivated: plasmoid.openUrl(link)
+-                }
+-
+-                PlasmaComponents.ToolButton {
+-                    id: closeButton
+-                    iconSource: "window-close"
+-                    width: notificationItem.toolIconSize
+-                    height: width
+-                    onClicked: {
+-                        if (notificationsModel.count > 1) {
+-                            removeAnimation.running = true
+-                        } else {
+-                            closeNotification(model.source)
+-                            notificationsModel.remove(index)
+-                        }
+-                    }
+-                    anchors {
+-                        top: parent.top
+-                        right: parent.right
+-                    }
+-                }
+-
+-                PlasmaComponents.ToolButton {
+-                    id: settingsButton
+-                    iconSource: "configure"
+-                    width: notificationItem.toolIconSize
+-                    height: width
+-                    visible: model.configurable
+-                    onClicked: {
+-                        plasmoid.hidePopup()
+-                        configureNotification(model.appRealName)
+-                    }
+-                    anchors {
+-                        top: parent.top
+-                        right: closeButton.left
+-                        rightMargin: 5
+-                    }
+-                }
+-            }
+-
+-            Item {
+-                height: childrenRect.height
+-                width: parent.width
+-                QIconItem {
+-                    id: appIconItem
+-                    icon: QIcon(appIcon)
+-                    width: theme.largeIconSize
+-                    height: theme.largeIconSize
+-                    visible: !imageItem.visible
+-                    anchors {
+-                        left: parent.left
+-                        verticalCenter: parent.verticalCenter
+-                    }
+-                }
+-                QImageItem {
+-                    id: imageItem
+-                    anchors.fill: appIconItem
+-                    image: model.image
+-                    smooth: true
+-                    visible: nativeWidth > 0
+-                }
+-                PlasmaComponents.ContextMenu {
+-                    id: contextMenu
+-                    visualParent: contextMouseArea
+-                    PlasmaComponents.MenuItem {
+-                        text: i18n("Copy")
+-                        onClicked: bodyText.copy()
+-                    }
+-                    PlasmaComponents.MenuItem {
+-                        text: i18n("Select All")
+-                        onClicked: bodyText.selectAll()
+-                    }
+-                }
+-                MouseArea {
+-                    id: contextMouseArea
+-                    anchors {
+-                        left: appIconItem.right
+-                        right: actionsColumn.left
+-                        verticalCenter: parent.verticalCenter
+-                        leftMargin: 6
+-                        rightMargin: 6
+-                    }
+-                    acceptedButtons: Qt.RightButton
+-                    height: bodyText.paintedHeight
+-                    preventStealing: true
+-                    onPressed: contextMenu.open(mouse.x, mouse.y)
+-                    TextEdit {
+-                        id: bodyText
+-                        anchors.fill: parent
+-                        text: body
+-                        color: theme.textColor
+-                        font.capitalization: theme.defaultFont.capitalization
+-                        font.family: theme.defaultFont.family
+-                        font.italic: theme.defaultFont.italic
+-                        font.letterSpacing: theme.defaultFont.letterSpacing
+-                        font.pointSize: theme.defaultFont.pointSize
+-                        font.strikeout: theme.defaultFont.strikeout
+-                        font.underline: theme.defaultFont.underline
+-                        font.weight: theme.defaultFont.weight
+-                        font.wordSpacing: theme.defaultFont.wordSpacing
+-                        selectByMouse: true
+-                        readOnly: true
+-                        wrapMode: Text.Wrap
+-                        textFormat: TextEdit.RichText
+-                        onLinkActivated: plasmoid.openUrl(link)
+-                    }
+-                }
+-                Column {
+-                    id: actionsColumn
+-                    spacing: notificationItem.layoutSpacing
+-                    anchors {
+-                        right: parent.right
+-                        rightMargin: 6
+-                        verticalCenter: parent.verticalCenter
+-                    }
+-                    Repeater {
+-                        model: actions
+-                        PlasmaComponents.Button {
+-                            text: model.text
+-                            width: theme.defaultFont.mSize.width * 8
+-                            height: theme.defaultFont.mSize.width * 2
+-                            onClicked: {
+-                                executeAction(source, model.id)
+-                                actionsColumn.visible = false
+-                            }
+-                        }
+-                    }
+-                }
+-            }
+-        }
+-    }
+-}
+diff --git a/plasma/generic/applets/notifications/contents/ui/NotificationDelegate/qmldir b/plasma/generic/applets/notifications/contents/ui/NotificationDelegate/qmldir
+deleted file mode 100644
+index 88fc37a..0000000
+--- a/plasma/generic/applets/notifications/contents/ui/NotificationDelegate/qmldir
++++ /dev/null
+@@ -1 +0,0 @@
+-NotificationDelegate 0.1 NotificationDelegate.qml
+diff --git a/plasma/generic/applets/notifications/contents/ui/NotificationIcon.qml b/plasma/generic/applets/notifications/contents/ui/NotificationIcon.qml
+deleted file mode 100644
+index f12cd56..0000000
+--- a/plasma/generic/applets/notifications/contents/ui/NotificationIcon.qml
++++ /dev/null
+@@ -1,188 +0,0 @@
+-/***************************************************************************
+- *   Copyright 2011 Davide Bettio <davide.bettio@kdemail.net>              *
+- *   Copyright 2011 Marco Martin <mart@kde.org>                            *
+- *                                                                         *
+- *   This program 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 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 Library General Public License for more details.                          *
+- *                                                                         *
+- *   You should have received a copy of the GNU Library 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 .        *
+- ***************************************************************************/
+-
+-import QtQuick 1.1
+-import org.kde.plasma.core 0.1 as PlasmaCore
+-import org.kde.plasma.components 0.1 as PlasmaComponents
+-import org.kde.qtextracomponents 0.1
+-import org.kde.plasma.extras 0.1 as PlasmaExtras
+-
+-
+-Item {
+-    PlasmaCore.SvgItem {
+-        id: notificationSvgItem
+-        svg: notificationSvg
+-        elementId: "notification-disabled"
+-        anchors.centerIn: parent
+-        width: Math.min(parent.width, parent.height)
+-        height: width
+-        state: notificationsApplet.state
+-
+-        PlasmaCore.Svg {
+-            id: notificationSvg
+-            imagePath: "icons/notification"
+-        }
+-
+-        Item {
+-            id: jobProgressItem
+-            width: notificationSvgItem.width * globalProgress
+-            clip: true
+-            visible: jobs.count > 0
+-            anchors {
+-                left: parent.left
+-                top: parent.top
+-                bottom: parent.bottom
+-            }
+-            PlasmaCore.SvgItem {
+-                svg: notificationSvg
+-                elementId: "notification-progress-active"
+-                anchors {
+-                    left: parent.left
+-                    top: parent.top
+-                    bottom: parent.bottom
+-                }
+-                width: notificationSvgItem.width
+-            }
+-        }
+-        PlasmaComponents.BusyIndicator {
+-            anchors.fill: parent
+-            visible: jobs ? jobs.count > 0 : false
+-            running: visible
+-        }
+-
+-        Column {
+-            id: countColumn
+-            visible: false
+-            anchors.centerIn: parent
+-            PlasmaCore.SvgItem {
+-                svg: notificationSvg
+-                elementId: {
+-                    switch (plasmoid.location) {
+-                    case TopEdge:
+-                        return "expander-top"
+-                    case LeftEdge:
+-                        return "expander-left"
+-                    case RightEdge:
+-                        return "expander-right"
+-                    default:
+-                        return "expander-bottom"
+-                    }
+-                }
+-                width: naturalSize.width
+-                height: naturalSize.height
+-                anchors.horizontalCenter: parent.horizontalCenter
+-            }
+-            PlasmaComponents.Label {
+-                property int totalCount: notificationsApplet.totalCount
+-                text: totalCount
+-
+-                property int oldTotalCount: 0
+-                font.pointSize: theme.smallestFont.pointSize
+-                height: paintedHeight - 3
+-                onTotalCountChanged: {
+-                    if (totalCount > oldTotalCount) {
+-                        notificationAnimation.running = true
+-                    }
+-                    oldTotalCount = totalCount
+-                }
+-            }
+-        }
+-
+-        PlasmaCore.SvgItem {
+-            id: notificationAnimatedItem
+-            anchors.fill: parent
+-            svg: notificationSvg
+-            elementId: "notification-active"
+-            opacity: 0
+-            scale: 2
+-
+-            SequentialAnimation {
+-                id: notificationAnimation
+-                NumberAnimation {
+-                    target: notificationAnimatedItem
+-                    duration: 250
+-                    properties: "opacity, scale"
+-                    to: 1
+-                    easing.type: Easing.InOutQuad
+-                }
+-                PauseAnimation { duration: 500 }
+-                ParallelAnimation {
+-                    NumberAnimation {
+-                        target: notificationAnimatedItem
+-                        duration: 250
+-                        properties: "opacity"
+-                        to: 0
+-                        easing.type: Easing.InOutQuad
+-                    }
+-                    NumberAnimation {
+-                        target: notificationAnimatedItem
+-                        duration: 250
+-                        properties: "scale"
+-                        to: 2
+-                        easing.type: Easing.InOutQuad
+-                    }
+-                }
+-            }
+-        }
+-        MouseArea {
+-            anchors.fill: parent
+-            onClicked: {
+-                if (notificationsApplet.totalCount > 0) {
+-                    plasmoid.togglePopup()
+-                } else {
+-                    plasmoid.hidePopup()
+-                }
+-            }
+-        }
+-        states: [
+-            State {
+-                name: "default"
+-                PropertyChanges {
+-                    target: notificationSvgItem
+-                    elementId: "notification-disabled"
+-                }
+-                PropertyChanges {
+-                    target: countColumn
+-                    visible: false
+-                }
+-                PropertyChanges {
+-                    target: plasmoid
+-                    status: PassiveStatus
+-                }
+-            },
+-            State {
+-                name: "new-notifications"
+-                PropertyChanges {
+-                    target: notificationSvgItem
+-                    elementId: jobs.count > 0 ? "notification-progress-inactive" : "notification-empty"
+-                }
+-                PropertyChanges {
+-                    target: countColumn
+-                    visible: true
+-                }
+-                PropertyChanges {
+-                    target: plasmoid
+-                    status: ActiveStatus
+-                }
+-            }
+-        ]
+-    }
+-}
+-
+diff --git a/plasma/generic/applets/notifications/contents/ui/Notifications.qml b/plasma/generic/applets/notifications/contents/ui/Notifications.qml
+deleted file mode 100644
+index 114ead2..0000000
+--- a/plasma/generic/applets/notifications/contents/ui/Notifications.qml
++++ /dev/null
+@@ -1,227 +0,0 @@
+-/*
+- *   Copyright 2012 Marco Martin <notmart@gmail.com>
+- *
+- *   This program 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, 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 Library General Public License for more details
+- *
+- *   You should have received a copy of the GNU Library 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.
+- */
+-
+-import QtQuick 1.1
+-import org.kde.plasma.core 0.1 as PlasmaCore
+-import org.kde.plasma.components 0.1 as PlasmaComponents
+-
+-import "plasmapackage:/ui/NotificationDelegate"
+-
+-Column {
+-    id: notificationsRoot
+-    property alias count: notificationsRepeater.count
+-    anchors {
+-        left: parent.left
+-        right: parent.right
+-    }
+-
+-    function addNotification(source, appIcon, image, appName, summary, body, expireTimeout, urgency, appRealName, configurable, actions) {
+-        // Do not show duplicated notifications
+-        for (var i = 0; i < notificationsModel.count; ++i) {
+-            if (notificationsModel.get(i).source == source &&
+-                notificationsModel.get(i).appName == appName &&
+-                notificationsModel.get(i).summary == summary &&
+-                notificationsModel.get(i).body == body) {
+-                return
+-            }
+-        }
+-
+-        for (var i = 0; i < notificationsModel.count; ++i) {
+-            if (notificationsModel.get(i).source == source) {
+-                notificationsModel.remove(i)
+-                break
+-            }
+-        }
+-        if (notificationsModel.count > 20) {
+-            notificationsModel.remove(notificationsModel.count-1)
+-        }
+-        var notification = {"source"  : source,
+-                "appIcon" : appIcon,
+-                "image"   : image,
+-                "appName" : appName,
+-                "summary" : summary,
+-                "body"    : body,
+-                "expireTimeout": expireTimeout,
+-                "urgency" : urgency,
+-                "configurable": configurable,
+-                "appRealName": appRealName,
+-                "actions" : actions}
+-        notificationsModel.insert(0, notification);
+-        if (plasmoid.popupShowing) {
+-            return
+-        }
+-        if (!lastNotificationPopup) {
+-            lastNotificationPopup = lastNotificationPopupComponent.createObject(notificationsRoot)
+-        }
+-        lastNotificationPopup.popup(notification)
+-    }
+-
+-    function executeAction(source, id) {
+-        //try to use the service
+-        if (source.indexOf("notification") !== -1) {
+-            var service = notificationsSource.serviceForSource(source)
+-            var op = service.operationDescription("invokeAction")
+-            op["actionId"] = id
+-
+-            service.startOperationCall(op)
+-        //try to open the id as url
+-        } else if (source.indexOf("Job") !== -1) {
+-            plasmoid.openUrl(id)
+-        }
+-    }
+-
+-    function configureNotification(appRealName) {
+-      var service = notificationsSource.serviceForSource("notification")
+-      var op = service.operationDescription("configureNotification")
+-      op["appRealName"] = appRealName;
+-      service.startOperationCall(op)
+-    }
+-
+-    function closeNotification(source) {
+-      var service = notificationsSource.serviceForSource(source)
+-      var op = service.operationDescription("userClosed")
+-      service.startOperationCall(op)
+-    }
+-
+-    property QtObject lastNotificationPopup
+-    Component {
+-        id: lastNotificationPopupComponent
+-        LastNotificationPopup {
+-        }
+-    }
+-
+-    ListModel {
+-        id: notificationsModel
+-    }
+-    ListModel {
+-        id: allApplicationsModel
+-        function addApplication(icon, name)
+-        {
+-            for (var i = 0; i < count; ++i) {
+-                var item = get(i)
+-                if (item.name == name) {
+-                    setProperty(i, "count", item.count + 1)
+-                    return
+-                }
+-            }
+-            append({"icon": icon, "name": name, "count": 1})
+-        }
+-        function removeApplication(name)
+-        {
+-            for (var i = 0; i < count; ++i) {
+-                var item = get(i)
+-                if (item.name == name) {
+-                    if (item.count <= 1) {
+-                        remove(i)
+-                        appTabBar.currentTab = allAppsTab
+-                        return
+-                    }
+-                    setProperty(i, "count", item.count - 1)
+-                    return
+-                }
+-            }
+-        }
+-    }
+-
+-    PlasmaCore.DataSource {
+-        id: idleTimeSource
+-        engine: "powermanagement"
+-        interval: 30000
+-        connectedSources: ["UserActivity"]
+-        //Idle whith more than 5 minutes of user inactivity
+-        property bool idle: data["UserActivity"]["IdleTime"] > 300000
+-    }
+-
+-    PlasmaCore.DataSource {
+-        id: notificationsSource
+-        engine: "notifications"
+-        interval: 0
+-
+-        onSourceAdded: {
+-            connectSource(source);
+-        }
+-
+-        onNewData: {
+-            var actions = new Array()
+-            if (data["actions"] && data["actions"].length % 2 == 0) {
+-                for (var i = 0; i < data["actions"].length; i += 2) {
+-                    var action = new Object()
+-                    action["id"] = data["actions"][i]
+-                    action["text"] = data["actions"][i+1]
+-                    actions.push(action)
+-                }
+-            }
+-            notificationsRoot.addNotification(
+-                    sourceName,
+-                    data["appIcon"],
+-                    data["image"],
+-                    data["appName"],
+-                    data["summary"],
+-                    data["body"],
+-                    data["expireTimeout"],
+-                    data["urgency"],
+-                    data["appRealName"],
+-                    data["configurable"],
+-                    actions)
+-        }
+-
+-    }
+-
+-    Title {
+-        visible: notificationsRepeater.count > 1 || (jobs && jobs.count > 0 && notificationsRepeater.count > 0)
+-        text: i18n("Notifications")
+-        PlasmaComponents.ToolButton {
+-            iconSource: "window-close"
+-            width: notificationsApplet.toolIconSize
+-            height: width
+-            anchors {
+-                right: parent.right
+-                verticalCenter: parent.verticalCenter
+-            }
+-            onClicked: notificationsModel.clear()
+-        }
+-    }
+-    PlasmaComponents.ListItem {
+-        visible: allApplicationsModel.count > 1
+-        PlasmaComponents.TabBar {
+-            id: appTabBar
+-            anchors.horizontalCenter: parent.horizontalCenter
+-            width: Math.min(implicitWidth, parent.width-8)
+-            PlasmaComponents.TabButton {
+-                id: allAppsTab
+-                text: i18n("All")
+-                iconSource: "dialog-information"
+-            }
+-            Repeater {
+-                model: allApplicationsModel
+-                PlasmaComponents.TabButton {
+-                    text: name
+-                    iconSource: icon
+-                }
+-            }
+-        }
+-    }
+-    Repeater {
+-        id: notificationsRepeater
+-        model: notificationsModel
+-        delegate: NotificationDelegate {
+-            toolIconSize: notificationsApplet.toolIconSize
+-        }
+-    }
+-}
+diff --git a/plasma/generic/applets/notifications/contents/ui/Title.qml b/plasma/generic/applets/notifications/contents/ui/Title.qml
+deleted file mode 100644
+index dff4f72..0000000
+--- a/plasma/generic/applets/notifications/contents/ui/Title.qml
++++ /dev/null
+@@ -1,43 +0,0 @@
+-/*
+- *   Copyright 2012 Marco Martin <notmart@gmail.com>
+- *
+- *   This program 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, 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 Library General Public License for more details
+- *
+- *   You should have received a copy of the GNU Library 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.
+- */
+-
+-import QtQuick 1.1
+-import org.kde.plasma.core 0.1 as PlasmaCore
+-import org.kde.plasma.components 0.1 as PlasmaComponents
+-
+-PlasmaComponents.ListItem {
+-    id: root
+-    property alias text: titleLabel.text
+-
+-
+-    sectionDelegate: true
+-
+-    width: parent.width
+-
+-    PlasmaComponents.Label {
+-        id: titleLabel
+-        horizontalAlignment: Text.AlignHCenter
+-        elide: Text.ElideRight
+-        anchors {
+-            verticalCenter: parent.verticalCenter
+-            left: parent.left
+-            right: parent.right
+-        }
+-    }
+-}
+diff --git a/plasma/generic/applets/notifications/contents/ui/config.ui b/plasma/generic/applets/notifications/contents/ui/config.ui
+deleted file mode 100644
+index 7769bba..0000000
+--- a/plasma/generic/applets/notifications/contents/ui/config.ui
++++ /dev/null
+@@ -1,69 +0,0 @@
+-<?xml version="1.0" encoding="UTF-8"?>
+-<ui version="4.0">
+- <class>feedsConfig</class>
+- <widget class="QWidget" name="feedsConfig">
+-  <property name="geometry">
+-   <rect>
+-    <x>0</x>
+-    <y>0</y>
+-    <width>337</width>
+-    <height>181</height>
+-   </rect>
+-  </property>
+-  <layout class="QFormLayout" name="formLayout">
+-   <item row="1" column="0">
+-    <widget class="QLabel" name="label_2">
+-     <property name="text">
+-      <string>&amp;Application notifications:</string>
+-     </property>
+-     <property name="buddy">
+-      <cstring>kcfg_ShowNotifications</cstring>
+-     </property>
+-    </widget>
+-   </item>
+-   <item row="1" column="1">
+-    <widget class="QCheckBox" name="kcfg_ShowNotifications">
+-     <property name="text">
+-      <string/>
+-     </property>
+-    </widget>
+-   </item>
+-   <item row="2" column="0">
+-    <widget class="QLabel" name="label_3">
+-     <property name="text">
+-      <string>&amp;File transfers and jobs:</string>
+-     </property>
+-     <property name="buddy">
+-      <cstring>kcfg_ShowJobs</cstring>
+-     </property>
+-    </widget>
+-   </item>
+-   <item row="2" column="1">
+-    <widget class="QCheckBox" name="kcfg_ShowJobs">
+-     <property name="text">
+-      <string/>
+-     </property>
+-    </widget>
+-   </item>
+-   <item row="0" column="0" colspan="2">
+-    <widget class="QLabel" name="label">
+-     <property name="font">
+-      <font>
+-       <weight>75</weight>
+-       <bold>true</bold>
+-      </font>
+-     </property>
+-     <property name="text">
+-      <string>Choose which information to show</string>
+-     </property>
+-    </widget>
+-   </item>
+-  </layout>
+- </widget>
+- <tabstops>
+-  <tabstop>kcfg_ShowNotifications</tabstop>
+-  <tabstop>kcfg_ShowJobs</tabstop>
+- </tabstops>
+- <resources/>
+- <connections/>
+-</ui>
+diff --git a/plasma/generic/applets/notifications/contents/ui/main.qml b/plasma/generic/applets/notifications/contents/ui/main.qml
+deleted file mode 100644
+index 4d4b0f7..0000000
+--- a/plasma/generic/applets/notifications/contents/ui/main.qml
++++ /dev/null
+@@ -1,171 +0,0 @@
+-/***************************************************************************
+- *   Copyright 2011 Davide Bettio <davide.bettio@kdemail.net>              *
+- *   Copyright 2011 Marco Martin <mart@kde.org>                            *
+- *                                                                         *
+- *   This program 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 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 Library General Public License for more details.                          *
+- *                                                                         *
+- *   You should have received a copy of the GNU Library 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 .        *
+- ***************************************************************************/
+-
+-import QtQuick 1.1
+-import org.kde.plasma.core 0.1 as PlasmaCore
+-import org.kde.plasma.components 0.1 as PlasmaComponents
+-import org.kde.qtextracomponents 0.1
+-import org.kde.plasma.extras 0.1 as PlasmaExtras
+-import org.kde.locale 0.1 as KLocale
+-
+-import "plasmapackage:/ui/uiproperties.js" as UiProperties
+-
+-
+-MouseEventListener {
+-    id: notificationsApplet
+-    state: "default"
+-    width: 32
+-    height: 32
+-    property int minimumWidth: mainScrollArea.implicitWidth
+-    property int minimumHeight: mainScrollArea.implicitHeight
+-    property int maximumWidth: -1
+-    property int maximumHeight: mainScrollArea.implicitHeight
+-
+-    property int toolIconSize: UiProperties.toolIconSize
+-    property int layoutSpacing: UiProperties.layoutSpacing
+-
+-    property real globalProgress: 0
+-
+-    property bool showNotifications: false
+-    property bool showJobs: false
+-
+-    property Item notifications: notificationsLoader.item
+-    property Item jobs: jobsLoader.item
+-
+-    //notifications + jobs
+-    property int totalCount: (notifications ? notifications.count : 0) + (jobs ? jobs.count : 0)
+-    onTotalCountChanged: {
+-        if (totalCount > 0) {
+-            state = "new-notifications"
+-        } else {
+-            state = "default"
+-            plasmoid.hidePopup()
+-        }
+-
+-        var data = new Object
+-        data["image"] = "preferences-desktop-notification"
+-        data["mainText"] = i18n("Notifications and Jobs")
+-        if (totalCount == 0) {
+-            data["subText"] = i18n("No notifications or jobs")
+-        } else if (!notifications.count) {
+-            data["subText"] = i18np("%1 running job", "%1 running jobs", jobs.count)
+-        } else if (!jobs.count) {
+-            data["subText"] = i18np("%1 notification", "%1 notifications", notifications.count)
+-        } else  {
+-            data["subText"] = i18np("%1 running job", "%1 running jobs", jobs.count) + "<br/>" + i18np("%1 notification", "%1 notifications", notifications.count)
+-        }
+-        plasmoid.popupIconToolTip = data
+-        plasmoid.passivePopup = jobs.count != 0
+-    }
+-
+-    property Item notificationIcon
+-
+-    Component.onCompleted: {
+-        //plasmoid.popupIcon = QIcon("preferences-desktop-notification")
+-        plasmoid.aspectRatioMode = "ConstrainedSquare"
+-        plasmoid.status = PassiveStatus
+-        allApplications = new Object
+-        plasmoid.addEventListener('ConfigChanged', configChanged);
+-        configChanged()
+-    }
+-
+-    function configChanged()
+-    {
+-        showNotifications = plasmoid.readConfig("ShowNotifications")
+-        showJobs = plasmoid.readConfig("ShowJobs")
+-    }
+-
+-    KLocale.Locale {
+-        id: locale
+-    }
+-
+-    PlasmaCore.Svg {
+-        id: configIconsSvg
+-        imagePath: "widgets/configuration-icons"
+-    }
+-
+-    property Component compactRepresentation: Component {
+-        NotificationIcon {
+-            id: notificationIcon
+-            Component.onCompleted: notificationsApplet.notificationIcon = notificationIcon
+-        }
+-    }
+-
+-    hoverEnabled: !UiProperties.touchInput
+-
+-    PlasmaExtras.ScrollArea {
+-        id: mainScrollArea
+-        anchors.fill: parent
+-        implicitWidth: theme.defaultFont.mSize.width * 40
+-        implicitHeight: Math.min(theme.defaultFont.mSize.height * 40, Math.max(theme.defaultFont.mSize.height * 6, contentsColumn.height))
+-        state: ""
+-
+-        states: [
+-            State {
+-                name: "underMouse"
+-                when: notificationsApplet.containsMouse
+-                PropertyChanges {
+-                    target: mainScrollArea
+-                    implicitHeight: implicitHeight
+-                }
+-            },
+-            State {
+-                name: ""
+-                when: !notificationsApplet.containsMouse
+-                PropertyChanges {
+-                    target: mainScrollArea
+-                    implicitHeight: Math.min(theme.defaultFont.mSize.height * 40, Math.max(theme.defaultFont.mSize.height * 6, contentsColumn.height))
+-                }
+-            }
+-        ]
+-
+-        Flickable {
+-            id: popupFlickable
+-            anchors.fill:parent
+-
+-            contentWidth: width
+-            contentHeight: contentsColumn.height
+-            clip: true
+-
+-            Column {
+-                id: contentsColumn
+-                width: popupFlickable.width
+-
+-                //TODO: load those on demand based on configuration
+-                Loader {
+-                    id: jobsLoader
+-                    source: showJobs ? "Jobs.qml" : ""
+-                    anchors {
+-                        left: parent.left
+-                        right: parent.right
+-                    }
+-                }
+-                Loader {
+-                    id: notificationsLoader
+-                    source: showNotifications ? "Notifications.qml" : ""
+-                    anchors {
+-                        left: parent.left
+-                        right: parent.right
+-                    }
+-                }
+-            }
+-        }
+-    }
+-}
+diff --git a/plasma/generic/applets/notifications/contents/ui/uiproperties.js b/plasma/generic/applets/notifications/contents/ui/uiproperties.js
+deleted file mode 100644
+index efad371..0000000
+--- a/plasma/generic/applets/notifications/contents/ui/uiproperties.js
++++ /dev/null
+@@ -1,23 +0,0 @@
+-/*
+- *   Copyright 2012 Marco Martin <notmart@gmail.com>
+- *
+- *   This program 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, 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 Library General Public License for more details
+- *
+- *   You should have received a copy of the GNU Library 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.
+- */
+-
+-
+-var toolIconSize = theme.smallMediumIconSize
+-var layoutSpacing = 4
+-var touchInput = false
+diff --git a/plasma/generic/applets/notifications/core/completedjobnotification.cpp b/plasma/generic/applets/notifications/core/completedjobnotification.cpp
+new file mode 100644
+index 0000000..9a08390
+--- /dev/null
++++ b/plasma/generic/applets/notifications/core/completedjobnotification.cpp
+@@ -0,0 +1,99 @@
++/***************************************************************************
++ *   completedjobnotification.h                                                          *
++ *   Copyright (C) 2010 Marco Martin <notmart@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 .        *
++ ***************************************************************************/
++
++#include "completedjobnotification.h"
++#include "job.h"
++
++#include <QProcess>
++
++#include <KIcon>
++#include <KLocale>
++#include <KDebug>
++
++
++static const int completedJobExpireDelay = 60 * 1000;
++static const int completedShortJobExpireDelay = 8 * 1000;
++static const uint shortJobsLength = 30 * 1000;
++
++CompletedJobNotification::CompletedJobNotification(QObject *parent)
++    : Notification(parent)
++{
++}
++
++CompletedJobNotification::~CompletedJobNotification()
++{
++}
++
++void CompletedJobNotification::setJob(Job *job)
++{
++    setApplicationName(job->applicationName());
++    setApplicationIcon(KIcon(job->applicationIconName()));
++    setSummary(i18n("%1 [Finished]", job->message()));
++
++    if (job->error().isEmpty()) {
++        setMessage(job->completedMessage());
++    } else {
++        setMessage(job->error());
++    }
++
++    if (job->elapsed() < shortJobsLength) {
++        setTimeout(completedShortJobExpireDelay);
++    } else {
++        setTimeout(completedJobExpireDelay);
++    }
++
++    if (job->destination().isValid()) {
++        QHash<QString, QString> actions;
++        actions.insert("open", i18n("Open"));
++        setActions(actions);
++        setActionOrder(QStringList()<<"open");
++
++        // create location url as is done in job->completedMessage()
++        KUrl location(job->destination());
++        if (job->totalAmounts().value("files") > 1) {
++            location.setFileName(QString());
++        }
++
++        m_destinationPrettyUrl = location.prettyUrl();
++    }
++
++    m_job = job;
++}
++
++void CompletedJobNotification::linkActivated(const QString &url)
++{
++    kDebug() << "open " << url;
++    QProcess::startDetached("kde-open", QStringList() << url);
++}
++
++Job *CompletedJobNotification::job() const
++{
++    return m_job;
++}
++
++void CompletedJobNotification::triggerAction(const QString &actionId)
++{
++    if (actionId == "open" && !m_destinationPrettyUrl.isNull()) {
++        linkActivated(m_destinationPrettyUrl);
++    }
++}
++
++
++#include "completedjobnotification.moc"
+diff --git a/plasma/generic/applets/notifications/core/completedjobnotification.h b/plasma/generic/applets/notifications/core/completedjobnotification.h
+new file mode 100644
+index 0000000..b5e1f15
+--- /dev/null
++++ b/plasma/generic/applets/notifications/core/completedjobnotification.h
+@@ -0,0 +1,51 @@
++/***************************************************************************
++ *   completedjobnotification.h                                            *
++ *   Copyright (C) 2010 Marco Martin <notmart@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 COMPLETEDJOBNOTIFICATION_H
++#define COMPLETEDJOBNOTIFICATION_H
++
++#include "notification.h"
++
++
++class Job;
++
++class CompletedJobNotification : public Notification
++{
++    Q_OBJECT
++
++public:
++    CompletedJobNotification(QObject *parent = 0);
++    virtual ~CompletedJobNotification();
++
++    void setJob(Job *job);
++    Job *job() const;
++
++public Q_SLOTS:
++    void linkActivated(const QString &link);
++    void triggerAction(const QString &actionId);
++
++private:
++    Job *m_job;
++    QString m_destinationPrettyUrl;
++};
++
++
++#endif
++
+diff --git a/plasma/generic/applets/notifications/core/job.cpp b/plasma/generic/applets/notifications/core/job.cpp
+new file mode 100644
+index 0000000..77ea03f
+--- /dev/null
++++ b/plasma/generic/applets/notifications/core/job.cpp
+@@ -0,0 +1,360 @@
++/***************************************************************************
++ *   Copyright (C) 2008 Rob Scheepmaker <r.scheepmaker@student.utwente.nl> *
++ *                                                                         *
++ *   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 "job.h"
++
++#include <QtCore/QTimer>
++#include <QtCore/QTime>
++#include <QTextDocument>
++#include <QFontMetrics>
++#include <QApplication>
++
++#include <KDebug>
++#include <KUrl>
++#include <KLocalizedString>
++
++
++class Job::Private
++{
++public:
++    Private() :
++        numericSpeed(0),
++        finalElapsed(0),
++        state(Running),
++        percentage(0),
++        eta(0),
++        timerId(0),
++        killable(false),
++        suspendable(false),
++        shown(false)
++    {
++    }
++
++    QString applicationName;
++    QString applicationIconName;
++    QString message;
++    QString error;
++    QString speed;
++    QString destination;
++    qlonglong numericSpeed;
++
++
++    QMap<QString, qlonglong> totalAmounts;
++    QMap<QString, qlonglong> processedAmounts;
++
++    QList<QPair<QString, QString> > labels;
++
++    QTime elapsed;
++    uint finalElapsed;
++
++    State state;
++    uint percentage;
++    uint eta;
++    int timerId;
++
++    bool killable : 1;
++    bool suspendable : 1;
++    bool shown : 1;
++};
++
++Job::Job(QObject *parent)
++    : QObject(parent),
++      d(new Private)
++{
++    //delay a little the job to avoid the user to be distracted with short ones
++    QTimer::singleShot(1500, this, SLOT(show()));
++    d->elapsed.restart();
++}
++
++Job::~Job()
++{
++    delete d;
++}
++
++void Job::destroy()
++{
++    emit destroyed(this);
++    deleteLater();
++}
++
++QString Job::applicationName() const
++{
++    return d->applicationName;
++}
++
++void Job::setApplicationName(const QString &applicationName)
++{
++    if (d->applicationName != applicationName) {
++        d->applicationName = applicationName;
++        scheduleChangedSignal();
++    }
++}
++
++QString Job::applicationIconName() const
++{
++    return d->applicationIconName;
++}
++
++void Job::setApplicationIconName(const QString &applicationIcon)
++{
++    if (d->applicationIconName != applicationIcon) {
++        d->applicationIconName = applicationIcon;
++        scheduleChangedSignal();
++    }
++}
++
++QString Job::message() const
++{
++    return d->message;
++}
++
++void Job::setMessage(const QString &message)
++{
++    if (d->message != message) {
++        d->message = message;
++        scheduleChangedSignal();
++    }
++}
++
++QString Job::error() const
++{
++    return d->error;
++}
++
++void Job::setError(const QString &error)
++{
++    if (d->error != error) {
++        d->error = error;
++        scheduleChangedSignal();
++    }
++}
++
++QString Job::speed() const
++{
++    return d->speed;
++}
++
++void Job::setSpeed(const QString &speed)
++{
++    if (d->speed != speed) {
++        d->speed = speed;
++        scheduleChangedSignal();
++    }
++}
++
++qlonglong Job::numericSpeed() const
++{
++    return d->numericSpeed;
++}
++
++void Job::setNumericSpeed(const qlonglong speed)
++{
++    if (d->numericSpeed != speed) {
++        d->numericSpeed = speed;
++        scheduleChangedSignal();
++    }
++}
++
++QString Job::completedMessage() const
++{
++    KUrl location(d->destination);
++    if (location.isValid()) {
++        if (totalAmounts().value("files") > 1) {
++            location.setFileName(QString());
++        }
++
++        QString destinationString;
++        if (location.isLocalFile()) {
++            destinationString = location.toLocalFile();
++        } else {
++            destinationString = location.prettyUrl();
++        }
++
++        //FIXME: this is visualization stuff, but putting html here is not so model as well
++
++        kDebug() << "href = " << location.url();
++        QString destinationLink = QString("<a href=\"%1\">%2</a>").arg(location.url())
++                                  .arg(Qt::escape(destinationString));
++
++        if (totalAmounts().value("files") > 1) {
++            return i18np("%1 file, to: %2", "%1 files, to: %2", totalAmounts().value("files"),
++                         destinationLink);
++        } else {
++            return destinationLink;
++        }
++    } else {
++        return QString("%1: %2").arg(labels().value(0).first).arg(labels().value(0).second);
++    }
++}
++
++KUrl Job::destination() const
++{
++    return d->destination;
++}
++
++ulong Job::eta() const
++{
++    return d->eta;
++}
++
++void Job::setEta(ulong eta)
++{
++    d->eta = eta;
++}
++
++QMap<QString, qlonglong> Job::totalAmounts() const
++{
++    return d->totalAmounts;
++}
++
++void Job::setTotalAmounts(QMap<QString, qlonglong> amounts)
++{
++    d->totalAmounts = amounts;
++    scheduleChangedSignal();
++}
++
++QMap<QString, qlonglong> Job::processedAmounts() const
++{
++    return d->processedAmounts;
++}
++
++void Job::setProcessedAmounts(QMap<QString, qlonglong> amounts)
++{
++    d->processedAmounts = amounts;
++    scheduleChangedSignal();
++}
++
++Job::State Job::state() const
++{
++    return d->state;
++}
++
++void Job::setState(State state)
++{
++    if (d->state != state) {
++        d->state = state;
++        show();
++        if (state == Stopped) {
++            d->finalElapsed = d->elapsed.elapsed();
++        }
++        emit stateChanged(this);
++    }
++}
++
++QList<QPair<QString, QString> > Job::labels() const
++{
++    return d->labels;
++}
++
++void Job::setLabels(QList<QPair<QString, QString> > labels)
++{
++    d->labels = labels;
++    if (d->labels.count() > 1 && d->destination.isEmpty()) {
++        d->destination = d->labels.value(1).second;
++    }
++    scheduleChangedSignal();
++}
++
++uint Job::percentage() const
++{
++    return d->percentage;
++}
++
++void Job::setPercentage(uint percentage)
++{
++    if (d->percentage != percentage) {
++        d->percentage = percentage;
++        scheduleChangedSignal();
++    }
++}
++
++uint Job::elapsed() const
++{
++    if (d->finalElapsed) {
++        return d->finalElapsed;
++    } else {
++        return d->elapsed.elapsed();
++    }
++}
++
++bool Job::isSuspendable() const
++{
++    return d->suspendable;
++}
++
++void Job::setSuspendable(bool suspendable)
++{
++    if (d->suspendable != suspendable) {
++        d->suspendable = suspendable;
++        scheduleChangedSignal();
++    }
++}
++
++bool Job::isKillable() const
++{
++    return d->killable;
++}
++
++void Job::setKillable(bool killable)
++{
++    if (d->killable != killable) {
++        d->killable = killable;
++        scheduleChangedSignal();
++    }
++}
++
++void Job::suspend()
++{
++    kWarning() << "Suspend is not implemented in this job provider.";
++}
++
++void Job::resume()
++{
++    kWarning() << "Resume is not implemented in this job provider.";
++}
++
++void Job::stop()
++{
++    kWarning() << "Stop is not implemented in this job provider.";
++}
++
++void Job::show()
++{
++    if (state() == Job::Running && !d->shown) {
++        d->shown = true;
++        emit ready(this);
++    }
++}
++
++void Job::scheduleChangedSignal()
++{
++    if (d->shown && !d->timerId) {
++        d->timerId = startTimer(0);
++    }
++}
++
++void Job::timerEvent(QTimerEvent *)
++{
++    killTimer(d->timerId);
++    d->timerId = 0;
++    emit changed(this);
++}
++
++
++#include "job.moc"
+diff --git a/plasma/generic/applets/notifications/core/job.h b/plasma/generic/applets/notifications/core/job.h
+new file mode 100644
+index 0000000..3d2984d
+--- /dev/null
++++ b/plasma/generic/applets/notifications/core/job.h
+@@ -0,0 +1,188 @@
++/***************************************************************************
++ *   Copyright (C) 2008 Rob Scheepmaker <r.scheepmaker@student.utwente.nl> *
++ *                                                                         *
++ *   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 JOB_H
++#define JOB_H
++
++#include <QtCore/QHash>
++#include <QtCore/QObject>
++
++#include <KUrl>
++
++
++class Job : public QObject
++{
++    Q_OBJECT
++
++public:
++    enum State {
++        Running = 0,
++        Suspended = 1,
++        Stopped = 2
++    };
++
++    Job(QObject *parent = 0);
++    virtual ~Job();
++
++    /**
++     * Request and signal destruction of this object
++     */
++    void destroy();
++
++    /**
++     * @return the name of the application which started this job.
++     */
++    QString applicationName() const;
++
++    /**
++     * @return the name of the icon to be used for this job.
++     */
++    QString applicationIconName() const;
++
++    /**
++     * @return the descripion of the activity that is performed.
++     */
++    QString message() const;
++
++    /**
++     * @return the errormessage if an error has occurred.
++     */
++    QString error() const;
++
++    /**
++     * @return the (human readable) speed at which the jobs is progressing.
++     */
++    QString speed() const;
++
++    /**
++     * @return the (in bytes per second) speed at which the jobs is progressing.
++     */
++    qlonglong numericSpeed() const;
++
++    /**
++     * @return a nice description of the job that has been completed.
++     */
++    QString completedMessage() const;
++
++    /**
++     * @return the time (in seconds) in which this job is expected to complete.
++     */
++    ulong eta() const;
++
++    void setEta(ulong eta);
++
++    QMap<QString, qlonglong> totalAmounts() const;
++
++    QMap<QString, qlonglong> processedAmounts() const;
++
++    /**
++     * @return a list of pairs containing label names/values in the order they should be displayed.
++     */
++    QList<QPair<QString, QString> > labels() const;
++
++    /**
++     * @return the state this job is in.
++     */
++    State state() const;
++
++    bool isSuspendable() const;
++
++    bool isKillable() const;
++
++    /**
++     * @retun the percentage of the job that has been completed.
++     */
++    uint percentage() const;
++
++    /**
++     * total elapsed job time
++     */
++    uint elapsed() const;
++
++    /**
++     * Destination url
++     */
++    KUrl destination() const;
++
++public slots:
++    /**
++     * suspend this job.
++     */
++    virtual void suspend();
++
++    /**
++     * resume this job.
++     */
++    virtual void resume();
++
++    /**
++     * stop this job.
++     */
++    virtual void stop();
++
++signals:
++    /**
++     * Emitted when the job is ready to be shown
++     */
++    void ready(Job *job);
++
++    /**
++     * Emitted when the job changes state
++     */
++    void stateChanged(Job *job);
++
++    /**
++     * Emitted when the job details change
++     */
++    void changed(Job *job);
++
++    /**
++     * Emitted when the job is about to be destroyed
++     **/
++    void destroyed(Job *job);
++
++protected:
++    void setApplicationName(const QString &applicationName);
++    void setApplicationIconName(const QString &applicationIcon);
++    void setMessage(const QString &message);
++    void setError(const QString &error);
++    void setSpeed(const QString &speed);
++    void setNumericSpeed(const qlonglong speed);
++    void setTotalAmounts(QMap<QString, qlonglong> amount);
++    void setProcessedAmounts(QMap<QString, qlonglong> amount);
++    void setState(State state);
++    void setSuspendable(bool suspendable);
++    void setKillable(bool killable);
++    void setPercentage(uint percentage);
++    void setLabels(QList<QPair<QString, QString> > labels);
++    void timerEvent(QTimerEvent *);
++
++private slots:
++    void show();
++
++private:
++    void scheduleChangedSignal();
++
++    class Private;
++    Private* const d;
++
++    friend class Manager;
++};
++
++#endif
+diff --git a/plasma/generic/applets/notifications/core/notification.cpp b/plasma/generic/applets/notifications/core/notification.cpp
+new file mode 100644
+index 0000000..26833b6
+--- /dev/null
++++ b/plasma/generic/applets/notifications/core/notification.cpp
+@@ -0,0 +1,272 @@
++/***************************************************************************
++ *   notification.cpp                                                      *
++ *                                                                         *
++ *   Copyright (C) 2008 Jason Stubbs <jasonbstubbs@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 .        *
++ ***************************************************************************/
++
++#include "notification.h"
++
++#include <QImage>
++#include <QtCore/QTimer>
++
++#include <KDebug>
++
++
++class Notification::Private
++{
++public:
++    Private()
++        : timeout(0),
++          urgency(0),
++          hideTimer(0),
++          expired(false),
++          read(false)
++    {
++    }
++
++    QString identifier;
++    QString applicationName;
++    QIcon applicationIcon;
++    QString message;
++    QString summary;
++    int timeout;
++    int urgency;
++    QImage image;
++    QTimer *deleteTimer;
++    QTimer *hideTimer;
++    bool expired;
++    bool read;
++
++    QHash<QString, QString> actions;
++    QStringList actionOrder;
++};
++
++Notification::Notification(QObject *parent)
++    : QObject(parent),
++      d(new Private)
++{
++    d->deleteTimer = new QTimer(this);
++    d->deleteTimer->setSingleShot(true);
++    connect(d->deleteTimer, SIGNAL(timeout()), this, SLOT(destroy()));
++}
++
++
++Notification::~Notification()
++{
++    emit notificationDestroyed(this);
++    delete d;
++}
++
++void Notification::destroy()
++{
++    emit notificationDestroyed(this);
++    deleteLater();
++}
++
++QString Notification::applicationName() const
++{
++    return d->applicationName;
++}
++
++
++void Notification::setApplicationName(const QString &applicationName)
++{
++    d->applicationName = applicationName;
++}
++
++
++QIcon Notification::applicationIcon() const
++{
++    return d->applicationIcon;
++}
++
++
++void Notification::setApplicationIcon(const QIcon &applicationIcon)
++{
++    d->applicationIcon = applicationIcon;
++}
++
++
++QString Notification::message() const
++{
++    return d->message;
++}
++
++
++void Notification::setMessage(const QString &message)
++{
++    d->message = message;
++}
++
++
++QString Notification::summary() const
++{
++    return d->summary;
++}
++
++
++void Notification::setSummary(const QString &summary)
++{
++    d->summary = summary;
++}
++
++
++int Notification::timeout() const
++{
++    return d->timeout;
++}
++
++QImage Notification::image() const
++{
++    return d->image;
++}
++
++void Notification::setImage(QImage image)
++{
++    d->image = image;
++}
++
++void Notification::setTimeout(int timeout)
++{
++    //show them at most 30 seconds
++    if (!timeout) {
++        d->timeout = 30 * 1000;
++    } else {
++        d->timeout = timeout;
++    }
++
++    if (d->urgency >= 2) {
++        return;
++    }
++
++    if (!d->hideTimer) {
++        d->hideTimer = new QTimer(this);
++        d->hideTimer->setSingleShot(true);
++        connect(d->hideTimer, SIGNAL(timeout()), this, SLOT(hide()));
++    }
++    d->hideTimer->start(d->timeout);
++}
++
++void Notification::setUrgency(int urgency)
++{
++    if (urgency != d->urgency) {
++        d->urgency = urgency;
++        if (urgency >= 2) {
++            if (d->hideTimer) {
++                d->hideTimer->stop();
++            }
++            d->deleteTimer->stop();
++        } else {
++            setTimeout(d->timeout);
++        }
++    }
++}
++
++int Notification::urgency() const
++{
++    return d->urgency;
++}
++
++QHash<QString, QString> Notification::actions() const
++{
++    return d->actions;
++}
++
++
++void Notification::setActions(const QHash<QString, QString> &actions)
++{
++    d->actions = actions;
++    emit changed(this);
++}
++
++
++QStringList Notification::actionOrder() const
++{
++    return d->actionOrder;
++}
++
++
++void Notification::setActionOrder(const QStringList &actionOrder)
++{
++    d->actionOrder = actionOrder;
++}
++
++
++void Notification::triggerAction(const QString &actionId)
++{
++    Q_UNUSED(actionId);
++    kDebug() << "action triggered but no handler implemented";
++}
++
++void Notification::remove()
++{
++    kDebug() << "remove requested but no handler implemented";
++}
++
++void Notification::linkActivated(const QString &link)
++{
++    Q_UNUSED(link)
++    kDebug() << "link activation requested but no handler implemented";
++}
++
++void Notification::hide()
++{
++    d->expired = true;
++    emit expired(this);
++}
++
++void Notification::startDeletionCountdown()
++{
++    if (d->urgency >= 2) {
++        return;
++    }
++
++    //keep it available for 10 minutes
++    d->deleteTimer->start(10*60*1000);
++}
++
++bool Notification::isExpired() const
++{
++    return d->expired;
++}
++
++void Notification::setRead(const bool read)
++{
++    d->read = read;
++}
++
++bool Notification::isRead() const
++{
++    return d->read;
++}
++
++void Notification::setDeleteTimeout(const int time)
++{
++    if (d->deleteTimer->interval() != time) {
++        d->deleteTimer->start(time);
++    }
++}
++
++int Notification::deleteTimeOut() const
++{
++    return d->deleteTimer->interval();
++}
++
++
++
++#include "notification.moc"
+diff --git a/plasma/generic/applets/notifications/core/notification.h b/plasma/generic/applets/notifications/core/notification.h
+new file mode 100644
+index 0000000..e04fdba
+--- /dev/null
++++ b/plasma/generic/applets/notifications/core/notification.h
+@@ -0,0 +1,100 @@
++/***************************************************************************
++ *   notification.h                                                        *
++ *                                                                         *
++ *   Copyright (C) 2008 Jason Stubbs <jasonbstubbs@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 NOTIFICATION_H
++#define NOTIFICATION_H
++
++#include <QImage>
++#include <QtCore/QHash>
++#include <QtCore/QObject>
++
++#include <QtGui/QIcon>
++
++
++
++class Notification : public QObject
++{
++    Q_OBJECT
++
++public:
++    Notification(QObject *parent = 0);
++    virtual ~Notification();
++
++    QString applicationName() const;
++    QIcon applicationIcon() const;
++    QString message() const;
++    QString summary() const;
++    int timeout() const;
++    QImage image() const;
++
++    void setUrgency(int urgency);
++    int urgency() const;
++
++    QHash<QString, QString> actions() const;
++    QStringList actionOrder() const;
++
++    bool isExpired() const;
++
++    void setRead(const bool read);
++    bool isRead() const;
++
++    void setDeleteTimeout(const int time);
++    int deleteTimeOut() const;
++
++public slots:
++    virtual void triggerAction(const QString &actionId);
++    virtual void remove();
++    virtual void linkActivated(const QString &link);
++    void startDeletionCountdown();
++    void hide();
++    void destroy();
++
++signals:
++    void changed(Notification *notification = 0);
++
++    /**
++     * Emitted when the notification is about to be destroyed
++     **/
++    void notificationDestroyed(Notification *notification = 0);
++
++    /**
++     * emitted when the notification wants to hide itself
++     */
++    void expired(Notification *notification = 0);
++
++protected:
++    void setApplicationName(const QString &applicationName);
++    void setApplicationIcon(const QIcon &applicationIcon);
++    void setMessage(const QString &message);
++    void setSummary(const QString &summary);
++    void setImage(QImage image);
++    void setTimeout(int timeout);
++    void setActions(const QHash<QString, QString> &actions);
++    void setActionOrder(const QStringList &actionOrder);
++
++private:
++    class Private;
++    Private* const d;
++};
++
++
++
++#endif
+diff --git a/plasma/generic/applets/notifications/core/notificationsmanager.cpp b/plasma/generic/applets/notifications/core/notificationsmanager.cpp
+new file mode 100644
+index 0000000..6892361
+--- /dev/null
++++ b/plasma/generic/applets/notifications/core/notificationsmanager.cpp
+@@ -0,0 +1,245 @@
++/***************************************************************************
++ *   manager.cpp                                                           *
++ *                                                                         *
++ *   Copyright (C) 2008 Jason Stubbs <jasonbstubbs@gmail.com>              *
++ *   Copyright (C) 2010 Marco Martin <notmart@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 .        *
++ ***************************************************************************/
++
++#include "notificationsmanager.h"
++
++#include <QTimer>
++
++#include <KGlobal>
++
++#include <plasma/applet.h>
++
++#include "job.h"
++#include "notification.h"
++#include "protocol.h"
++
++#include "../protocols/notifications/dbusnotificationprotocol.h"
++#include "../protocols/jobs/dbusjobprotocol.h"
++
++
++static const int idleCheckInterval = 60 * 1000;
++
++class Manager::Private
++{
++public:
++    Private(Manager *manager)
++        : q(manager),
++          jobTotals(new Job(manager)),
++          jobProtocol(0),
++          notificationProtocol(0)
++    {
++    }
++
++    void setupProtocol(Protocol *protocol);
++    void checkIdle();
++
++    Manager *q;
++    QList<Task *> tasks;
++    QList<Notification*> notifications;
++    QList<Job *> jobs;
++    Job *jobTotals;
++    Notifications *notificationsApplet;
++    Protocol *jobProtocol;
++    Protocol *notificationProtocol;
++    QTimer *idleTimer;
++    static const int s_notificationLimit = 15;
++};
++
++
++Manager::Manager(Notifications *parentApplet)
++    : QObject(parentApplet),
++      d(new Private(this))
++{
++    d->notificationsApplet = parentApplet;
++    d->idleTimer = new QTimer(this);
++    d->idleTimer->setSingleShot(false);
++    connect(d->idleTimer, SIGNAL(timeout()), this, SLOT(checkIdle()));
++}
++
++Manager::~Manager()
++{
++    delete d;
++}
++
++void Manager::registerNotificationProtocol()
++{
++    if (!d->notificationProtocol) {
++        d->notificationProtocol = new DBusNotificationProtocol(this);
++        d->setupProtocol(d->notificationProtocol);
++    }
++}
++
++void Manager::unregisterNotificationProtocol()
++{
++    delete d->notificationProtocol;
++    d->notificationProtocol = 0;
++}
++
++void Manager::addNotification(Notification* notification)
++{
++    connect(notification, SIGNAL(notificationDestroyed(Notification*)),
++            this, SLOT(removeNotification(Notification*)));
++    connect(notification, SIGNAL(changed(Notification*)),
++            this, SIGNAL(notificationChanged(Notification*)));
++    connect(notification, SIGNAL(expired(Notification*)),
++            this, SIGNAL(notificationExpired(Notification*)));
++
++    d->notifications.append(notification);
++
++    if (!d->idleTimer->isActive()) {
++        d->idleTimer->start(idleCheckInterval);
++    }
++    connect(this, SIGNAL(idleTerminated()), notification, SLOT(startDeletionCountdown()));
++
++    emit notificationAdded(notification);
++
++    if (d->notifications.count() > d->s_notificationLimit) {
++        Notification *notification = d->notifications.first();
++        d->notifications.pop_front();
++        notification->deleteLater();
++    }
++}
++
++void Manager::removeNotification(Notification *notification)
++{
++    d->notifications.removeAll(notification);
++    disconnect(notification, 0, this, 0);
++    disconnect(this, 0, notification, 0);
++
++    if (d->notifications.isEmpty()) {
++        d->idleTimer->stop();
++    }
++
++    emit notificationRemoved(notification);
++}
++
++QList<Notification*> Manager::notifications() const
++{
++    return d->notifications;
++}
++
++void Manager::clearNotifications()
++{
++    qDeleteAll(d->notifications);
++    d->notifications.clear();
++}
++
++void Manager::registerJobProtocol()
++{
++    if (!d->jobProtocol) {
++        d->jobProtocol = new DBusJobProtocol(this);
++        d->setupProtocol(d->jobProtocol);
++    }
++}
++
++void Manager::unregisterJobProtocol()
++{
++    delete d->jobProtocol;
++    d->jobProtocol = 0;
++}
++
++void Manager::addJob(Job *job)
++{
++    connect(job, SIGNAL(destroyed(Job*)), this, SLOT(removeJob(Job*)));
++    connect(job, SIGNAL(changed(Job*)), this, SIGNAL(jobChanged(Job*)));
++    connect(job, SIGNAL(stateChanged(Job*)), this, SIGNAL(jobStateChanged(Job*)));
++    connect(job, SIGNAL(changed(Job*)), this, SLOT(updateTotals()));
++
++    d->jobs.append(job);
++    emit jobAdded(job);
++}
++
++void Manager::removeJob(Job *job)
++{
++    d->jobs.removeAll(job);
++    disconnect(job);
++    updateTotals();
++    emit jobRemoved(job);
++}
++
++void Manager::updateTotals()
++{
++    uint totalPercent = 0;
++    ulong totalEta = 0;
++    foreach (Job *job, d->jobs) {
++        totalPercent += job->percentage();
++        if (job->eta() > totalEta) {
++            totalEta = job->eta();
++        }
++    }
++
++    if (d->jobs.count() > 0) {
++        d->jobTotals->setPercentage(totalPercent / d->jobs.count());
++        d->jobTotals->setMessage(i18np("1 running job (%2 remaining)", "%1 running jobs (%2 remaining)",
++                                 d->jobs.count(),
++                                 KGlobal::locale()->prettyFormatDuration(totalEta)));
++    } else {
++        d->jobTotals->setPercentage(0);
++        d->jobTotals->setMessage(i18n("no running jobs"));
++    }
++    //TODO: set a sensible icon
++}
++
++Job *Manager::jobTotals() const
++{
++    return d->jobTotals;
++}
++
++QList<Job*> Manager::jobs() const
++{
++    return d->jobs;
++}
++
++void Manager::checkIdle()
++{
++    int totalIdle;
++#ifdef HAVE_LIBXSS      // Idle detection.
++    XScreenSaverInfo*  _mit_info;
++    _mit_info = XScreenSaverAllocInfo();
++    XScreenSaverQueryInfo( QX11Info::display(), QX11Info::appRootWindow(), _mit_info );
++    totalIdle =  _mit_info->idle;
++    XFree( _mit_info );
++#else
++    totalIdle = 0;
++#endif // HAVE_LIBXSS
++
++    if (totalIdle < idleCheckInterval) {
++        d->idleTimer->stop();
++        emit idleTerminated();
++    }
++}
++
++void Manager::Private::setupProtocol(Protocol *protocol)
++{
++    connect(protocol, SIGNAL(jobCreated(Job*)), q, SLOT(addJob(Job*)));
++    connect(protocol, SIGNAL(notificationCreated(Notification*)),
++            q, SLOT(addNotification(Notification*)));
++    protocol->init();
++}
++
++Notifications *Manager::applet() const
++{
++    return d->notificationsApplet;
++}
++
++
++#include "notificationsmanager.moc"
+diff --git a/plasma/generic/applets/notifications/core/notificationsmanager.h b/plasma/generic/applets/notifications/core/notificationsmanager.h
+new file mode 100644
+index 0000000..a6d6639
+--- /dev/null
++++ b/plasma/generic/applets/notifications/core/notificationsmanager.h
+@@ -0,0 +1,161 @@
++/***************************************************************************
++ *   manager.h                                                             *
++ *                                                                         *
++ *   Copyright (C) 2008 Jason Stubbs <jasonbstubbs@gmail.com>              *
++ *   Copyright (C) 2010 Marco Martin <notmart@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 NOTIFICATIONSMANAGER_H
++#define NOTIFICATIONSMANAGER_H
++
++#include <QtCore/QObject>
++
++#include <KConfigGroup>
++
++#include <plasma/plasma.h>
++#include "../ui/notifications.h"
++
++
++namespace Plasma
++{
++class Applet;
++}
++
++class Notifications;
++class Notification;
++class Task;
++class Job;
++
++/**
++ * w
++ * @short Creator and amalgamator of the supported system tray specifications
++ **/
++class Manager : public QObject
++{
++    Q_OBJECT
++
++public:
++    Manager(Notifications *parentApplet);
++    ~Manager();
++
++    /**
++     * @return a list of all known Notification instances
++     **/
++    QList<Notification*> notifications() const;
++
++    /**
++     * clear all notifications
++     */
++    void clearNotifications();
++
++    /**
++     * @return a list of all known Job instances
++     **/
++    QList<Job*> jobs() const;
++
++    /**
++     * @return a Job instance that can be used to monitor total progress
++     **/
++    Job *jobTotals() const;
++
++    /**
++     * Integrates the Job progress info into the applet's notification system
++     **/
++    void registerJobProtocol();
++
++    /**
++     * Iintegrates the notifications into the applet's notification system
++     **/
++    void registerNotificationProtocol();
++
++      /**
++     * Removes the Job progress info from the applet's notification system
++     **/
++    void unregisterJobProtocol();
++
++    /**
++     * Removes the notifications from the applet's notification system
++     **/
++    void unregisterNotificationProtocol();
++
++    Notifications *applet() const;
++
++signals:
++    /**
++     * Emitted when a new notification has been added
++     **/
++    void notificationAdded(Notification *notification);
++
++    /**
++     * Emitted when something about a notification changes
++     **/
++    void notificationChanged(Notification *notification);
++
++    /**
++     * The notification is expired and wants to hide itself
++     */
++    void notificationExpired(Notification *notification);
++
++    /**
++     * Emitted when a notification has been removed
++     **/
++    void notificationRemoved(Notification *notification);
++
++    /**
++     * Emitted when a new job has been added
++     **/
++    void jobAdded(Job *job);
++
++    /**
++     * Emitted when the state of a job changes
++     **/
++    void jobStateChanged(Job *job);
++
++    /**
++     * Emitted when something about a job changes
++     **/
++    void jobChanged(Job *job);
++
++    /**
++     * Emitted when a job has been removed
++     **/
++    void jobRemoved(Job *job);
++
++    /**
++     * the pc is out of idle and is starting being used
++     */
++    void idleTerminated();
++
++private slots:
++    void addNotification(Notification *notification);
++    void removeNotification(Notification *notification);
++    void addJob(Job *job);
++    void removeJob(Job *job);
++    void updateTotals();
++    void checkIdle();
++
++private:
++    class Private;
++    Private* const d;
++
++    friend class Notifications;
++};
++
++
++
++#endif
+diff --git a/plasma/generic/applets/notifications/core/protocol.cpp b/plasma/generic/applets/notifications/core/protocol.cpp
+new file mode 100644
+index 0000000..a3716a2
+--- /dev/null
++++ b/plasma/generic/applets/notifications/core/protocol.cpp
+@@ -0,0 +1,31 @@
++/***************************************************************************
++ *   taskprotocol.cpp                                                      *
++ *                                                                         *
++ *   Copyright (C) 2008 Jason Stubbs <jasonbstubbs@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 .        *
++ ***************************************************************************/
++
++#include "protocol.h"
++
++
++Protocol::Protocol(QObject *parent)
++    : QObject(parent)
++{
++}
++
++
++#include "protocol.moc"
+diff --git a/plasma/generic/applets/notifications/core/protocol.h b/plasma/generic/applets/notifications/core/protocol.h
+new file mode 100644
+index 0000000..ea47292
+--- /dev/null
++++ b/plasma/generic/applets/notifications/core/protocol.h
+@@ -0,0 +1,68 @@
++/***************************************************************************
++ *   taskprotocol.h                                                        *
++ *                                                                         *
++ *   Copyright (C) 2008 Jason Stubbs <jasonbstubbs@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 PROTOCOL_H
++#define PROTOCOL_H
++
++#include <QtCore/QObject>
++
++
++class Job;
++class Notification;
++class Task;
++
++
++/**
++ * @short System tray protocol base class
++ *
++ * To support a new system tray protocol, this class and Task should be
++ * subclassed and the subclass of this class registered with the global
++ * Manager. The Protocol subclass should emit taskCreated() for each new
++ * task created.
++ **/
++class Protocol : public QObject
++{
++    Q_OBJECT
++public:
++    explicit Protocol(QObject *parent);
++
++    virtual void init() = 0;
++
++signals:
++    /**
++     * Signals that a new task has been created
++     **/
++    void taskCreated(Task *task);
++
++    /**
++     * Signals that a new notification has been created
++     **/
++    void jobCreated(Job *job);
++
++    /**
++     * Signals that a new notification has been created
++     **/
++    void notificationCreated(Notification *notification);
++};
++
++
++
++#endif
+diff --git a/plasma/generic/applets/notifications/metadata.desktop b/plasma/generic/applets/notifications/metadata.desktop
+deleted file mode 100644
+index 3a2be65..0000000
+--- a/plasma/generic/applets/notifications/metadata.desktop
++++ /dev/null
+@@ -1,166 +0,0 @@
+-[Desktop Entry]
+-Encoding=UTF-8
+-Name=Notifications
+-Name[ar]=تنبيهات
+-Name[ast]=Notificaciones
+-Name[be]=Абвяшчэнні
+-Name[be@latin]=Infarmavańnie
+-Name[bg]=Уведомяване
+-Name[bn]=বিজ্ঞপ্তি
+-Name[bn_IN]=সূচনাবার্তা
+-Name[br]=Kemenn
+-Name[bs]=obavještenja
+-Name[ca]=Notificacions
+-Name[ca@valencia]=Notificacions
+-Name[cs]=Oznamování
+-Name[csb]=Dôwanié wiédzë
+-Name[da]=Bekendtgørelser
+-Name[de]=Benachrichtigungen
+-Name[el]=Ειδοποιήσεις
+-Name[en_GB]=Notifications
+-Name[eo]=Atentigoj
+-Name[es]=Notificaciones
+-Name[et]=Märguanded
+-Name[eu]=Jakinarazpenak
+-Name[fa]=اخطارها
+-Name[fi]=Ilmoitukset
+-Name[fr]=Notifications
+-Name[fy]=Notifikaasjes
+-Name[ga]=Fógairt
+-Name[gl]=Notificacións
+-Name[gu]=નોંધણીઓ
+-Name[he]=הודעות
+-Name[hi]=सूचनाएँ
+-Name[hne]=सूचना मन ल
+-Name[hr]=Obavijesti
+-Name[hu]=Rendszerüzenetek
+-Name[ia]=Notificationes
+-Name[id]=Notifikasi
+-Name[is]=Kerfistilkynningar
+-Name[it]=Notifiche
+-Name[ja]=通知
+-Name[kk]=Құлақтандыру
+-Name[km]=សេចក្តី​ជូន​ដំណឹង​
+-Name[kn]=ಸೂಚನೆಗಳು
+-Name[ko]=알림
+-Name[ku]=Agahdarî
+-Name[lt]=Pranešimai
+-Name[lv]=Paziņojumi
+-Name[mai]=सूचनासभ
+-Name[mk]=Известувања
+-Name[ml]=അറിയിപ്പുകള്‍
+-Name[mr]=सूचना
+-Name[ms]=Pemberitahuan
+-Name[nb]=Varslinger
+-Name[nds]=Bescheden
+-Name[ne]=सूचना
+-Name[nl]=Meldingen
+-Name[nn]=Varslingar
+-Name[oc]=Notificacions
+-Name[or]=ବିଜ୍ଞପ୍ତି
+-Name[pa]=ਨੋਟੀਫਿਕੇਸ਼ਨ
+-Name[pl]=Powiadomienia
+-Name[pt]=Notificações
+-Name[pt_BR]=Notificações
+-Name[ro]=Notificări
+-Name[ru]=Системные уведомления
+-Name[se]=Dieđáhusat
+-Name[si]=දැනුම් දීම්
+-Name[sk]=Upozornenia
+-Name[sl]=Obvestila
+-Name[sr]=обавештења
+-Name[sr@ijekavian]=обавјештења
+-Name[sr@ijekavianlatin]=obavještenja
+-Name[sr@latin]=obaveštenja
+-Name[sv]=Underrättelser
+-Name[ta]=Notifications
+-Name[te]=నోటీసులు
+-Name[tg]=Огоҳиномаҳо
+-Name[th]=การแจ้งให้ทราบต่าง ๆ
+-Name[tr]=Bildirimler
+-Name[ug]=ئۇقتۇرۇشلار
+-Name[uk]=Сповіщення
+-Name[uz]=Xabarnomalar
+-Name[uz@cyrillic]=Хабарномалар
+-Name[wa]=Notifiaedjes
+-Name[x-test]=xxNotificationsxx
+-Name[zh_CN]=通知
+-Name[zh_TW]=通知
+-Comment=Display notifications and jobs
+-Comment[ar]=أظهر التنبيهات والمهام
+-Comment[ast]=Amosar notificaciones y xeres
+-Comment[bg]=Показване на уведомления и задачи
+-Comment[bs]=Prikazuje obavještenja i poslove
+-Comment[ca]=Mostra les notificacions i els treballs
+-Comment[ca@valencia]=Mostra les notificacions i els treballs
+-Comment[cs]=Oznámení a úlohy
+-Comment[da]=Vis bekendtgørelser og job
+-Comment[de]=Benachrichtigungen und Aktionen anzeigen
+-Comment[el]=Εμφανίζει ειδοποιήσεις και εργασίες
+-Comment[en_GB]=Display notifications and jobs
+-Comment[es]=Mostrar notificaciones y tareas
+-Comment[et]=Märguannete ja tööde näitamine
+-Comment[eu]=Bistaratu jakinarazpenak eta lanak
+-Comment[fi]=Näyttää ilmoituksia ja töitä
+-Comment[fr]=Affiche les notifications et les tâches
+-Comment[ga]=Taispeáin fógraí agus jabanna
+-Comment[gl]=Mostra notificacións e tarefas
+-Comment[he]=משמש להצגת הודעות ועבודות
+-Comment[hr]=Prikazuje obavijesti i poslove
+-Comment[hu]=Értesítések és feladatok megjelenítése
+-Comment[ia]=Monstra notificationes e labores
+-Comment[id]=Tampilan notifikasi dan tugas
+-Comment[is]=Birting tilkynninga og verka
+-Comment[it]=Mostra notifiche e processi
+-Comment[ja]=ディスプレイ通知とジョブ
+-Comment[kk]=Құлақтандыру мен тапсырмаларды көрсету
+-Comment[km]=បង្ហាញ​ការ​ជូនដំណឹង និង​ការងារ
+-Comment[kn]=ಸೂಚನೆಗಳು ಹಾಗು ಕಾರ್ಯಗಳನ್ನು ಪ್ರದರ್ಶಿಸು
+-Comment[ko]=알림과 작업 표시
+-Comment[lt]=Rodyti pranešimus ir darbus
+-Comment[lv]=Parāda paziņojumus un darbus
+-Comment[mr]=सूचना व कार्यै दर्शवा
+-Comment[nb]=Vis varslinger og jobber
+-Comment[nds]=Bescheden un Opgaven wiesen
+-Comment[nl]=Meldingen en taken tonen
+-Comment[pa]=ਨੋਟੀਫਿਕੇਸ਼ਨ ਤੇ ਜਾਬ ਵੇਖੋ
+-Comment[pl]=Wyświetlanie powiadomień i zadań
+-Comment[pt]=Mostrar as notificações e tarefas
+-Comment[pt_BR]=Exibe notificações e tarefas
+-Comment[ro]=Afișează notificări și sarcini
+-Comment[ru]=Уведомления и задания
+-Comment[si]=කාර්ය සහ දැනුම්දීමෙ පෙන්වන්න
+-Comment[sk]=Zobrazenie upozornení a úloh
+-Comment[sl]=Prikazuje obvestila in opravila
+-Comment[sr]=Приказује обавештења и послове
+-Comment[sr@ijekavian]=Приказује обавјештења и послове
+-Comment[sr@ijekavianlatin]=Prikazuje obavještenja i poslove
+-Comment[sr@latin]=Prikazuje obaveštenja i poslove
+-Comment[sv]=Visa underrättelser och jobb
+-Comment[tg]=Иттилооти огоҳиҳо ва амалҳо
+-Comment[th]=แสดงการแจ้งให้ทราบและงานต่าง ๆ
+-Comment[tr]=Bildirimleri ve görevleri göster
+-Comment[ug]=ئۇقتۇرۇش ۋە ۋەزىپىلەرنى كۆرسىتىدۇ
+-Comment[uk]=Показ сповіщень і завдань
+-Comment[vi]=Hiển thị thông báo và công việc
+-Comment[wa]=Håyner notifiaedjes eyet bouyes
+-Comment[x-test]=xxDisplay notifications and jobsxx
+-Comment[zh_CN]=显示通知和任务
+-Comment[zh_TW]=顯示通知與工作
+-
+-Type=Service
+-Icon=preferences-desktop-notification
+-X-KDE-ParentApp=
+-X-KDE-PluginInfo-Author=Davide Bettio
+-X-KDE-PluginInfo-Category=Tasks
+-X-KDE-PluginInfo-Email=davide.bettio@kdemail.net
+-X-KDE-PluginInfo-License=GPL
+-X-KDE-PluginInfo-Name=org.kde.notifications
+-X-KDE-PluginInfo-Version=0.1
+-X-KDE-PluginInfo-Website=http://plasma.kde.org/
+-X-KDE-ServiceTypes=Plasma/PopupApplet,Plasma/Applet
+-X-Plasma-API=declarativeappletscript
+-X-Plasma-DefaultSize=100,100
+-X-Plasma-MainScript=ui/main.qml
+-X-Plasma-RequiredExtensions=LaunchApp
+-X-Plasma-NotificationArea=true
+diff --git a/plasma/generic/applets/notifications/plasma-applet-notifications.desktop b/plasma/generic/applets/notifications/plasma-applet-notifications.desktop
+new file mode 100644
+index 0000000..78a76f8
+--- /dev/null
++++ b/plasma/generic/applets/notifications/plasma-applet-notifications.desktop
+@@ -0,0 +1,164 @@
++[Desktop Entry]
++Name=Notifications
++Name[ar]=تنبيهات
++Name[ast]=Notificaciones
++Name[be]=Абвяшчэнні
++Name[be@latin]=Infarmavańnie
++Name[bg]=Уведомяване
++Name[bn]=বিজ্ঞপ্তি
++Name[bn_IN]=সূচনাবার্তা
++Name[br]=Kemenn
++Name[bs]=obavještenja
++Name[ca]=Notificacions
++Name[ca@valencia]=Notificacions
++Name[cs]=Oznamování
++Name[csb]=Dôwanié wiédzë
++Name[da]=Bekendtgørelser
++Name[de]=Benachrichtigungen
++Name[el]=Ειδοποιήσεις
++Name[en_GB]=Notifications
++Name[eo]=Atentigoj
++Name[es]=Notificaciones
++Name[et]=Märguanded
++Name[eu]=Jakinarazpenak
++Name[fa]=اخطارها
++Name[fi]=Ilmoitukset
++Name[fr]=Notifications
++Name[fy]=Notifikaasjes
++Name[ga]=Fógairt
++Name[gl]=Notificacións
++Name[gu]=નોંધણીઓ
++Name[he]=הודעות
++Name[hi]=सूचनाएँ
++Name[hne]=सूचना मन ल
++Name[hr]=Obavijesti
++Name[hu]=Rendszerüzenetek
++Name[ia]=Notificationes
++Name[id]=Notifikasi
++Name[is]=Kerfistilkynningar
++Name[it]=Notifiche
++Name[ja]=通知
++Name[kk]=Құлақтандыру
++Name[km]=សេចក្តី​ជូន​ដំណឹង​
++Name[kn]=ಸೂಚನೆಗಳು
++Name[ko]=알림
++Name[ku]=Agahdarî
++Name[lt]=Pranešimai
++Name[lv]=Paziņojumi
++Name[mai]=सूचनासभ
++Name[mk]=Известувања
++Name[ml]=അറിയിപ്പുകള്‍
++Name[mr]=सूचना
++Name[ms]=Pemberitahuan
++Name[nb]=Varslinger
++Name[nds]=Bescheden
++Name[ne]=सूचना
++Name[nl]=Meldingen
++Name[nn]=Varslingar
++Name[oc]=Notificacions
++Name[or]=ବିଜ୍ଞପ୍ତି
++Name[pa]=ਨੋਟੀਫਿਕੇਸ਼ਨ
++Name[pl]=Powiadomienia
++Name[pt]=Notificações
++Name[pt_BR]=Notificações
++Name[ro]=Notificări
++Name[ru]=Системные уведомления
++Name[se]=Dieđáhusat
++Name[si]=දැනුම් දීම්
++Name[sk]=Upozornenia
++Name[sl]=Obvestila
++Name[sr]=обавештења
++Name[sr@ijekavian]=обавјештења
++Name[sr@ijekavianlatin]=obavještenja
++Name[sr@latin]=obaveštenja
++Name[sv]=Underrättelser
++Name[ta]=Notifications
++Name[te]=నోటీసులు
++Name[tg]=Огоҳиномаҳо
++Name[th]=การแจ้งให้ทราบต่าง ๆ
++Name[tr]=Bildirimler
++Name[ug]=ئۇقتۇرۇشلار
++Name[uk]=Сповіщення
++Name[uz]=Xabarnomalar
++Name[uz@cyrillic]=Хабарномалар
++Name[wa]=Notifiaedjes
++Name[x-test]=xxNotificationsxx
++Name[zh_CN]=通知
++Name[zh_TW]=通知
++Comment=Display notifications and jobs
++Comment[ar]=أظهر التنبيهات والمهام
++Comment[ast]=Amosar notificaciones y xeres
++Comment[bg]=Показване на уведомления и задачи
++Comment[bs]=Prikazuje obavještenja i poslove
++Comment[ca]=Mostra les notificacions i els treballs
++Comment[ca@valencia]=Mostra les notificacions i els treballs
++Comment[cs]=Oznámení a úlohy
++Comment[da]=Vis bekendtgørelser og job
++Comment[de]=Benachrichtigungen und Aktionen anzeigen
++Comment[el]=Εμφανίζει ειδοποιήσεις και εργασίες
++Comment[en_GB]=Display notifications and jobs
++Comment[es]=Mostrar notificaciones y tareas
++Comment[et]=Märguannete ja tööde näitamine
++Comment[eu]=Bistaratu jakinarazpenak eta lanak
++Comment[fi]=Näyttää ilmoituksia ja töitä
++Comment[fr]=Affiche les notifications et les tâches
++Comment[ga]=Taispeáin fógraí agus jabanna
++Comment[gl]=Mostra notificacións e tarefas
++Comment[he]=משמש להצגת הודעות ועבודות
++Comment[hr]=Prikazuje obavijesti i poslove
++Comment[hu]=Értesítések és feladatok megjelenítése
++Comment[ia]=Monstra notificationes e labores
++Comment[id]=Tampilan notifikasi dan tugas
++Comment[is]=Birting tilkynninga og verka
++Comment[it]=Mostra notifiche e processi
++Comment[ja]=ディスプレイ通知とジョブ
++Comment[kk]=Құлақтандыру мен тапсырмаларды көрсету
++Comment[km]=បង្ហាញ​ការ​ជូនដំណឹង និង​ការងារ
++Comment[kn]=ಸೂಚನೆಗಳು ಹಾಗು ಕಾರ್ಯಗಳನ್ನು ಪ್ರದರ್ಶಿಸು
++Comment[ko]=알림과 작업 표시
++Comment[lt]=Rodyti pranešimus ir darbus
++Comment[lv]=Parāda paziņojumus un darbus
++Comment[nb]=Vis varslinger og jobber
++Comment[nds]=Bescheden un Opgaven wiesen
++Comment[nl]=Meldingen en taken tonen
++Comment[pa]=ਨੋਟੀਫਿਕੇਸ਼ਨ ਤੇ ਜਾਬ ਵੇਖੋ
++Comment[pl]=Wyświetlanie powiadomień i zadań
++Comment[pt]=Mostrar as notificações e tarefas
++Comment[pt_BR]=Exibe notificações e tarefas
++Comment[ro]=Afișează notificări și sarcini
++Comment[ru]=Уведомления и задания
++Comment[si]=කාර්ය සහ දැනුම්දීමෙ පෙන්වන්න
++Comment[sk]=Zobrazenie upozornení a úloh
++Comment[sl]=Prikazuje obvestila in opravila
++Comment[sr]=Приказује обавештења и послове
++Comment[sr@ijekavian]=Приказује обавјештења и послове
++Comment[sr@ijekavianlatin]=Prikazuje obavještenja i poslove
++Comment[sr@latin]=Prikazuje obaveštenja i poslove
++Comment[sv]=Visa underrättelser och jobb
++Comment[tg]=Иттилооти огоҳиҳо ва амалҳо
++Comment[th]=แสดงการแจ้งให้ทราบและงานต่าง ๆ
++Comment[tr]=Bildirimleri ve görevleri göster
++Comment[ug]=ئۇقتۇرۇش ۋە ۋەزىپىلەرنى كۆرسىتىدۇ
++Comment[uk]=Показ сповіщень і завдань
++Comment[vi]=Hiển thị thông báo và công việc
++Comment[wa]=Håyner notifiaedjes eyet bouyes
++Comment[x-test]=xxDisplay notifications and jobsxx
++Comment[zh_CN]=显示通知和任务
++Comment[zh_TW]=顯示通知與工作
++
++Icon=dialog-information
++Type=Service
++X-KDE-ServiceTypes=Plasma/Applet
++
++X-KDE-Library=plasma_applet_notifications
++X-KDE-PluginInfo-Author=Marco Martin
++X-KDE-PluginInfo-Email=notmart@gmail.com
++X-KDE-PluginInfo-Name=notifications
++X-KDE-PluginInfo-Version=1.0
++X-KDE-PluginInfo-Website=http://plasma.kde.org/
++X-KDE-PluginInfo-Category=System Information
++X-KDE-PluginInfo-Depends=
++X-KDE-PluginInfo-License=GPL v2+
++X-KDE-PluginInfo-EnabledByDefault=true
++
++X-Plasma-NotificationArea=true
+diff --git a/plasma/generic/applets/notifications/platformcontents/touch/ui/NotificationDelegate/NotificationDelegate.qml b/plasma/generic/applets/notifications/platformcontents/touch/ui/NotificationDelegate/NotificationDelegate.qml
+deleted file mode 100644
+index bdb74c2..0000000
+--- a/plasma/generic/applets/notifications/platformcontents/touch/ui/NotificationDelegate/NotificationDelegate.qml
++++ /dev/null
+@@ -1,195 +0,0 @@
+-/*
+- *   Copyright 2011 Marco Martin <notmart@gmail.com>
+- *
+- *   This program 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, 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 Library General Public License for more details
+- *
+- *   You should have received a copy of the GNU Library 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.
+- */
+-
+-import QtQuick 1.0
+-import org.kde.plasma.core 0.1 as PlasmaCore
+-import org.kde.plasma.components 0.1 as PlasmaComponents
+-import org.kde.qtextracomponents 0.1
+-
+-PlasmaComponents.ListItem {
+-    id: notificationItem
+-    opacity: 1-Math.abs(x)/width
+-    width: popupFlickable.width
+-    property int toolIconSize: theme.smallMediumIconSize
+-    property int layoutSpacing: 4
+-
+-    visible: appTabBar.currentTab == allAppsTab || appTabBar.currentTab.text == appName
+-
+-    Component.onCompleted: {
+-        allApplicationsModel.addApplication(appIcon, appName)
+-        mainScrollArea.height = mainScrollArea.implicitHeight
+-    }
+-    Component.onDestruction: {
+-        allApplicationsModel.removeApplication(model.appName)
+-        mainScrollArea.height = mainScrollArea.implicitHeight
+-    }
+-    Timer {
+-        interval: 10*60*1000
+-        repeat: false
+-        running: !idleTimeSource.idle
+-        onTriggered: {
+-            notificationsModel.remove(index)
+-        }
+-    }
+-
+-
+-    MouseArea {
+-        width: parent.width
+-        height: childrenRect.height
+-        drag {
+-            target: notificationItem
+-            axis: Drag.XAxis
+-            //kind of an hack over Column being too smart
+-            minimumX: -parent.width + 1
+-            maximumX: parent.width - 1
+-        }
+-        onReleased: {
+-            if (notificationItem.x < -notificationItem.width/2) {
+-                removeAnimation.exitFromRight = false
+-                removeAnimation.running = true
+-            } else if (notificationItem.x > notificationItem.width/2 ) {
+-                removeAnimation.exitFromRight = true
+-                removeAnimation.running = true
+-            } else {
+-                resetAnimation.running = true
+-            }
+-        }
+-        SequentialAnimation {
+-            id: removeAnimation
+-            property bool exitFromRight: true
+-            NumberAnimation {
+-                target: notificationItem
+-                properties: "x"
+-                to: removeAnimation.exitFromRight ? notificationItem.width-1 : 1-notificationItem.width
+-                duration: 250
+-                easing.type: Easing.InOutQuad
+-            }
+-            NumberAnimation {
+-                target: notificationItem
+-                properties: "height"
+-                to: 0
+-                duration: 250
+-                easing.type: Easing.InOutQuad
+-            }
+-            ScriptAction {
+-                script: notificationsModel.remove(index)
+-            }
+-        }
+-        SequentialAnimation {
+-            id: resetAnimation
+-            NumberAnimation {
+-                target: notificationItem
+-                properties: "x"
+-                to: 0
+-                duration: 250
+-                easing.type: Easing.InOutQuad
+-            }
+-        }
+-        Column {
+-            spacing: notificationItem.layoutSpacing
+-            width: parent.width
+-            Item {
+-                width: parent.width
+-                height: summaryLabel.height
+-
+-                PlasmaComponents.Label {
+-                    id: summaryLabel
+-                    text: summary
+-                    height: paintedHeight
+-                    anchors {
+-                        left: parent.left
+-                        right: parent.right
+-                        leftMargin: closeButton.width
+-                        rightMargin: closeButton.width
+-                    }
+-                    horizontalAlignment: Text.AlignHCenter
+-                    elide: Text.ElideRight
+-                }
+-
+-                PlasmaComponents.ToolButton {
+-                    id: closeButton
+-                    iconSource: "window-close"
+-                    width: notificationItem.toolIconSize
+-                    height: width
+-                    onClicked: removeAnimation.running = true
+-                    anchors {
+-                        top: parent.top
+-                        right: parent.right
+-                    }
+-                }
+-            }
+-
+-            Item {
+-                height: childrenRect.height
+-                width: parent.width
+-                QIconItem {
+-                    id: appIconItem
+-                    icon: QIcon(appIcon)
+-                    width: theme.largeIconSize
+-                    height: theme.largeIconSize
+-                    visible: !imageItem.visible
+-                    anchors {
+-                        left: parent.left
+-                        verticalCenter: parent.verticalCenter
+-                    }
+-                }
+-                QImageItem {
+-                    id: imageItem
+-                    anchors.fill: appIconItem
+-                    image: model.image
+-                    smooth: true
+-                    visible: nativeWidth > 0
+-                }
+-                PlasmaComponents.Label {
+-                    text: body
+-                    color: theme.textColor
+-                    anchors {
+-                        left: appIconItem.right
+-                        right: actionsColumn.left
+-                        verticalCenter: parent.verticalCenter
+-                        leftMargin: 6
+-                        rightMargin: 6
+-                    }
+-                    wrapMode: Text.Wrap
+-                }
+-                Column {
+-                    id: actionsColumn
+-                    spacing: notificationItem.layoutSpacing
+-                    anchors {
+-                        right: parent.right
+-                        rightMargin: 6
+-                        verticalCenter: parent.verticalCenter
+-                    }
+-                    Repeater {
+-                        model: actions
+-                        PlasmaComponents.Button {
+-                            text: model.text
+-                            width: theme.defaultFont.mSize.width * 8
+-                            height: theme.defaultFont.mSize.width * 3
+-                            onClicked: {
+-                                executeAction(source, model.id)
+-                                actionsColumn.visible = false
+-                            }
+-                        }
+-                    }
+-                }
+-            }
+-        }
+-    }
+-}
+diff --git a/plasma/generic/applets/notifications/platformcontents/touch/ui/NotificationDelegate/qmldir b/plasma/generic/applets/notifications/platformcontents/touch/ui/NotificationDelegate/qmldir
+deleted file mode 100644
+index 88fc37a..0000000
+--- a/plasma/generic/applets/notifications/platformcontents/touch/ui/NotificationDelegate/qmldir
++++ /dev/null
+@@ -1 +0,0 @@
+-NotificationDelegate 0.1 NotificationDelegate.qml
+diff --git a/plasma/generic/applets/notifications/platformcontents/touch/ui/uiproperties.js b/plasma/generic/applets/notifications/platformcontents/touch/ui/uiproperties.js
+deleted file mode 100644
+index f2f3d6b..0000000
+--- a/plasma/generic/applets/notifications/platformcontents/touch/ui/uiproperties.js
++++ /dev/null
+@@ -1,23 +0,0 @@
+-/*
+- *   Copyright 2012 Marco Martin <notmart@gmail.com>
+- *
+- *   This program 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, 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 Library General Public License for more details
+- *
+- *   You should have received a copy of the GNU Library 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.
+- */
+-
+-
+-var toolIconSize = theme.mediumIconSize
+-var layoutSpacing = 6
+-var touchInput = true
+diff --git a/plasma/generic/applets/notifications/protocols/jobs/dbusjob.cpp b/plasma/generic/applets/notifications/protocols/jobs/dbusjob.cpp
+new file mode 100644
+index 0000000..7c89275
+--- /dev/null
++++ b/plasma/generic/applets/notifications/protocols/jobs/dbusjob.cpp
+@@ -0,0 +1,54 @@
++/***************************************************************************
++ *   Copyright (C) 2008 Rob Scheepmaker <r.scheepmaker@student.utwente.nl> *
++ *                                                                         *
++ *   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 "dbusjob.h"
++
++#include <KDebug>
++
++
++
++DBusJob::DBusJob(const QString &source, QObject *parent)
++    : Job(parent),
++      m_source(source)
++{
++}
++
++DBusJob::~DBusJob()
++{
++    emit jobDeleted(m_source);
++}
++
++void DBusJob::suspend()
++{
++    emit suspend(m_source);
++    kDebug() << "suspend";
++}
++
++void DBusJob::resume()
++{
++    emit resume(m_source);
++    kDebug() << "resume";
++}
++
++void DBusJob::stop()
++{
++    emit stop(m_source);
++    kDebug() << "cancel";
++}
++
+diff --git a/plasma/generic/applets/notifications/protocols/jobs/dbusjob.h b/plasma/generic/applets/notifications/protocols/jobs/dbusjob.h
+new file mode 100644
+index 0000000..2e973d6
+--- /dev/null
++++ b/plasma/generic/applets/notifications/protocols/jobs/dbusjob.h
+@@ -0,0 +1,54 @@
++/***************************************************************************
++ *   Copyright (C) 2008 Rob Scheepmaker <r.scheepmaker@student.utwente.nl> *
++ *                                                                         *
++ *   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 DBUSJOB_H
++#define DBUSJOB_H
++
++#include "../../core/job.h"
++
++
++
++class DBusJob : public Job
++{
++    Q_OBJECT
++
++    friend class DBusJobProtocol;
++
++public:
++    DBusJob(const QString &source, QObject *parent = 0);
++    ~DBusJob();
++
++public slots:
++    void suspend();
++    void resume();
++    void stop();
++
++signals:
++    void jobDeleted(const QString &source);
++    void suspend(const QString &source);
++    void resume(const QString &source);
++    void stop(const QString &source);
++
++private:
++    QString m_source;
++};
++
++
++
++#endif
+diff --git a/plasma/generic/applets/notifications/protocols/jobs/dbusjobprotocol.cpp b/plasma/generic/applets/notifications/protocols/jobs/dbusjobprotocol.cpp
+new file mode 100644
+index 0000000..dff6dc9
+--- /dev/null
++++ b/plasma/generic/applets/notifications/protocols/jobs/dbusjobprotocol.cpp
+@@ -0,0 +1,180 @@
++/***************************************************************************
++ *   Copyright (C) 2008 Rob Scheepmaker <r.scheepmaker@student.utwente.nl> *
++ *                                                                         *
++ *   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 "dbusjob.h"
++#include "dbusjobprotocol.h"
++
++
++#include <KConfigGroup>
++
++#include <Plasma/DataEngineManager>
++#include <Plasma/Service>
++#include <Plasma/ServiceJob>
++
++static const char engineName[] = "applicationjobs";
++
++DBusJobProtocol::DBusJobProtocol(Manager *parent)
++    : Protocol(parent),
++      m_manager(parent),
++      m_engine(0)
++{
++}
++
++
++DBusJobProtocol::~DBusJobProtocol()
++{
++    if (m_engine) {
++        Plasma::DataEngineManager::self()->unloadEngine(engineName);
++    }
++
++    foreach (DBusJob *job, m_jobs) {
++        disconnect(job);
++        job->destroy();
++    }
++
++    m_jobs.clear();
++}
++
++
++void DBusJobProtocol::init()
++{
++    m_engine = Plasma::DataEngineManager::self()->loadEngine(engineName);
++
++    if (!m_engine->isValid()) {
++        Plasma::DataEngineManager::self()->unloadEngine(engineName);
++        m_engine = 0;
++        return;
++    }
++
++    connect(m_engine, SIGNAL(sourceAdded(QString)),
++            this, SLOT(prepareJob(QString)));
++    connect(m_engine, SIGNAL(sourceRemoved(QString)),
++            this, SLOT(removeJob(QString)));
++}
++
++void DBusJobProtocol::prepareJob(const QString &source)
++{
++    m_engine->connectSource(source, this);
++}
++
++void DBusJobProtocol::dataUpdated(const QString &source, const Plasma::DataEngine::Data &data)
++{
++    DBusJob *job = m_jobs.value(source, 0);
++
++    if (!job) {
++        job = new DBusJob(source, this);
++        m_jobs.insert(source, job);
++        connect(job, SIGNAL(jobDeleted(QString)),
++                this, SLOT(removeJob(QString)));
++        connect(job, SIGNAL(suspend(QString)),
++                this, SLOT(suspend(QString)));
++        connect(job, SIGNAL(resume(QString)),
++                this, SLOT(resume(QString)));
++        connect(job, SIGNAL(stop(QString)),
++                this, SLOT(stop(QString)));
++        connect(job, SIGNAL(ready(Job*)),
++                this, SIGNAL(jobCreated(Job*)));
++    }
++
++    job->setApplicationName(data.value("appName").toString());
++    job->setApplicationIconName(data.value("appIconName").toString());
++    job->setPercentage(data["percentage"].toUInt());
++    job->setError(data["error"].toString());
++    job->setMessage(data["infoMessage"].toString());
++    job->setSuspendable(data["suspendable"].toBool());
++    job->setKillable(data["killable"].toBool());
++    job->setSpeed(data["speed"].toString());
++    job->setNumericSpeed(data["numericSpeed"].toLongLong());
++    job->setEta(data["eta"].toULongLong());
++
++    if (data["state"].toString() == "running") {
++        job->setState(Job::Running);
++    } else if (data["state"].toString() == "suspended") {
++        job->setState(Job::Suspended);
++    } else {
++        job->setState(Job::Stopped);
++    }
++
++    int i = 0;
++    QList<QPair<QString, QString> > labels;
++    while (data.contains(QString("label%1").arg(i))) {
++        QPair<QString, QString> label;
++        label.first = data[QString("labelName%1").arg(i)].toString();
++        label.second = data[QString("label%1").arg(i)].toString();
++        labels << label;
++        i++;
++    }
++    job->setLabels(labels);
++
++    i = 0;
++    QMap<QString, qlonglong> totalAmounts;
++    while (data.contains(QString("totalUnit%1").arg(i))) {
++        QString unit = data[QString("totalUnit%1").arg(i)].toString();
++        qlonglong amount = data[QString("totalAmount%1").arg(i)].toLongLong();
++        totalAmounts[unit] = amount;
++        i++;
++    }
++    job->setTotalAmounts(totalAmounts);
++
++    i = 0;
++    QMap<QString, qlonglong> processedAmounts;
++    while (data.contains(QString("processedUnit%1").arg(i))) {
++        QString unit = data[QString("processedUnit%1").arg(i)].toString();
++        qlonglong amount = data[QString("processedAmount%1").arg(i)].toLongLong();
++        processedAmounts[unit] = amount;
++        i++;
++    }
++
++    job->setProcessedAmounts(processedAmounts);
++}
++
++void DBusJobProtocol::removeJob(const QString &source)
++{
++    if (m_jobs.contains(source)) {
++        DBusJob *job = m_jobs.take(source);
++        job->setState(Job::Stopped);
++        job->destroy();
++    }
++}
++
++void DBusJobProtocol::suspend(const QString &source)
++{
++    Plasma::Service *service = m_engine->serviceForSource(source);
++    KConfigGroup op = service->operationDescription("suspend");
++    KJob *job = service->startOperationCall(op);
++    connect(job, SIGNAL(finished(KJob*)), service, SLOT(deleteLater()));
++}
++
++void DBusJobProtocol::resume(const QString &source)
++{
++    Plasma::Service *service = m_engine->serviceForSource(source);
++    KConfigGroup op = service->operationDescription("resume");
++    KJob *job = service->startOperationCall(op);
++    connect(job, SIGNAL(finished(KJob*)), service, SLOT(deleteLater()));
++}
++
++void DBusJobProtocol::stop(const QString &source)
++{
++    Plasma::Service *service = m_engine->serviceForSource(source);
++    KConfigGroup op = service->operationDescription("stop");
++    KJob *job = service->startOperationCall(op);
++    connect(job, SIGNAL(finished(KJob*)), service, SLOT(deleteLater()));
++}
++
++#include "dbusjobprotocol.moc"
+diff --git a/plasma/generic/applets/notifications/protocols/jobs/dbusjobprotocol.h b/plasma/generic/applets/notifications/protocols/jobs/dbusjobprotocol.h
+new file mode 100644
+index 0000000..230356c
+--- /dev/null
++++ b/plasma/generic/applets/notifications/protocols/jobs/dbusjobprotocol.h
+@@ -0,0 +1,57 @@
++/***************************************************************************
++ *   Copyright (C) 2008 Rob Scheepmaker <r.scheepmaker@student.utwente.nl> *
++ *                                                                         *
++ *   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 DBUSJOBPROTOCOL_H
++#define DBUSJOBPROTOCOL_H
++
++#include "../../core/protocol.h"
++#include "../../core/notificationsmanager.h"
++
++#include <plasma/dataengine.h>
++
++
++class DBusJob;
++
++class DBusJobProtocol : public Protocol
++{
++    Q_OBJECT
++
++public:
++    DBusJobProtocol(Manager *parent);
++    ~DBusJobProtocol();
++    void init();
++
++private slots:
++    void prepareJob(const QString &source);
++    void dataUpdated(const QString &source, const Plasma::DataEngine::Data &data);
++    void removeJob(const QString &source);
++    //void relayAction(const QString &source, const QString &actionName);
++    void suspend(const QString &source);
++    void resume(const QString &source);
++    void stop(const QString &source);
++
++private:
++    Manager *m_manager;
++    Plasma::DataEngine *m_engine;
++    QHash<QString, DBusJob*> m_jobs;
++};
++
++
++
++#endif
+diff --git a/plasma/generic/applets/notifications/protocols/notifications/dbusnotification.cpp b/plasma/generic/applets/notifications/protocols/notifications/dbusnotification.cpp
+new file mode 100644
+index 0000000..2c28ff2
+--- /dev/null
++++ b/plasma/generic/applets/notifications/protocols/notifications/dbusnotification.cpp
+@@ -0,0 +1,48 @@
++/***************************************************************************
++ *   dbusnotification.cpp                                                  *
++ *                                                                         *
++ *   Copyright (C) 2008 Jason Stubbs <jasonbstubbs@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 .        *
++ ***************************************************************************/
++
++#include "dbusnotification.h"
++
++#include <KDebug>
++
++
++DBusNotification::DBusNotification(const QString &source, QObject *parent)
++    : Notification(parent),
++      m_source(source)
++{
++}
++
++DBusNotification::~DBusNotification()
++{
++    emit notificationDeleted(m_source);
++}
++
++void DBusNotification::remove()
++{
++    emit unregisterNotification(m_source);
++    deleteLater();
++}
++
++void DBusNotification::triggerAction(const QString &actionId)
++{
++    emit actionTriggered(m_source, actionId);
++}
++
+diff --git a/plasma/generic/applets/notifications/protocols/notifications/dbusnotification.h b/plasma/generic/applets/notifications/protocols/notifications/dbusnotification.h
+new file mode 100644
+index 0000000..213cc71
+--- /dev/null
++++ b/plasma/generic/applets/notifications/protocols/notifications/dbusnotification.h
+@@ -0,0 +1,54 @@
++/***************************************************************************
++ *   dbusnotification.h                                                    *
++ *                                                                         *
++ *   Copyright (C) 2008 Jason Stubbs <jasonbstubbs@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 DBUSNOTIFICATION_H
++#define DBUSNOTIFICATION_H
++
++#include "../../core/notification.h"
++
++
++
++class DBusNotification : public Notification
++{
++    Q_OBJECT
++
++    friend class DBusNotificationProtocol;
++
++public:
++    DBusNotification(const QString &source, QObject *parent = 0);
++    ~DBusNotification();
++
++public slots:
++    void remove();
++    void triggerAction(const QString &actionId);
++
++signals:
++    void notificationDeleted(const QString &source);
++    void actionTriggered(const QString &source, const QString &actionId);
++    void unregisterNotification(const QString &source);
++
++private:
++    QString m_source;
++};
++
++
++
++#endif
+diff --git a/plasma/generic/applets/notifications/protocols/notifications/dbusnotificationprotocol.cpp b/plasma/generic/applets/notifications/protocols/notifications/dbusnotificationprotocol.cpp
+new file mode 100644
+index 0000000..fd94048
+--- /dev/null
++++ b/plasma/generic/applets/notifications/protocols/notifications/dbusnotificationprotocol.cpp
+@@ -0,0 +1,192 @@
++/***************************************************************************
++ *   fdoprotocol.cpp                                                       *
++ *                                                                         *
++ *   Copyright (C) 2008 Jason Stubbs <jasonbstubbs@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 .        *
++ ***************************************************************************/
++
++#include "dbusnotification.h"
++#include "dbusnotificationprotocol.h"
++
++#include <KConfigGroup>
++#include <KDebug>
++#include <KIcon>
++
++#include <Plasma/DataEngineManager>
++#include <Plasma/Service>
++#include <Plasma/ServiceJob>
++
++
++static const char engineName[] = "notifications";
++
++DBusNotificationProtocol::DBusNotificationProtocol(Manager *parent)
++    : Protocol(parent),
++      m_manager(parent),
++      m_engine(0)
++{
++}
++
++
++DBusNotificationProtocol::~DBusNotificationProtocol()
++{
++    if (m_engine) {
++        Plasma::DataEngineManager::self()->unloadEngine(engineName);
++    }
++}
++
++
++void DBusNotificationProtocol::init()
++{
++    m_engine = Plasma::DataEngineManager::self()->loadEngine(engineName);
++
++    if (!m_engine->isValid()) {
++        m_engine = 0;
++        Plasma::DataEngineManager::self()->unloadEngine(engineName);
++        return;
++    }
++
++    connect(m_engine, SIGNAL(sourceAdded(QString)),
++            this, SLOT(prepareNotification(QString)));
++    connect(m_engine, SIGNAL(sourceRemoved(QString)),
++            this, SLOT(hideNotification(QString)));
++}
++
++
++void DBusNotificationProtocol::prepareNotification(const QString &source)
++{
++    if (m_engine) {
++        m_engine->connectSource(source, this);
++    }
++}
++
++
++void DBusNotificationProtocol::dataUpdated(const QString &source, const Plasma::DataEngine::Data &data)
++{
++    bool isNew = !m_notifications.contains(source);
++
++    if (isNew) {
++        DBusNotification * notification = new DBusNotification(source, this);
++        connect(notification, SIGNAL(unregisterNotification(QString)),
++                this, SLOT(unregisterNotification(QString)));
++        connect(notification, SIGNAL(notificationDeleted(QString)),
++                this, SLOT(notificationDeleted(QString)));
++        connect(notification, SIGNAL(actionTriggered(QString,QString)),
++                this, SLOT(relayAction(QString,QString)));
++        m_notifications[source] = notification;
++    }
++
++    DBusNotification* notification = m_notifications[source];
++    notification->setApplicationName(data.value("appName").toString());
++    notification->setApplicationIcon(KIcon(data.value("appIcon").toString()));
++    notification->setSummary(data.value("summary").toString());
++    notification->setMessage(data.value("body").toString());
++    notification->setTimeout(data.value("expireTimeout").toInt());
++    notification->setUrgency(data.value("urgency").toInt());
++
++    if (data.contains("image")) {
++        QImage image = qvariant_cast<QImage>(data.value("image"));
++        notification->setImage(image);
++    }
++
++    QStringList codedActions = data.value("actions").toStringList();
++    if (codedActions.count() % 2 != 0) {
++        kDebug() << "Invalid actions" << codedActions << "from" << notification->applicationName();
++        codedActions.clear();
++    }
++
++    QHash<QString, QString> actions;
++    QStringList actionOrder;
++
++    while (!codedActions.isEmpty()) {
++        QString actionId = codedActions.takeFirst();
++        QString actionName = codedActions.takeFirst();
++        actions.insert(actionId, actionName);
++        actionOrder.append(actionId);
++    }
++
++    notification->setActions(actions);
++    notification->setActionOrder(actionOrder);
++
++    if (isNew) {
++        emit notificationCreated(notification);
++    } else {
++        emit notification->changed(notification);
++    }
++}
++
++
++void DBusNotificationProtocol::relayAction(const QString &source, const QString &actionId)
++{
++    if (!m_engine) {
++        return;
++    }
++
++    Plasma::Service *service = m_engine->serviceForSource(source);
++    KConfigGroup op = service->operationDescription("invokeAction");
++
++    if (op.isValid()) {
++        op.writeEntry("actionId", actionId);
++        KJob *job = service->startOperationCall(op);
++        connect(job, SIGNAL(finished(KJob*)), service, SLOT(deleteLater()));
++    } else {
++        delete service;
++        kDebug() << "invalid operation";
++    }
++}
++
++void DBusNotificationProtocol::unregisterNotification(const QString &source)
++{
++    if (!m_engine) {
++        return;
++    }
++
++    Plasma::Service *service = m_engine->serviceForSource(source);
++    KConfigGroup op = service->operationDescription("userClosed");
++    KJob *job = service->startOperationCall(op);
++    connect(job, SIGNAL(finished(KJob*)), service, SLOT(deleteLater()));
++}
++
++void DBusNotificationProtocol::hideNotification(const QString &source)
++{
++    if (m_notifications.contains(source)) {
++        m_notifications.value(source)->hide();
++    }
++}
++
++void DBusNotificationProtocol::removeNotification(const QString &source)
++{
++    if (m_notifications.contains(source)) {
++        m_notifications.take(source)->destroy();
++    }
++}
++
++void DBusNotificationProtocol::notificationDeleted(const QString &source)
++{
++    if (!m_engine) {
++        return;
++    }
++
++    Plasma::Service *service = m_engine->serviceForSource(source);
++    KConfigGroup op = service->operationDescription("userClosed");
++    KJob *job = service->startOperationCall(op);
++    connect(job, SIGNAL(finished(KJob*)), service, SLOT(deleteLater()));
++
++    m_notifications.remove(source);
++}
++
++
++#include "dbusnotificationprotocol.moc"
+diff --git a/plasma/generic/applets/notifications/protocols/notifications/dbusnotificationprotocol.h b/plasma/generic/applets/notifications/protocols/notifications/dbusnotificationprotocol.h
+new file mode 100644
+index 0000000..e52dfd9
+--- /dev/null
++++ b/plasma/generic/applets/notifications/protocols/notifications/dbusnotificationprotocol.h
+@@ -0,0 +1,62 @@
++/***************************************************************************
++ *   dbusnotificationprotocol.h                                            *
++ *                                                                         *
++ *   Copyright (C) 2008 Jason Stubbs <jasonbstubbs@gmail.com>              *
++ *   Copyright (C) 2008 Dmitry Suzdalev <dimsuz@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 DBUSNOTIFICATIONPROTOCOL_H
++#define DBUSNOTIFICATIONPROTOCOL_H
++
++#include "../../core/protocol.h"
++#include "../../core/notificationsmanager.h"
++
++#include <QHash>
++
++#include <Plasma/DataEngine>
++
++
++class DBusNotification;
++
++class DBusNotificationProtocol : public Protocol
++{
++    Q_OBJECT
++
++public:
++    DBusNotificationProtocol(Manager *parent);
++    ~DBusNotificationProtocol();
++    void init();
++
++private slots:
++    void prepareNotification(const QString &source);
++    void dataUpdated(const QString &source, const Plasma::DataEngine::Data &data);
++    void removeNotification(const QString &source);
++    void notificationDeleted(const QString &source);
++    void relayAction(const QString &source, const QString &actionId);
++    void unregisterNotification(const QString&);
++    void hideNotification(const QString &source);
++
++private:
++    Manager *m_manager;
++    Plasma::DataEngine *m_engine;
++    QHash<QString, DBusNotification*> m_notifications;
++};
++
++
++
++#endif
+diff --git a/plasma/generic/applets/notifications/ui/busywidget.cpp b/plasma/generic/applets/notifications/ui/busywidget.cpp
+new file mode 100644
+index 0000000..6bce0d7
+--- /dev/null
++++ b/plasma/generic/applets/notifications/ui/busywidget.cpp
+@@ -0,0 +1,352 @@
++/***************************************************************************
++ *   Copyright (C) 2008, 2009 Rob Scheepmaker <r.scheepmaker@student.utwente.nl> *
++ *   Copyright (C) 2010 Marco Martin <notmart@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 .        *
++ ***************************************************************************/
++
++#include "busywidget.h"
++#include <fixx11h.h>
++
++#include <QtGui/QPainter>
++#include <QtGui/QTextOption>
++#include <QtGui/QStyleOptionGraphicsItem>
++#include <QtGui/QWidget> // QWIDGETSIZE_MAX
++#include <QSequentialAnimationGroup>
++
++#include <plasma/extender.h>
++#include <plasma/extenderitem.h>
++#include <plasma/extendergroup.h>
++#include <plasma/popupapplet.h>
++#include <plasma/tooltipmanager.h>
++#include <plasma/theme.h>
++#include <Plasma/Animation>
++#include <Plasma/Animator>
++
++#include <KIcon>
++#include <KGlobalSettings>
++
++#include "../core/notificationsmanager.h"
++#include "../core/job.h"
++#include "../core/notification.h"
++#include "../core/completedjobnotification.h"
++
++
++
++BusyWidget::BusyWidget(Plasma::PopupApplet *parent, const Manager *manager)
++    : Plasma::BusyWidget(parent),
++      m_icon("dialog-information"),
++      m_state(Empty),
++      m_svg(new Plasma::Svg(this)),
++      m_systray(parent),
++      m_manager(manager),
++      m_total(0),
++      m_suppressToolTips(false)
++{
++    setAcceptsHoverEvents(true);
++    m_svg->setImagePath("icons/notification");
++    m_svg->setContainsMultipleImages(true);
++    setRunning(false);
++
++    m_fadeInAnimation = Plasma::Animator::create(Plasma::Animator::PixmapTransitionAnimation);
++    m_fadeInAnimation->setTargetWidget(this);
++    m_fadeInAnimation->setProperty("duration", 1000);
++    m_fadeInAnimation->setProperty("targetPixmap", m_svg->pixmap("notification-active"));
++
++    m_fadeOutAnimation = Plasma::Animator::create(Plasma::Animator::PixmapTransitionAnimation);
++    m_fadeOutAnimation->setTargetWidget(this);
++    m_fadeOutAnimation->setProperty("duration", 1000);
++    m_fadeOutAnimation->setProperty("startPixmap", m_svg->pixmap("notification-active"));
++
++
++    m_fadeGroup = new QSequentialAnimationGroup(this);
++    m_fadeGroup->addAnimation(m_fadeInAnimation);
++    m_fadeGroup->addAnimation(m_fadeOutAnimation);
++
++    connect(manager, SIGNAL(notificationAdded(Notification*)),
++            this, SLOT(updateTask()));
++    connect(manager, SIGNAL(notificationRemoved(Notification*)),
++            this, SLOT(updateTask()));
++    connect(manager, SIGNAL(notificationChanged(Notification*)),
++            this, SLOT(updateTask()));
++    connect(manager, SIGNAL(notificationExpired(Notification*)),
++            this, SLOT(updateTask()));
++    connect(manager, SIGNAL(jobAdded(Job*)),
++            this, SLOT(updateTask()));
++    connect(manager, SIGNAL(jobRemoved(Job*)),
++            this, SLOT(updateTask()));
++    connect(manager, SIGNAL(jobStateChanged(Job*)),
++            this, SLOT(updateTask()));
++
++    Plasma::Extender *extender = qobject_cast<Plasma::Extender *>(m_systray->graphicsWidget());
++    if (extender) {
++        connect(extender, SIGNAL(itemDetached(Plasma::ExtenderItem*)),
++                this, SLOT(updateTask()));
++    }
++
++    Plasma::ToolTipManager::self()->registerWidget(this);
++    updateTask();
++}
++
++void BusyWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
++{
++    QRectF iconRect(0, 0, qMin(size().width(), size().height()), qMin(size().width(), size().height()));
++    iconRect.moveCenter(boundingRect().center());
++
++    if (m_state == Running) {
++        const int arcStart = 90*16;
++        const int arcEnd = -(360*(qreal)m_manager->jobTotals()->percentage()/100)*16;
++
++        Plasma::BusyWidget::paint(painter, option, widget);
++
++        //kDebug() << arcStart << arcEnd;
++
++        QPixmap activePixmap(iconRect.size().toSize());
++        activePixmap.fill(Qt::transparent);
++        QPixmap inActivePixmap(iconRect.size().toSize());
++        inActivePixmap.fill(Qt::transparent);
++        QRect pieRect(QPoint(0, 0), activePixmap.size()*2);
++        pieRect.moveCenter(activePixmap.rect().center());
++
++        QPainter p(&activePixmap);
++        p.setPen(Qt::NoPen);
++        p.setBrush(Qt::black);
++        p.setCompositionMode(QPainter::CompositionMode_Source);
++        p.drawPie(pieRect, arcStart, arcEnd);
++        p.setCompositionMode(QPainter::CompositionMode_SourceIn);
++        m_svg->paint(&p, QRectF(QPointF(0, 0), iconRect.size()), "notification-progress-active");
++        p.end();
++
++        p.begin(&inActivePixmap);
++        p.setPen(Qt::NoPen);
++        p.setBrush(Qt::black);
++        p.setCompositionMode(QPainter::CompositionMode_Source);
++        p.drawPie(pieRect, arcStart, (360*16)+arcEnd);
++        p.setCompositionMode(QPainter::CompositionMode_SourceIn);
++        m_svg->paint(&p, QRectF(QPointF(0, 0), iconRect.size()), "notification-progress-inactive");
++        p.end();
++
++        painter->drawPixmap(iconRect.topLeft().toPoint(), activePixmap);
++        painter->drawPixmap(iconRect.topLeft().toPoint(), inActivePixmap);
++
++        Plasma::BusyWidget::paint(painter, option, widget);
++
++    } else if (m_state == Empty && m_manager->notifications().count() > 0) {
++        m_svg->paint(painter, iconRect, "notification-inactive");
++    } else if (m_state == Empty && m_manager->notifications().count() == 0) {
++        m_svg->paint(painter, iconRect, "notification-disabled");
++    } else {
++        // m_state ==  Info
++        m_svg->paint(painter, iconRect, "notification-empty");
++        QFont font(KGlobalSettings::smallestReadableFont());
++        painter->setFont(font);
++        QRectF r = rect();
++
++        painter->setPen(Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor));
++
++        const QFontMetrics fm(font);
++        const QSize textSize = fm.boundingRect(label()).size();
++        const bool textFits = textSize.width() <= r.width() && textSize.height() <= r.height();
++        if (m_svg && m_svg->hasElement(expanderElement())) {
++            QSizeF arrowSize(m_svg->elementSize(expanderElement()));
++            QRectF arrowRect(r.center() - QPointF(arrowSize.width() / 2, arrowSize.height() + fm.xHeight() / 2), arrowSize);
++            m_svg->paint(painter, arrowRect, expanderElement());
++
++            r.setTop(arrowRect.bottom());
++
++            if (textFits) {
++                painter->drawText(r, Qt::AlignHCenter|Qt::AlignTop, label());
++            }
++        } else if (textFits) {
++            painter->drawText(r, Qt::AlignCenter, label());
++        }
++    }
++
++    if (m_fadeInAnimation->state() == QAbstractAnimation::Running) {
++        QPixmap pix = m_fadeInAnimation->property("currentPixmap").value<QPixmap>();
++        painter->drawPixmap(iconRect, pix, pix.rect());
++    } else if (m_fadeOutAnimation->state() == QAbstractAnimation::Running) {
++        QPixmap pix = m_fadeOutAnimation->property("currentPixmap").value<QPixmap>();
++        painter->drawPixmap(iconRect, pix, pix.rect());
++    }
++}
++
++void BusyWidget::resizeEvent(QGraphicsSceneResizeEvent *)
++{
++    //regenerate pixmaps
++    m_svg->resize(contentsRect().size());
++    m_fadeInAnimation->setProperty("targetPixmap", m_svg->pixmap("notification-active"));
++    m_fadeOutAnimation->setProperty("startPixmap", m_svg->pixmap("notification-active"));
++    m_svg->resize();
++}
++
++void BusyWidget::setState(State state)
++{
++    if (m_state == state) {
++        return;
++    }
++
++    m_state = state;
++    setRunning(m_state == Running);
++    update();
++}
++
++QString BusyWidget::expanderElement() const
++{
++    switch (m_systray->location()) {
++        case Plasma::TopEdge:
++            return "expander-top";
++        case Plasma::RightEdge:
++            return "expander-right";
++        case Plasma::LeftEdge:
++            return "expander-left";
++        case Plasma::BottomEdge:
++        default:
++            return "expander-bottom";
++    }
++}
++
++void BusyWidget::getJobCounts(int &runningJobs, int &pausedJobs, int &completedJobs, int &jobSpeed)
++{
++    runningJobs = pausedJobs = completedJobs = jobSpeed = 0;
++    foreach (const Job *job, m_manager->jobs()) {
++        switch (job->state()) {
++            case Job::Running:
++                jobSpeed += job->numericSpeed();
++                ++runningJobs;
++                break;
++            case Job::Suspended:
++                ++pausedJobs;
++                break;
++            default:
++                break;
++        }
++    }
++
++}
++
++void BusyWidget::updateTask()
++{
++    int runningJobs, pausedJobs, completedJobs, jobSpeed;
++    getJobCounts(runningJobs, pausedJobs, completedJobs, jobSpeed);
++
++    int total = m_manager->jobs().count();
++    int activeNotifications = 0;
++    bool hasOldNotifications = false;
++
++    foreach (Notification *notification, m_manager->notifications()) {
++        if (qobject_cast<CompletedJobNotification *>(notification)) {
++            ++completedJobs;
++        } else if (notification->isExpired()) {
++            hasOldNotifications = true;
++        } else {
++            ++activeNotifications;
++        }
++    }
++
++    total += completedJobs + activeNotifications;
++
++    if (total + m_manager->notifications().count() < 0) {
++        m_systray->hidePopup();
++    }
++
++    if (total > m_total) {
++        m_fadeGroup->start();
++    }
++
++    m_total = total;
++
++    if (activeNotifications > 0) {
++        m_systray->setStatus(Plasma::NeedsAttentionStatus);
++    } else if (m_total > 0 || hasOldNotifications) {
++        m_systray->setStatus(Plasma::ActiveStatus);
++    } else {
++        m_systray->setStatus(Plasma::PassiveStatus);
++    }
++
++    if (!total) {
++        setState(BusyWidget::Empty);
++        setLabel(QString());
++    } else if (runningJobs) {
++        setState(BusyWidget::Running);
++        setLabel(QString("%1").arg(QString::number(total)));
++    } else {
++        setState(BusyWidget::Info);
++        setLabel(QString::number(total));
++    }
++
++    if (Plasma::ToolTipManager::self()->isVisible(this)) {
++        toolTipAboutToShow();
++    }
++}
++
++void BusyWidget::suppressToolTips(bool suppress)
++{
++    m_suppressToolTips = suppress;
++}
++
++void BusyWidget::toolTipAboutToShow()
++{
++    if (m_suppressToolTips) {
++        Plasma::ToolTipManager::self()->setContent(this, Plasma::ToolTipContent());
++        return;
++    }
++
++    int runningJobs, pausedJobs, completedJobs, jobSpeed;
++    getJobCounts(runningJobs, pausedJobs, completedJobs, jobSpeed);
++
++    //make a nice plasma tooltip
++    QString tooltipContent;
++    if (runningJobs > 0) {
++        tooltipContent += i18ncp("Number of jobs and the speed at which they are downloading",
++                                 "%1 running job (%2/s)", "%1 running jobs (%2/s)", runningJobs,
++                                 KGlobal::locale()->formatByteSize(jobSpeed));
++        if (pausedJobs > 0 || completedJobs > 0 || !m_manager->notifications().isEmpty()) {
++            tooltipContent += "<br>";
++        }
++    }
++
++    if (pausedJobs > 0) {
++        tooltipContent += i18np("%1 suspended job", "%1 suspended jobs", pausedJobs);
++        if (completedJobs > 0 || !m_manager->notifications().isEmpty()) {
++            tooltipContent += "<br>";
++        }
++    }
++
++    if (completedJobs > 0) {
++        tooltipContent += i18np("%1 completed job", "%1 completed jobs", completedJobs);
++        if (!m_manager->notifications().isEmpty()) {
++            tooltipContent += "<br>";
++        }
++    }
++
++    if (!m_manager->notifications().isEmpty()) {
++        tooltipContent += i18np("%1 notification", "%1 notifications",
++                                m_manager->notifications().count());
++    }
++
++    if (tooltipContent.isEmpty()) {
++        tooltipContent = i18n("No active jobs or notifications");
++    }
++
++    Plasma::ToolTipContent data(i18n("Notifications and jobs"),
++                                tooltipContent,
++                                KIcon("help-about"));
++    Plasma::ToolTipManager::self()->setContent(this, data);
++}
++
++
++#include "busywidget.moc"
+diff --git a/plasma/generic/applets/notifications/ui/busywidget.h b/plasma/generic/applets/notifications/ui/busywidget.h
+new file mode 100644
+index 0000000..ae5f994
+--- /dev/null
++++ b/plasma/generic/applets/notifications/ui/busywidget.h
+@@ -0,0 +1,80 @@
++/***************************************************************************
++ *   Copyright (C) 2008 Rob Scheepmaker <r.scheepmaker@student.utwente.nl> *
++ *   Copyright (C) 2010 Marco Martin <notmart@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 NOTIFICATIONBUSYWIDGET_H
++#define NOTIFICATIONBUSYWIDGET_H
++
++#include <KIcon>
++
++#include <Plasma/BusyWidget>
++
++class QStyleOptionGraphicsItem;
++class QSequentialAnimationGroup;
++
++namespace Plasma
++{
++    class Animation;
++    class Extender;
++    class PopupApplet;
++    class Svg;
++}
++
++
++class Manager;
++
++class BusyWidget : public Plasma::BusyWidget
++{
++    Q_OBJECT
++
++public:
++    enum State { Empty, Info, Running };
++
++    BusyWidget(Plasma::PopupApplet *parent, const Manager *manager);
++    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0);
++    void setState(State state);
++    void suppressToolTips(bool suppress);
++
++public slots:
++    void toolTipAboutToShow();
++
++protected:
++    void resizeEvent(QGraphicsSceneResizeEvent *event);
++
++protected slots:
++    void updateTask();
++
++private:
++    QString expanderElement() const;
++    void getJobCounts(int &runningJobs, int &pausedJobs, int &completedJobs, int &jobSpeed);
++
++    KIcon m_icon;
++    State m_state;
++    Plasma::Svg *m_svg;
++    Plasma::PopupApplet *m_systray;
++    const Manager *m_manager;
++    Plasma::Animation *m_fadeInAnimation;
++    Plasma::Animation *m_fadeOutAnimation;
++    QSequentialAnimationGroup *m_fadeGroup;
++    int m_total;
++    bool m_suppressToolTips;
++};
++
++
++#endif
+diff --git a/plasma/generic/applets/notifications/ui/jobtotalswidget.cpp b/plasma/generic/applets/notifications/ui/jobtotalswidget.cpp
+new file mode 100644
+index 0000000..6552ed3
+--- /dev/null
++++ b/plasma/generic/applets/notifications/ui/jobtotalswidget.cpp
+@@ -0,0 +1,94 @@
++/***************************************************************************
++ *   Copyright 2009 by Rob Scheepmaker <r.scheepmaker@student.utwente.nl>  *
++ *                                                                         *
++ *   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 "jobtotalswidget.h"
++#include "../core/job.h"
++
++#include <Plasma/ExtenderItem>
++#include <Plasma/Meter>
++
++static const int UPDATE_TIMER_INTERVAL = 200;
++
++
++JobTotalsWidget::JobTotalsWidget(Job *job, QGraphicsWidget *parent)
++    : Meter(parent),
++      m_job(job),
++      m_updateTimerId(0)
++{
++    m_extenderGroup = qobject_cast<Plasma::ExtenderGroup *>(parent),
++
++    setSvg("widgets/bar_meter_horizontal");
++    setMeterType(Plasma::Meter::BarMeterHorizontal);
++
++    setMinimumWidth(350);
++    setMinimumHeight(16);
++    setMaximumHeight(16);
++    setMaximum(100);
++    setValue(0);
++
++    if (m_job) {
++        connect(m_job, SIGNAL(changed(Job*)),
++                this, SLOT(scheduleJobUpdate()));
++
++        updateJob();
++    }
++}
++
++JobTotalsWidget::~JobTotalsWidget()
++{
++}
++
++void JobTotalsWidget::scheduleJobUpdate()
++{
++    if (!m_updateTimerId) {
++        m_updateTimerId = startTimer(UPDATE_TIMER_INTERVAL);
++    }
++}
++
++void JobTotalsWidget::timerEvent(QTimerEvent *event)
++{
++    if (event->timerId() == m_updateTimerId) {
++        killTimer(m_updateTimerId);
++        m_updateTimerId = 0;
++        updateJob();
++    } else {
++        Meter::timerEvent(event);
++    }
++}
++
++void JobTotalsWidget::updateJob()
++{
++    setValue(m_job->percentage());
++
++    if (m_extenderGroup) {
++        if (m_extenderGroup->items().count() > 1 || m_extenderGroup->isGroupCollapsed()) {
++            m_extenderGroup->setTitle(m_job->message());
++        } else {
++            m_extenderGroup->setTitle(i18nc("Generic title for the job transfer popup", "Jobs"));
++        }
++        m_extenderGroup->setIcon(m_job->applicationIconName());
++    } else {
++        setLabelAlignment(0, Qt::AlignLeft|Qt::AlignVCenter);
++        setLabel(0, m_job->message());
++    }
++}
++
++
++#include "jobtotalswidget.moc"
++
+diff --git a/plasma/generic/applets/notifications/ui/jobtotalswidget.h b/plasma/generic/applets/notifications/ui/jobtotalswidget.h
+new file mode 100644
+index 0000000..4f07c86
+--- /dev/null
++++ b/plasma/generic/applets/notifications/ui/jobtotalswidget.h
+@@ -0,0 +1,65 @@
++/***************************************************************************
++ *   Copyright 2009 by Rob Scheepmaker <r.scheepmaker@student.utwente.nl   *
++ *                                                                         *
++ *   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 JOBTOTALSWIDGET_H
++#define JOBTOTALSWIDGET_H
++
++#include "../core/job.h"
++
++
++#include <QGraphicsWidget>
++
++#include <plasma/widgets/meter.h>
++#include <Plasma/Service>
++#include <Plasma/ExtenderGroup>
++#include <plasma/dataengine.h>
++
++namespace Plasma
++{
++    class ExtenderItem;
++    class Meter;
++} // namespace Plasma
++
++
++class Job;
++
++class JobTotalsWidget : public Plasma::Meter
++{
++    Q_OBJECT
++
++    public:
++        explicit JobTotalsWidget(Job *job, QGraphicsWidget *parent);
++        ~JobTotalsWidget();
++
++    protected:
++        void timerEvent(QTimerEvent *event);
++
++    private Q_SLOTS:
++        void scheduleJobUpdate();
++
++    private:
++        void updateJob();
++
++        Plasma::ExtenderGroup *m_extenderGroup;
++        Job *m_job;
++        int m_updateTimerId;
++};
++
++
++#endif
+diff --git a/plasma/generic/applets/notifications/ui/jobwidget.cpp b/plasma/generic/applets/notifications/ui/jobwidget.cpp
+new file mode 100644
+index 0000000..06096fd
+--- /dev/null
++++ b/plasma/generic/applets/notifications/ui/jobwidget.cpp
+@@ -0,0 +1,435 @@
++/***************************************************************************
++ *   Copyright 2008 by Rob Scheepmaker <r.scheepmaker@student.utwente.nl>  *
++ *                                                                         *
++ *   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 "jobwidget.h"
++#include "../core/job.h"
++
++
++#include <QFont>
++#include <QAction>
++#include <QGraphicsGridLayout>
++#include <QLabel>
++
++#include <KIconLoader>
++
++#include <Plasma/DataEngine>
++#include <Plasma/Extender>
++#include <Plasma/ExtenderItem>
++#include <Plasma/Label>
++#include <Plasma/Meter>
++#include <Plasma/PopupApplet>
++#include <Plasma/PushButton>
++#include <Plasma/Service>
++#include <Plasma/SignalPlotter>
++#include <Plasma/IconWidget>
++#include <Plasma/Theme>
++#include <Plasma/ToolTipManager>
++
++static const int UPDATE_INTERVAL = 200;
++
++JobWidget::JobWidget(Job *job, Plasma::ExtenderItem *parent)
++    : QGraphicsWidget(parent),
++      m_extenderItem(parent),
++      m_job(job),
++      m_updateTimerId(0),
++      m_extenderItemDestroyed(false)
++{
++    Q_ASSERT(m_extenderItem);
++
++    m_meter = new Plasma::Meter(this);
++    m_meter->setSvg("widgets/bar_meter_horizontal");
++    m_meter->setMeterType(Plasma::Meter::BarMeterHorizontal);
++    m_meter->setMaximumHeight(16);
++    m_meter->setMaximum(100);
++    m_meter->setValue(0);
++
++    m_plotter = new Plasma::SignalPlotter(this);
++    m_plotter->setUseAutoRange(true);
++    m_plotter->setShowVerticalLines(false);
++    m_plotter->setUnit(i18n("KiB/s"));
++    m_plotter->addPlot(Plasma::Theme::defaultTheme()->color(Plasma::Theme::HighlightColor));
++
++    m_fromNameLabel = new Plasma::Label(this);
++    m_fromLabel = new Plasma::Label(this);
++    m_toNameLabel = new Plasma::Label(this);
++    m_toLabel = new Plasma::Label(this);
++    m_totalBytesLabel = new Plasma::Label(this);
++    m_dirCountLabel = new Plasma::Label(this);
++    m_fileCountLabel = new Plasma::Label(this);
++    m_eta = new Plasma::Label(this);
++    m_details = new Plasma::IconWidget(this);
++    m_details->setSvg("widgets/action-overlays", "add-normal");
++    m_details->setMaximumSize(KIconLoader::SizeSmallMedium, KIconLoader::SizeSmallMedium);
++    m_details->setMinimumSize(KIconLoader::SizeSmallMedium, KIconLoader::SizeSmallMedium);
++
++    m_totalBytesLabel->setVisible(false);
++    m_dirCountLabel->setVisible(false);
++    m_fileCountLabel->setVisible(false);
++    m_plotter->setVisible(false);
++
++    m_fromNameLabel->setAlignment(Qt::AlignRight);
++    m_fromLabel->setAlignment(Qt::AlignLeft);
++    m_toNameLabel->setAlignment(Qt::AlignRight);
++    m_toLabel->setAlignment(Qt::AlignLeft);
++    m_totalBytesLabel->setAlignment(Qt::AlignRight);
++    m_dirCountLabel->setAlignment(Qt::AlignRight);
++    m_fileCountLabel->setAlignment(Qt::AlignRight);
++    m_eta->setAlignment(Qt::AlignRight);
++
++    m_fromLabel->nativeWidget()->setWordWrap(false);
++    m_toLabel->nativeWidget()->setWordWrap(false);
++    m_dirCountLabel->nativeWidget()->setWordWrap(false);
++    m_fileCountLabel->nativeWidget()->setWordWrap(false);
++    m_totalBytesLabel->nativeWidget()->setWordWrap(false);
++    m_eta->nativeWidget()->setWordWrap(false);
++
++    m_layout = new QGraphicsGridLayout(this);
++    m_layout->addItem(m_fromNameLabel, 0, 0);
++    m_layout->addItem(m_fromLabel, 0, 1);
++    m_layout->addItem(m_toNameLabel, 1, 0);
++    m_layout->addItem(m_toLabel, 1, 1);
++    m_layout->addItem(m_eta, 2, 1);
++    m_layout->addItem(m_details, 3, 0, Qt::AlignVCenter|Qt::AlignRight);
++    m_layout->addItem(m_meter, 3, 1, Qt::AlignCenter);
++
++    setMinimumWidth(350);
++
++    if (m_job.data()) {
++        m_details->setToolTip(i18n("More"));
++        m_details->setSvg("widgets/action-overlays", "add-normal");
++
++        connect(m_job.data(), SIGNAL(stateChanged(Job*)), this, SLOT(updateJobState()));
++        connect(m_job.data(), SIGNAL(destroyed(Job*)), this, SLOT(destroyExtenderItem()));
++        connect(m_details, SIGNAL(clicked()), this, SLOT(detailsClicked()));
++
++        //the suspend action
++        QAction *suspendAction = new QAction(m_extenderItem);
++        suspendAction->setIcon(KIcon("media-playback-pause"));
++        suspendAction->setEnabled(true);
++        suspendAction->setVisible(false);
++        suspendAction->setToolTip(i18n("Pause job"));
++        m_extenderItem->addAction("suspend", suspendAction);
++        connect(suspendAction, SIGNAL(triggered()), m_job.data(), SLOT(suspend()));
++
++        //the resume action
++        QAction *resumeAction = new QAction(m_extenderItem);
++        resumeAction->setIcon(KIcon("media-playback-start"));
++        resumeAction->setEnabled(true);
++        resumeAction->setVisible(false);
++        resumeAction->setToolTip(i18n("Resume job"));
++        m_extenderItem->addAction("resume", resumeAction);
++        connect(resumeAction, SIGNAL(triggered()), m_job.data(), SLOT(resume()));
++
++        //the friendly stop action
++        QAction *stopAction = new QAction(m_extenderItem);
++        stopAction->setIcon(KIcon("media-playback-stop"));
++        stopAction->setEnabled(true);
++        stopAction->setVisible(true);
++        stopAction->setToolTip(i18n("Cancel job"));
++        m_extenderItem->addAction("stop", stopAction);
++        connect(stopAction, SIGNAL(triggered()), m_job.data(), SLOT(stop()));
++
++        updateJob();
++        updateJobState();  // make sure to set the title
++    } else {
++        m_extenderItem->showCloseButton();
++
++        labelName0 = m_extenderItem->config().readEntry("labelName0", "");
++        label0= m_extenderItem->config().readEntry("label0", "");
++        labelName1 = m_extenderItem->config().readEntry("labelName1", "");
++        label1 = m_extenderItem->config().readEntry("label1", "");
++
++        updateLabels();
++    }
++}
++
++JobWidget::~JobWidget()
++{
++}
++
++void JobWidget::destroyExtenderItem()
++{
++    m_extenderItem->destroy();
++    m_extenderItemDestroyed = true;
++}
++
++void JobWidget::scheduleUpdateJob()
++{
++    if (m_extenderItemDestroyed) {
++        return;
++    }
++
++    if (!m_updateTimerId) {
++        m_updateTimerId = startTimer(UPDATE_INTERVAL);
++    }
++}
++
++void JobWidget::updateJobState()
++{
++    if (m_extenderItemDestroyed && m_job.data()) {
++        return;
++    }
++
++    //show the current status in the title.
++    if (!m_job.data()->error().isEmpty()) {
++        m_extenderItem->setTitle(m_job.data()->error());
++    } else if (m_job.data()->state() == Job::Running) {
++        m_extenderItem->setTitle(m_job.data()->message());
++        if (m_job.data()->eta()) {
++            m_eta->setText(i18n("%1 (%2 remaining)", m_job.data()->speed(),
++                                 KGlobal::locale()->prettyFormatDuration(m_job.data()->eta())));
++        } else {
++            m_eta->setText(QString());
++        }
++    } else if (m_job.data()->state() == Job::Suspended) {
++        m_extenderItem->setTitle(
++            i18nc("%1 is the name of the job, can be things like Copying, deleting, moving",
++                  "%1 [Paused]", m_job.data()->message()));
++        m_eta->setText(i18n("Paused"));
++    } else {
++        m_extenderItem->setTitle(
++            i18nc("%1 is the name of the job, can be things like Copying, deleting, moving",
++                  "%1 [Finished]", m_job.data()->message()));
++        m_extenderItem->showCloseButton();
++    }
++}
++
++void JobWidget::updateJob()
++{
++    if (m_extenderItemDestroyed || !m_job.data()) {
++        return;
++    }
++
++    m_meter->setValue(m_job.data()->percentage());
++
++    //Update the ETA and job speed (only if running)
++    if (m_job.data()->state() == Job::Running) {
++        if (m_job.data()->eta()) {
++            m_eta->setText(i18n("%1 (%2 remaining)", m_job.data()->speed(),
++                                 KGlobal::locale()->prettyFormatDuration(m_job.data()->eta())));
++        } else {
++            m_eta->setText(QString());
++        }
++    }
++
++    if (m_job.data()->labels().count() > 0) {
++        labelName0 = m_job.data()->labels().value(0).first;
++        label0 = m_job.data()->labels().value(0).second;
++    }
++    if (m_job.data()->labels().count() > 1) {
++        labelName1 = m_job.data()->labels().value(1).first;
++        label1 = m_job.data()->labels().value(1).second;
++    }
++
++    //TODO: can we write this at some later point?
++    KConfigGroup cg = m_extenderItem->config();
++    cg.writeEntry("labelName0", labelName0);
++    cg.writeEntry("label0", label0);
++    cg.writeEntry("labelName1", labelName1);
++    cg.writeEntry("label1", label1);
++
++    updateLabels();
++
++    //set the correct actions to visible.
++    if (m_extenderItem->action("suspend")) {
++        m_extenderItem->action("suspend")->setVisible(m_job.data()->isSuspendable() &&
++                                            m_job.data()->state() == Job::Running);
++    }
++
++    if (m_extenderItem->action("resume")) {
++        m_extenderItem->action("resume")->setVisible(m_job.data()->isSuspendable() &&
++                                           m_job.data()->state() == Job::Suspended);
++    }
++
++    if (m_extenderItem->action("stop")) {
++        m_extenderItem->action("stop")->setVisible(m_job.data()->isKillable() &&
++                                         m_job.data()->state() != Job::Stopped);
++    }
++
++    QMap<QString, qlonglong> processed = m_job.data()->processedAmounts();
++    QMap<QString, qlonglong> totals = m_job.data()->totalAmounts();
++
++    qlonglong dirs = totals.value("dirs");
++    if (dirs > 1) {
++        m_dirCountLabel->setText(i18np("%2 / 1 folder", "%2 / %1 folders", dirs, processed["dirs"]));
++        m_dirCountLabel->setMaximumHeight(INT_MAX);
++    } else {
++        m_dirCountLabel->setMaximumHeight(0);
++    }
++
++    qlonglong files = totals.value("files");
++    if (files > 1) {
++        m_fileCountLabel->setText(i18np("%2 / 1 file", "%2 / %1 files", files, processed["files"]));
++        m_fileCountLabel->setMaximumHeight(INT_MAX);
++    } else {
++        m_fileCountLabel->setMaximumHeight(0);
++    }
++
++    QList<double> sample;
++    sample << m_job.data()->numericSpeed()/1000;
++    m_plotter->addSample(sample);
++
++    qlonglong total = totals["bytes"];
++    if (total > 0) {
++        QString processedString = KGlobal::locale()->formatByteSize(processed["bytes"]);
++        QString totalsString = KGlobal::locale()->formatByteSize(total);
++        m_totalBytesLabel->setText(QString("%1 / %2").arg(processedString, totalsString));
++    } else {
++        m_details->hide();
++        m_totalBytesLabel->hide();
++    }
++
++    if (m_totalBytesLabel->text().isEmpty() &&
++        m_dirCountLabel->text().isEmpty() &&
++        m_fileCountLabel->text().isEmpty()) {
++        m_details->hide();
++    } else {
++        m_details->show();
++    }
++
++    m_extenderItem->setIcon(m_job.data()->applicationIconName());
++}
++
++void JobWidget::showEvent(QShowEvent *)
++{
++    if (!m_job.data()) {
++        return;
++    }
++
++    Plasma::PopupApplet *applet = qobject_cast<Plasma::PopupApplet *>(m_extenderItem->extender()->applet());
++    if (applet && applet->isPopupShowing()) {
++        updateJob();
++        disconnect(m_job.data(), SIGNAL(changed(Job*)), this, SLOT(scheduleUpdateJob()));
++        connect(m_job.data(), SIGNAL(changed(Job*)), this, SLOT(scheduleUpdateJob()));
++        return;
++    }
++}
++
++void JobWidget::hideEvent(QHideEvent *)
++{
++    if (!m_job.data()) {
++        return;
++    }
++
++    disconnect(m_job.data(), SIGNAL(changed(Job*)), this, SLOT(scheduleUpdateJob()));
++}
++
++void JobWidget::poppedUp(bool shown)
++{
++    if (!m_job.data()) {
++        return;
++    }
++
++    disconnect(m_job.data(), SIGNAL(changed(Job*)), this, SLOT(scheduleUpdateJob()));
++
++    if (shown && isVisible()) {
++        updateJob();
++        connect(m_job.data(), SIGNAL(changed(Job*)), this, SLOT(scheduleUpdateJob()));
++        return;
++    }
++}
++
++Job *JobWidget::job() const
++{
++    return m_job.data();
++}
++
++void JobWidget::resizeEvent(QGraphicsSceneResizeEvent *event)
++{
++    Q_UNUSED(event)
++    updateLabels();
++}
++
++void JobWidget::timerEvent(QTimerEvent *event)
++{
++    if (event->timerId() == m_updateTimerId) {
++        killTimer(m_updateTimerId);
++        m_updateTimerId = 0;
++        updateJob();
++    }
++}
++
++void JobWidget::updateLabels()
++{
++    QFontMetricsF fm = m_fromLabel->nativeWidget()->fontMetrics();
++    if (!labelName0.isEmpty()) {
++        m_fromNameLabel->setText(QString("%1: ").arg(labelName0));
++    }
++    if (label0.startsWith(QLatin1String("file://"))) {
++        label0 = KUrl(label0).toLocalFile();
++    }
++
++    const QString shortLabel0(fm.elidedText(label0, Qt::ElideMiddle, m_fromLabel->size().width()));
++    m_fromLabel->setText(shortLabel0);
++
++
++    Plasma::ToolTipContent data;
++
++    if (label0.length() > shortLabel0.length()) {
++        data.setSubText(label0);
++        Plasma::ToolTipManager::self()->setContent(m_fromLabel, data);
++    }
++
++    if (!labelName1.isEmpty()) {
++        m_toNameLabel->setText(QString("%1: ").arg(labelName1));
++    }
++    if (label1.startsWith(QLatin1String("file://"))) {
++        label1 = KUrl(label1).toLocalFile();
++    }
++
++    const QString shortLabel1(fm.elidedText(label1, Qt::ElideMiddle, m_toLabel->size().width()));
++    m_toLabel->setText(shortLabel1);
++
++    if (label1.length() > shortLabel1.length()) {
++        data.setSubText(label1);
++        Plasma::ToolTipManager::self()->setContent(m_toLabel, data);
++    }
++}
++
++void JobWidget::detailsClicked()
++{
++    if (!m_totalBytesLabel->isVisible()) {
++        m_details->setToolTip(i18n("Less"));
++        m_details->setSvg("widgets/action-overlays", "remove-normal");
++        m_totalBytesLabel->setVisible(true);
++        m_dirCountLabel->setVisible(true);
++        m_fileCountLabel->setVisible(true);
++        m_plotter->setVisible(true);
++        m_layout->addItem(m_totalBytesLabel, 4, 1);
++        m_layout->addItem(m_fileCountLabel, 5, 1);
++        m_layout->addItem(m_dirCountLabel, 6, 1);
++        m_layout->addItem(m_plotter, 7, 1);
++        m_extenderItem->setCollapsed(m_extenderItem->isCollapsed());
++    } else {
++        m_details->setToolTip(i18n("More"));
++        m_details->setSvg("widgets/action-overlays", "add-normal");
++        m_totalBytesLabel->setVisible(false);
++        m_dirCountLabel->setVisible(false);
++        m_fileCountLabel->setVisible(false);
++        m_plotter->setVisible(false);
++        for (int i = 0; i < 4; i++) {
++            m_layout->removeAt(m_layout->count() - 1);
++        }
++        m_layout->updateGeometry();
++        m_extenderItem->setCollapsed(m_extenderItem->isCollapsed());
++    }
++}
++
++#include "jobwidget.moc"
++
+diff --git a/plasma/generic/applets/notifications/ui/jobwidget.h b/plasma/generic/applets/notifications/ui/jobwidget.h
+new file mode 100644
+index 0000000..b949bac
+--- /dev/null
++++ b/plasma/generic/applets/notifications/ui/jobwidget.h
+@@ -0,0 +1,102 @@
++/***************************************************************************
++ *   Copyright 2008 by Rob Scheepmaker <r.scheepmaker@student.utwente.nl   *
++ *                                                                         *
++ *   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 JOBWIDGET_H
++#define JOBWIDGET_H
++
++#include "../core/job.h"
++
++
++#include <QGraphicsWidget>
++#include <QGraphicsGridLayout>
++
++#include <Plasma/Service>
++#include <Plasma/ExtenderItem>
++#include <plasma/dataengine.h>
++#include <Plasma/PushButton>
++
++namespace Plasma
++{
++    class ExtenderItem;
++    class PushButton;
++    class Label;
++    class Meter;
++    class IconWidget;
++    class SignalPlotter;
++} // namespace Plasma
++
++class Job;
++
++
++class JobWidget : public QGraphicsWidget
++{
++    Q_OBJECT
++
++    public:
++        explicit JobWidget(Job *job, Plasma::ExtenderItem *parent);
++        ~JobWidget();
++
++        void poppedUp(bool shown);
++
++        Job *job() const;
++
++    protected:
++        void resizeEvent(QGraphicsSceneResizeEvent *event);
++        void timerEvent(QTimerEvent *event);
++        void showEvent(QShowEvent *event);
++        void hideEvent(QHideEvent *event);
++
++    private Q_SLOTS:
++        void detailsClicked();
++        void destroyExtenderItem();
++        void scheduleUpdateJob();
++        void updateJobState();
++
++    private:
++        void updateLabels();
++        void updateJob();
++
++        Plasma::ExtenderItem *m_extenderItem;
++        QWeakPointer<Job>m_job;
++
++        Plasma::Meter *m_meter;
++        Plasma::Label *m_fromNameLabel;
++        Plasma::Label *m_fromLabel;
++        Plasma::Label *m_toNameLabel;
++        Plasma::Label *m_toLabel;
++        Plasma::Label *m_totalBytesLabel;
++        Plasma::Label *m_dirCountLabel;
++        Plasma::Label *m_fileCountLabel;
++        Plasma::Label *m_eta;
++        Plasma::IconWidget *m_details;
++        Plasma::SignalPlotter *m_plotter;
++
++        QGraphicsGridLayout *m_layout;
++
++        QString labelName0;
++        QString labelName1;
++        QString label0;
++        QString label1;
++
++        int m_updateTimerId;
++
++        bool m_extenderItemDestroyed;
++};
++
++#endif
+diff --git a/plasma/generic/applets/notifications/ui/notificationgroup.cpp b/plasma/generic/applets/notifications/ui/notificationgroup.cpp
+new file mode 100644
+index 0000000..f27e2c3
+--- /dev/null
++++ b/plasma/generic/applets/notifications/ui/notificationgroup.cpp
+@@ -0,0 +1,239 @@
++/***************************************************************************
++ *   notificationgroup.cpp                                                *
++ *   Copyright (C) 2010 Marco Martin <notmart@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 .        *
++ ***************************************************************************/
++
++#include "notificationgroup.h"
++#include "../core/notification.h"
++#include "notificationwidget.h"
++
++#include <QGraphicsLinearLayout>
++#include <QWidget>
++
++#include <KDebug>
++#include <KIcon>
++#include <KLocale>
++
++#include <Plasma/TabBar>
++#include <Plasma/ExtenderItem>
++
++
++NotificationGroup::NotificationGroup(Plasma::Extender *parent, uint groupId)
++   : Plasma::ExtenderGroup(parent, groupId)
++{
++    setTransient(true);
++    config().writeEntry("type", "notification");
++    setName("notifications");
++    setTitle(i18n("Notifications"));
++    setIcon("dialog-information");
++    showCloseButton();
++
++
++    m_notificationBar = new Plasma::TabBar(this);
++    m_notificationBar->nativeWidget()->setMaximumWidth(400);
++    m_notificationBar->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
++    m_notificationBar->addTab(KIcon("dialog-information"), i18nc("Show all  notifications", "All"));
++    connect(m_notificationBar, SIGNAL(currentChanged(int)), this, SLOT(tabSwitched(int)));
++
++
++    QGraphicsWidget *widget = new QGraphicsWidget(this);
++    QGraphicsLinearLayout *tabsLayout = new QGraphicsLinearLayout(Qt::Horizontal, widget);
++    widget->setContentsMargins(0, 4, 0, 0);
++    tabsLayout->setContentsMargins(0, 0, 0, 0);
++    tabsLayout->addStretch();
++    tabsLayout->addItem(m_notificationBar);
++    tabsLayout->addStretch();
++
++    setWidget(widget);
++    setCollapsed(true);
++    setAutoCollapse(false);
++}
++
++NotificationGroup::~NotificationGroup()
++{
++    m_extenderItemsForNotification.clear();
++    m_notificationForExtenderItems.clear();
++    qDeleteAll(m_notifications);
++}
++
++
++void NotificationGroup::addNotification(Notification *notification)
++{
++    connect(notification, SIGNAL(notificationDestroyed(Notification*)), this, SLOT(removeNotification(Notification*)));
++
++    NotificationWidget *notificationWidget = new NotificationWidget(notification, this);
++    notificationWidget->setTitleBarVisible(false);
++    Plasma::ExtenderItem *extenderItem = new ExtenderItem(extender());
++    extenderItem->setGroup(this, QPointF(0,0));
++    extenderItem->setTransient(true);
++    extenderItem->config().writeEntry("type", "notification");
++    extenderItem->setWidget(notificationWidget);
++    extenderItem->setIcon(QIcon());
++    extenderItem->showCloseButton();
++    connect(extenderItem, SIGNAL(destroyed(Plasma::ExtenderItem*)), this, SLOT(extenderItemDestroyed(Plasma::ExtenderItem*)));
++    connect(notificationWidget, SIGNAL(destroyed()), extenderItem, SLOT(deleteLater()));
++
++    if (!notification->summary().isEmpty()) {
++        extenderItem->setTitle(notification->summary());
++    } else {
++        extenderItem->setTitle(i18n("Notification from %1", notification->applicationName()));
++    }
++
++    m_extenderItemsForNotification[notification] = extenderItem;
++    m_notificationForExtenderItems[extenderItem] = notification;
++    m_notifications.append(notification);
++    m_notificationsForApp[notification->applicationName()].insert(notification);
++    m_appForNotification[notification] = notification->applicationName();
++
++    if (!m_currentFilter.isNull() && m_currentFilter != notification->applicationName()) {
++        extenderItem->setMaximumHeight(0);
++        extenderItem->setVisible(false);
++    }
++
++    //adjust tabbar
++    bool found = false;
++    for (int i = 0; i < m_notificationBar->count(); ++i) {
++        if (m_notificationBar->tabText(i) == notification->applicationName()) {
++            found = true;
++            break;
++        }
++    }
++
++    if (!found) {
++        m_notificationBar->addTab(notification->applicationIcon(), notification->applicationName());
++        if (m_notificationBar->count() > 2) {
++            setCollapsed(false);
++            setAutoCollapse(true);
++        }
++    }
++
++    if (items().count() == 1) {
++        //ensure the notifications group is the last item
++        Plasma::ExtenderGroup *jobGroup = extender()->group("jobGroup");
++        if (jobGroup && jobGroup->isVisible()) {
++            if (extender()->appearance() == Plasma::Extender::TopDownStacked) {
++                setExtender(extender(), QPointF(0,0));
++            } else {
++                setExtender(extender(), jobGroup->geometry().bottomLeft());
++            }
++        }
++    }
++
++    notificationWidget->layout()->activate();
++}
++
++void NotificationGroup::extenderItemDestroyed(Plasma::ExtenderItem *object)
++{
++    if (m_extenderItemsForNotification.isEmpty()) {
++        // either we aren't tracking this notification or else we're being deleted
++        return;
++    }
++
++    Notification *n = m_notificationForExtenderItems.value(object);
++
++    if (n) {
++        m_notificationForExtenderItems.remove(object);
++        removeNotification(n);
++        n->deleteLater();
++    }
++}
++
++void NotificationGroup::removeNotification(Notification *notification)
++{
++    if (m_extenderItemsForNotification.isEmpty()) {
++        // either we aren't tracking this notification or else we're being deleted
++        return;
++    }
++
++    Plasma::ExtenderItem *item = m_extenderItemsForNotification.value(notification);
++    if (item) {
++        m_notificationForExtenderItems.remove(item);
++    }
++
++    m_extenderItemsForNotification.remove(notification);
++    m_notifications.removeAll(notification);
++    QString applicationName = m_appForNotification.value(notification);
++
++    if (applicationName.isEmpty()) {
++        return;
++    }
++
++    m_appForNotification.remove(notification);
++
++    if (m_notificationsForApp.contains(applicationName)) {
++        m_notificationsForApp[applicationName].remove(notification);
++        if (m_notificationsForApp[applicationName].isEmpty()) {
++            m_notificationsForApp.remove(applicationName);
++        }
++    }
++
++    //clear tabbar
++    for (int i = 1; i < m_notificationBar->count(); ++i) {
++        if (!m_notificationsForApp.contains(m_notificationBar->tabText(i))) {
++            if (i == m_notificationBar->currentIndex()) {
++                m_notificationBar->setCurrentIndex(0);
++            }
++            m_notificationBar->removeTab(i);
++            //2 tabs means just "all" and a single application, no need to display it
++            if (m_notificationBar->count() <= 2) {
++                setCollapsed(true);
++                setAutoCollapse(false);
++            }
++        }
++    }
++
++    if (m_notifications.count() == 0) {
++        emit scrollerEmpty();
++        return;
++    }
++}
++
++
++void NotificationGroup::filterNotificationsByOwner(const QString &owner)
++{
++    foreach (Notification *notification, m_notifications) {
++        Plasma::ExtenderItem *item = m_extenderItemsForNotification.value(notification);
++
++        if (!item || item->group() != this) {
++            continue;
++        }
++
++        if (owner.isNull() || notification->applicationName() == owner) {
++            item->setMaximumHeight(QWIDGETSIZE_MAX);
++            item->setVisible(true);
++        } else {
++            item->setMaximumHeight(0);
++            item->setVisible(false);
++        }
++    }
++
++    m_currentFilter = owner;
++}
++
++void NotificationGroup::tabSwitched(int index)
++{
++    if (index > 0) {
++        filterNotificationsByOwner(m_notificationBar->tabText(index));
++    } else {
++        filterNotificationsByOwner(QString());
++    }
++}
++
++
++#include "notificationgroup.moc"
++
+diff --git a/plasma/generic/applets/notifications/ui/notificationgroup.h b/plasma/generic/applets/notifications/ui/notificationgroup.h
+new file mode 100644
+index 0000000..ffa2112
+--- /dev/null
++++ b/plasma/generic/applets/notifications/ui/notificationgroup.h
+@@ -0,0 +1,85 @@
++/***************************************************************************
++ *   notificationgroup.h                                                *
++ *   Copyright (C) 2010 Marco Martin <notmart@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 NOTIFICATIONGROUP_H
++#define NOTIFICATIONGROUP_H
++
++
++#include <Plasma/Extender>
++#include <Plasma/ExtenderGroup>
++
++
++#include <Plasma/Plasma>
++
++class QGraphicsLinearLayout;
++
++namespace Plasma
++{
++    class ExtenderItem;
++    class TabBar;
++    class Extender;
++}
++
++class NotificationWidget;
++class Notification;
++
++class NotificationGroup : public Plasma::ExtenderGroup
++{
++    Q_OBJECT
++
++public:
++    NotificationGroup(Plasma::Extender *parent, uint groupId = 0);
++    ~NotificationGroup();
++
++    void addNotification(Notification *notification);
++
++    void filterNotificationsByOwner(const QString &owner);
++
++
++public Q_SLOTS:
++    void removeNotification(Notification *notification);
++
++protected Q_SLOTS:
++    void tabSwitched(int index);
++    void extenderItemDestroyed(Plasma::ExtenderItem *object);
++
++Q_SIGNALS:
++    void scrollerEmpty();
++
++private:
++    Plasma::TabBar *m_notificationBar;
++
++    //housekeeping data structures
++    QList<Notification *>m_notifications;
++
++    //Those two are kept on both ways since we are not sure the thing
++    //contained in the hash is still valid so we couldn't obtain the
++    //info to remove the proper key, unless both ways are stored
++    QHash<QString, QSet<Notification *> > m_notificationsForApp;
++    QHash<Notification *, QString> m_appForNotification;
++
++    QHash<Notification *, Plasma::ExtenderItem *>m_extenderItemsForNotification;
++    QHash<Plasma::ExtenderItem *, Notification *>m_notificationForExtenderItems;
++
++    QString m_currentFilter;
++};
++
++
++#endif
+diff --git a/plasma/generic/applets/notifications/ui/notifications.cpp b/plasma/generic/applets/notifications/ui/notifications.cpp
+new file mode 100644
+index 0000000..eea1d72
+--- /dev/null
++++ b/plasma/generic/applets/notifications/ui/notifications.cpp
+@@ -0,0 +1,434 @@
++/***************************************************************************
++ *   applet.cpp                                                            *
++ *                                                                         *
++ *   Copyright (C) 2008 Jason Stubbs <jasonbstubbs@gmail.com>              *
++ *   Copyright (C) 2008 Sebastian Sauer                                    *
++ *   Copyright (C) 2010 Marco Martin <notmart@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 .        *
++ ***************************************************************************/
++
++#include "notifications.h"
++
++#include <QtGui/QApplication>
++#include <QtGui/QGraphicsLayout>
++#include <QtGui/QGraphicsLinearLayout>
++#include <QtGui/QVBoxLayout>
++#include <QtGui/QIcon>
++#include <QtGui/QLabel>
++#include <QtGui/QListWidget>
++#include <QtGui/QTreeWidget>
++#include <QtGui/QCheckBox>
++#include <QtGui/QPainter>
++#include <QtGui/QX11Info>
++#include <QtCore/QProcess>
++
++
++#include <KConfigDialog>
++#include <KComboBox>
++#include <KWindowSystem>
++#include <KIconLoader>
++
++#include <Solid/Device>
++
++#include <plasma/extender.h>
++#include <plasma/extenderitem.h>
++#include <plasma/extendergroup.h>
++#include <plasma/framesvg.h>
++#include <plasma/widgets/label.h>
++#include <plasma/theme.h>
++#include <plasma/dataenginemanager.h>
++#include <plasma/dataengine.h>
++#include <Plasma/TabBar>
++#include <Plasma/Animator>
++#include <Plasma/Animation>
++#include <Plasma/Containment>
++#include <Plasma/Corona>
++#include <Plasma/Dialog>
++#include <Plasma/WindowEffects>
++
++#include "config-notifications.h"
++#ifdef HAVE_LIBXSS      // Idle detection.
++#include <X11/Xlib.h>
++#include <X11/Xutil.h>
++#include <X11/extensions/scrnsaver.h>
++#include <fixx11h.h>
++#endif // HAVE_LIBXSS
++
++#include "../core/notificationsmanager.h"
++#include "../core/notification.h"
++#include "../core/completedjobnotification.h"
++#include "busywidget.h"
++#include "jobwidget.h"
++#include "jobtotalswidget.h"
++#include "notificationgroup.h"
++#include "notificationstack.h"
++#include "stackdialog.h"
++
++
++K_EXPORT_PLASMA_APPLET(notifications, Notifications)
++
++
++Notifications::Notifications(QObject *parent, const QVariantList &arguments)
++    : Plasma::PopupApplet(parent, arguments),
++      m_jobSummaryWidget(0),
++      m_autoHidePopup(true),
++      m_notificationStack(0),
++      m_notificationStackDialog(0),
++      m_standaloneJobSummaryWidget(0),
++      m_standaloneJobSummaryDialog(0),
++      m_busyWidget(0)
++{
++    m_manager = new Manager(this);
++
++    setPopupIcon(QIcon());
++    setPassivePopup(true);
++    setAspectRatioMode(Plasma::IgnoreAspectRatio);
++    setBackgroundHints(NoBackground);
++    setHasConfigurationInterface(true);
++    setMinimumSize(KIconLoader::SizeSmall, KIconLoader::SizeSmall);
++}
++
++Notifications::~Notifications()
++{
++    // stop listening to the manager
++    disconnect(m_manager, 0, this, 0);
++    if (m_notificationStackDialog) {
++        disconnect(m_notificationStackDialog, 0, this, 0);
++    }
++
++    foreach (Notification *notification, m_manager->notifications()) {
++        // we don't want a destroyed managed after the destruction of manager
++        disconnect(notification, 0, this, 0);
++    }
++
++    //has to be deleted before the manager because it will access it
++    delete m_busyWidget;
++    delete m_notificationStackDialog;
++    delete m_standaloneJobSummaryDialog;
++}
++
++void Notifications::init()
++{
++    extender()->setEmptyExtenderMessage(i18n("No notifications and no jobs"));
++
++    m_busyWidget = new BusyWidget(this, m_manager);
++    connect(m_busyWidget, SIGNAL(clicked()), this, SLOT(togglePopup()));
++    QGraphicsLinearLayout *lay = new QGraphicsLinearLayout(this);
++    setContentsMargins(0, 0, 0, 0);
++    lay->setContentsMargins(0, 0, 0, 0);
++    lay->addItem(m_busyWidget);
++
++    configChanged();
++    setStatus(Plasma::PassiveStatus);
++}
++
++void Notifications::configChanged()
++{
++    KConfigGroup cg = config();
++
++    m_autoHidePopup = cg.readEntry("AutoHidePopup", true);
++    if (m_notificationStackDialog) {
++        m_notificationStackDialog->setAutoHide(m_autoHidePopup);
++    }
++
++    if (cg.readEntry("ShowJobs", true)) {
++        createJobGroups();
++
++        m_manager->registerJobProtocol();
++        connect(m_manager, SIGNAL(jobAdded(Job*)),
++                this, SLOT(addJob(Job*)), Qt::UniqueConnection);
++        connect(m_manager, SIGNAL(jobRemoved(Job*)),
++                this, SLOT(finishJob(Job*)), Qt::UniqueConnection);
++    } else {
++        delete extender()->group("jobGroup");
++        m_manager->unregisterJobProtocol();
++        disconnect(m_manager, SIGNAL(jobAdded(Job*)),
++                   this, SLOT(addJob(Job*)));
++        disconnect(m_manager, SIGNAL(jobRemoved(Job*)),
++                   this, SLOT(finishJob(Job*)));
++    }
++
++    if (cg.readEntry("ShowNotifications", true)) {
++        m_manager->registerNotificationProtocol();
++        connect(m_manager, SIGNAL(notificationAdded(Notification*)),
++                this, SLOT(addNotification(Notification*)), Qt::UniqueConnection);
++    } else {
++        m_manager->unregisterNotificationProtocol();
++        disconnect(m_manager, SIGNAL(notificationAdded(Notification*)),
++                   this, SLOT(addNotification(Notification*)));
++    }
++}
++
++void Notifications::syncNotificationBarNeeded()
++{
++    if (!m_manager) {
++        return;
++    }
++
++    if (m_manager->notifications().isEmpty()) {
++        if (extender()->item("notifications")) {
++            //don't let him in the config file
++            extender()->item("notifications")->destroy();
++        }
++    } else if (!extender()->item("notifications")) {
++        m_notificationGroup = new NotificationGroup(extender());
++    }
++}
++
++Manager *Notifications::manager() const
++{
++    return m_manager;
++}
++
++void Notifications::createConfigurationInterface(KConfigDialog *parent)
++{
++    if (!m_notificationInterface) {
++        KConfigGroup cg = config();
++        m_notificationInterface = new QWidget();
++
++        m_notificationUi.setupUi(m_notificationInterface.data());
++
++        m_notificationUi.showJobs->setChecked(cg.readEntry("ShowJobs", true));
++        m_notificationUi.showNotifications->setChecked(cg.readEntry("ShowNotifications", true));
++
++        m_notificationUi.autoHide->setChecked(config().readEntry("AutoHidePopup", true));
++
++        connect(parent, SIGNAL(applyClicked()), this, SLOT(configAccepted()));
++        connect(parent, SIGNAL(okClicked()), this, SLOT(configAccepted()));
++
++        parent->addPage(m_notificationInterface.data(), i18n("Information"),
++                        "preferences-desktop-notification",
++                        i18n("Choose which information to show"));
++
++        connect(m_notificationUi.showNotifications, SIGNAL(stateChanged(int)), parent, SLOT(settingsModified()));
++        connect(m_notificationUi.showJobs, SIGNAL(stateChanged(int)), parent, SLOT(settingsModified()));
++        connect(m_notificationUi.autoHide, SIGNAL(stateChanged(int)), parent, SLOT(settingsModified()));
++    }
++}
++
++void Notifications::configAccepted()
++{
++    //TODO put in a single page
++    //cg.writeEntry("AutoHidePopup", m_autoHideUi.autoHide->isChecked());
++
++    KConfigGroup cg = config();
++    cg.writeEntry("ShowJobs", m_notificationUi.showJobs->isChecked());
++    cg.writeEntry("ShowNotifications", m_notificationUi.showNotifications->isChecked());
++    cg.writeEntry("AutoHidePopup", m_notificationUi.autoHide->isChecked());
++
++    emit configNeedsSaving();
++}
++
++void Notifications::addNotification(Notification *notification)
++{
++    syncNotificationBarNeeded();
++
++    //At this point we are sure the pointer is valid
++    m_notificationGroup.data()->addNotification(notification);
++
++
++    if (isPopupShowing()) {
++        return;
++    }
++
++    if (!m_notificationStack) {
++        m_notificationStack = new NotificationStack(this);
++        if (containment() && containment()->corona()) {
++            containment()->corona()->addOffscreenWidget(m_notificationStack);
++        }
++        m_notificationStackDialog = new StackDialog;
++        m_notificationStackDialog->setNotificationStack(m_notificationStack);
++        m_notificationStackDialog->setApplet(this);
++        connect(m_notificationStack, SIGNAL(stackEmpty()), m_notificationStackDialog, SLOT(hide()));
++        connect(m_notificationStack, SIGNAL(showRequested()), m_notificationStackDialog, SLOT(perhapsShow()));
++        m_notificationStackDialog->setAutoHide(m_autoHidePopup);
++
++        if (m_standaloneJobSummaryDialog) {
++            m_notificationStackDialog->setWindowToTile(m_standaloneJobSummaryDialog);
++        }
++    }
++
++
++    m_notificationStack->addNotification(notification);
++    m_notificationStackDialog->syncToGraphicsWidget();
++
++    if (containment() && containment()->corona()) {
++        if (!m_notificationStackDialog->isVisible()) {
++            m_notificationStack->setCurrentNotification(notification);
++        }
++
++        KWindowSystem::setOnAllDesktops(m_notificationStackDialog->winId(), true);
++        m_notificationStackDialog->perhapsShow();
++    }
++
++    Plasma::Animation *pulse = Plasma::Animator::create(Plasma::Animator::PulseAnimation, m_busyWidget);
++    pulse->setTargetWidget(m_busyWidget);
++    pulse->start(QAbstractAnimation::DeleteWhenStopped);
++}
++
++void Notifications::addJob(Job *job)
++{
++    Plasma::ExtenderGroup *group = extender()->group("jobGroup");
++
++    Plasma::ExtenderItem *extenderItem = new Plasma::ExtenderItem(extender());
++    extenderItem->setTransient(true);
++    extenderItem->config().writeEntry("type", "job");
++    extenderItem->setWidget(new JobWidget(job, extenderItem));
++
++    extenderItem->setGroup(group);
++
++    if (group) {
++        group->setCollapsed(group->items().count() < 2);
++    }
++
++    if (isPopupShowing()) {
++        return;
++    }
++
++    //show the tiny standalone overview
++    if (!m_standaloneJobSummaryWidget) {
++        m_standaloneJobSummaryDialog = new Plasma::Dialog();
++        KWindowSystem::setType(m_standaloneJobSummaryDialog->winId(), NET::Dock);
++        if (m_notificationStackDialog) {
++            m_notificationStackDialog->setWindowToTile(m_standaloneJobSummaryDialog);
++        }
++
++        m_standaloneJobSummaryWidget = new JobTotalsWidget(m_manager->jobTotals(), this);
++        if (containment() && containment()->corona()) {
++            containment()->corona()->addOffscreenWidget(m_standaloneJobSummaryWidget);
++        }
++        m_standaloneJobSummaryDialog->setGraphicsWidget(m_standaloneJobSummaryWidget);
++        //FIXME:sizing hack and layout issues..
++        m_standaloneJobSummaryWidget->resize(m_standaloneJobSummaryWidget->size().width(), 32);
++        m_standaloneJobSummaryWidget->setMaximumHeight(32);
++        m_standaloneJobSummaryWidget->setMinimumHeight(32);
++        m_standaloneJobSummaryWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
++    }
++
++    m_standaloneJobSummaryDialog->syncToGraphicsWidget();
++    KWindowSystem::setState(m_standaloneJobSummaryDialog->winId(), NET::KeepBelow);
++
++    if (containment() && containment()->corona()) {
++        m_standaloneJobSummaryDialog->move(containment()->corona()->popupPosition(this, m_standaloneJobSummaryDialog->size()));
++        m_standaloneJobSummaryDialog->show();
++        Plasma::WindowEffects::slideWindow(m_standaloneJobSummaryDialog, location());
++
++        KWindowSystem::setOnAllDesktops(m_standaloneJobSummaryDialog->winId(), true);
++        KWindowSystem::clearState(m_standaloneJobSummaryDialog->winId(), NET::KeepAbove|NET::StaysOnTop);
++
++        KWindowSystem::setState(m_standaloneJobSummaryDialog->winId(), NET::SkipTaskbar|NET::SkipPager);
++        KWindowSystem::raiseWindow(m_standaloneJobSummaryDialog->winId());
++        KWindowSystem::setOnAllDesktops(m_standaloneJobSummaryDialog->winId(), true);
++    }
++}
++
++void Notifications::initExtenderItem(Plasma::ExtenderItem *extenderItem)
++{
++    if (extenderItem->name() == "jobGroup") {
++        m_jobSummaryWidget = new JobTotalsWidget(m_manager->jobTotals(), extenderItem);
++        extenderItem->setWidget(m_jobSummaryWidget);
++        Plasma::ExtenderGroup *group = qobject_cast<Plasma::ExtenderGroup*>(extenderItem);
++        if (group) {
++            extenderItem->setCollapsed(!group->isGroupCollapsed());
++        }
++        return;
++    }
++
++    if (extenderItem->config().readEntry("type", QString()) == "job") {
++        extenderItem->setWidget(new JobWidget(0, extenderItem));
++    } else {
++        //unknown type, this should never happen
++        extenderItem->destroy();
++    }
++
++}
++
++void Notifications::popupEvent(bool show)
++{
++    if (m_busyWidget) {
++        m_busyWidget->suppressToolTips(show);
++    }
++
++    //decide about showing the tiny progressbar or not
++    if (m_standaloneJobSummaryDialog) {
++        if (show || !m_manager->jobs().isEmpty()) {
++            if (!show) {
++                KWindowSystem::raiseWindow(m_standaloneJobSummaryDialog->winId());
++                KWindowSystem::setState(m_standaloneJobSummaryDialog->winId(), NET::SkipTaskbar|NET::SkipPager);
++                KWindowSystem::setState(m_standaloneJobSummaryDialog->winId(), NET::KeepBelow);
++            } else {
++                m_standaloneJobSummaryDialog->hide();
++            }
++        }
++    }
++
++    if (m_notificationStackDialog && show) {
++        m_notificationStackDialog->hide();
++    }
++
++    Plasma::ExtenderGroup * jobGroup = extender()->group("jobGroup");
++    if (!jobGroup) {
++        return;
++    }
++
++    foreach (Plasma::ExtenderItem *item, jobGroup->items()) {
++        JobWidget *job = dynamic_cast<JobWidget *>(item->widget());
++        if (job) {
++            job->poppedUp(show);
++        }
++    }
++}
++
++void Notifications::finishJob(Job *job)
++{
++    //finished all jobs? hide the mini progressbar
++    if (m_standaloneJobSummaryDialog && m_manager->jobs().isEmpty()) {
++        m_standaloneJobSummaryDialog->hide();
++    }
++
++    //create a fake notification
++    CompletedJobNotification *notification = new CompletedJobNotification(this);
++    notification->setJob(job);
++    m_manager->addNotification(notification);
++
++    Plasma::ExtenderGroup *group = extender()->group("jobGroup");
++    if (group) {
++        // < 3 because the second still hasn't been removed from the extendergroup
++        group->setCollapsed(!group->isGroupCollapsed() && group->items().count() < 3);
++    }
++}
++
++void Notifications::open(const QString &url)
++{
++    //kDebug() << "open " << url;
++    QProcess::startDetached("kde-open", QStringList() << url);
++}
++
++void Notifications::createJobGroups()
++{
++    if (!extender()->hasItem("jobGroup")) {
++        Plasma::ExtenderGroup *extenderGroup = new Plasma::ExtenderGroup(extender());
++        extenderGroup->setName("jobGroup");
++        initExtenderItem(extenderGroup);
++        extenderGroup->setAutoHide(true);
++    } else if (extender()->group("jobGroup")) {
++        extender()->group("jobGroup")->setAutoHide(true);
++    }
++}
++
++
++#include "notifications.moc"
+diff --git a/plasma/generic/applets/notifications/ui/notifications.h b/plasma/generic/applets/notifications/ui/notifications.h
+new file mode 100644
+index 0000000..827b28e
+--- /dev/null
++++ b/plasma/generic/applets/notifications/ui/notifications.h
+@@ -0,0 +1,101 @@
++/***************************************************************************
++ *   applet.h                                                              *
++ *                                                                         *
++ *   Copyright (C) 2008 Jason Stubbs <jasonbstubbs@gmail.com>              *
++ *   Copyright (C) 2010 Marco Martin <notmart@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 NOTIFICATIONS_H
++#define NOTIFICATIONS_H
++
++#include <plasma/popupapplet.h>
++
++#include "ui_notificationsconfig.h"
++
++
++namespace Plasma
++{
++class ExtenderItem;
++class TabBar;
++class Dialog;
++}
++
++class NotificationWidget;
++class StackDialog;
++
++
++class Job;
++class JobTotalsWidget;
++class Manager;
++class Notification;
++class NotificationGroup;
++class NotificationStack;
++class BusyWidget;
++
++class Notifications : public Plasma::PopupApplet
++{
++    Q_OBJECT
++
++public:
++    explicit Notifications(QObject *parent, const QVariantList &arguments = QVariantList());
++    ~Notifications();
++
++    void init();
++    Manager *manager() const;
++
++protected:
++    void createConfigurationInterface(KConfigDialog *parent);
++    void initExtenderItem(Plasma::ExtenderItem *extenderItem);
++    void configChanged();
++
++    void popupEvent(bool show);
++
++private slots:
++    void configAccepted();
++    void addNotification(Notification *notification);
++    void addJob(Job *job);
++    void finishJob(Job *job);
++    void open(const QString &url);
++    void syncNotificationBarNeeded();
++
++private:
++    void createJobGroups();
++
++    Manager *m_manager;
++    static int s_managerUsage;
++
++    QWeakPointer<QWidget> m_notificationInterface;
++    QDateTime m_lastActivity;
++
++    JobTotalsWidget *m_jobSummaryWidget;
++    bool m_autoHidePopup;
++
++    QWeakPointer<NotificationGroup> m_notificationGroup;
++    NotificationStack *m_notificationStack;
++    StackDialog *m_notificationStackDialog;
++    JobTotalsWidget *m_standaloneJobSummaryWidget;
++    Plasma::Dialog *m_standaloneJobSummaryDialog;
++
++    BusyWidget *m_busyWidget;
++
++    Ui::NotificationsConfig m_notificationUi;
++};
++
++
++
++#endif
+diff --git a/plasma/generic/applets/notifications/ui/notificationsconfig.ui b/plasma/generic/applets/notifications/ui/notificationsconfig.ui
+new file mode 100644
+index 0000000..aaa6a82
+--- /dev/null
++++ b/plasma/generic/applets/notifications/ui/notificationsconfig.ui
+@@ -0,0 +1,114 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<ui version="4.0">
++ <class>NotificationsConfig</class>
++ <widget class="QWidget" name="ProtocolsConfig">
++  <property name="geometry">
++   <rect>
++    <x>0</x>
++    <y>0</y>
++    <width>213</width>
++    <height>236</height>
++   </rect>
++  </property>
++  <layout class="QFormLayout" name="formLayout">
++   <property name="fieldGrowthPolicy">
++    <enum>QFormLayout::ExpandingFieldsGrow</enum>
++   </property>
++   <item row="0" column="0" colspan="2">
++    <widget class="QLabel" name="label_2">
++     <property name="font">
++      <font>
++       <weight>75</weight>
++       <bold>true</bold>
++      </font>
++     </property>
++     <property name="text">
++      <string>Pop Up Notices</string>
++     </property>
++    </widget>
++   </item>
++   <item row="2" column="0">
++    <widget class="QLabel" name="label_4">
++     <property name="text">
++      <string>Application notifications</string>
++     </property>
++     <property name="buddy">
++      <cstring>showNotifications</cstring>
++     </property>
++    </widget>
++   </item>
++   <item row="2" column="1">
++    <widget class="QCheckBox" name="showNotifications">
++     <property name="text">
++      <string/>
++     </property>
++    </widget>
++   </item>
++   <item row="4" column="0">
++    <widget class="QLabel" name="label_5">
++     <property name="text">
++      <string>File transfers and other jobs</string>
++     </property>
++     <property name="buddy">
++      <cstring>showJobs</cstring>
++     </property>
++    </widget>
++   </item>
++   <item row="4" column="1">
++    <widget class="QCheckBox" name="showJobs">
++     <property name="text">
++      <string/>
++     </property>
++    </widget>
++   </item>
++   <item row="8" column="0">
++    <spacer name="verticalSpacer">
++     <property name="orientation">
++      <enum>Qt::Vertical</enum>
++     </property>
++     <property name="sizeType">
++      <enum>QSizePolicy::Fixed</enum>
++     </property>
++     <property name="sizeHint" stdset="0">
++      <size>
++       <width>20</width>
++       <height>6</height>
++      </size>
++     </property>
++    </spacer>
++   </item>
++   <item row="9" column="0" colspan="2">
++    <widget class="QLabel" name="label_3">
++     <property name="font">
++      <font>
++       <weight>75</weight>
++       <bold>true</bold>
++      </font>
++     </property>
++     <property name="text">
++      <string>Popup</string>
++     </property>
++    </widget>
++   </item>
++   <item row="10" column="1">
++    <widget class="QCheckBox" name="autoHide">
++     <property name="text">
++      <string/>
++     </property>
++    </widget>
++   </item>
++   <item row="10" column="0">
++    <widget class="QLabel" name="label_10">
++     <property name="text">
++      <string>Automatically hide</string>
++     </property>
++     <property name="buddy">
++      <cstring>autoHide</cstring>
++     </property>
++    </widget>
++   </item>
++  </layout>
++ </widget>
++ <resources/>
++ <connections/>
++</ui>
+diff --git a/plasma/generic/applets/notifications/ui/notificationstack.cpp b/plasma/generic/applets/notifications/ui/notificationstack.cpp
+new file mode 100644
+index 0000000..f0fc52e
+--- /dev/null
++++ b/plasma/generic/applets/notifications/ui/notificationstack.cpp
+@@ -0,0 +1,233 @@
++/***************************************************************************
++ *   notificationstack.cpp                                                *
++ *   Copyright (C) 2010 Marco Martin <notmart@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 .        *
++ ***************************************************************************/
++
++#include "notificationstack.h"
++#include "../core/notification.h"
++#include "notificationwidget.h"
++
++#include <QGraphicsLinearLayout>
++#include <QTimer>
++
++#include <KDebug>
++#include <KGlobalSettings>
++
++#include <Plasma/FrameSvg>
++#include <Plasma/Dialog>
++
++NotificationStack::NotificationStack(QGraphicsItem *parent)
++   : QGraphicsWidget(parent),
++     m_size(4),
++     m_underMouse(false)
++{
++    m_mainLayout = new QGraphicsLinearLayout(Qt::Vertical, this);
++    m_canDismissTimer = new QTimer(this);
++    m_canDismissTimer->setSingleShot(true);
++
++    m_delayedRemoveTimer = new QTimer(this);
++    m_delayedRemoveTimer->setSingleShot(true);
++    connect(m_delayedRemoveTimer, SIGNAL(timeout()), this, SLOT(popNotification()));
++
++    setAcceptsHoverEvents(true);
++}
++
++NotificationStack::~NotificationStack()
++{
++}
++
++void NotificationStack::addNotification(Notification *notification)
++{
++    m_canDismissTimer->start(1000);
++    connect(notification, SIGNAL(notificationDestroyed(Notification*)), this, SLOT(removeNotification(Notification*)), Qt::UniqueConnection);
++    connect(notification, SIGNAL(expired(Notification*)), this, SLOT(delayedRemoveNotification(Notification*)),  Qt::UniqueConnection);
++    connect(notification, SIGNAL(changed(Notification*)), this, SLOT(notificationChanged(Notification*)), Qt::UniqueConnection);
++
++    NotificationWidget *notificationWidget = new NotificationWidget(notification, this);
++    notificationWidget->installEventFilter(this);
++    notificationWidget->setAcceptsHoverEvents(this);
++    connect(notificationWidget, SIGNAL(actionTriggered(Notification*)), this, SLOT(removeNotification(Notification*)));
++
++    m_notificationWidgets[notification] = notificationWidget;
++    m_notifications.append(notification);
++
++    if (m_notifications.size() > 1) {
++        notificationWidget->setCollapsed(true, false);
++    } else {
++        m_currentNotificationWidget = notificationWidget;
++    }
++
++    if (m_notifications.size() > m_size) {
++        bool found = false;
++
++        //try to kill the oldest notification of the same app
++        foreach (Notification *notif, m_notifications) {
++            if (notif->applicationName() == notification->applicationName()) {
++                m_notificationWidgets[notif]->deleteLater();
++                m_notificationWidgets.remove(notif);
++                m_notifications.removeAll(notif);
++                found = true;
++                break;
++            }
++        }
++        //or kill the oldest one
++        if (!found) {
++            Notification *notif = m_notifications.first();
++            m_notificationWidgets[notif]->deleteLater();
++            m_notificationWidgets.remove(notif);
++            m_notifications.pop_front();
++        }
++    }
++
++    m_mainLayout->insertItem(0, notificationWidget);
++    m_mainLayout->activate();
++    updateGeometry();
++    resize(size().width(), effectiveSizeHint(Qt::MinimumSize).height());
++    emit updateRequested();
++}
++
++void NotificationStack::notificationChanged(Notification *notification)
++{
++    //if it was gone away put in on the stack again
++    if (!m_notificationWidgets.contains(notification)) {
++        addNotification(notification);
++    }
++    emit showRequested();
++}
++
++void NotificationStack::removeNotification(Notification *notification)
++{
++    NotificationWidget *nw = m_notificationWidgets.value(notification);
++    if (nw) {
++        nw->deleteLater();
++    }
++    m_mainLayout->removeItem(nw);
++    m_notificationWidgets.remove(notification);
++    m_notifications.removeAll(notification);
++
++    if (m_notifications.count() > 0) {
++        setCurrentNotification(m_notifications.first());
++    }
++
++    if (m_notifications.count() == 0) {
++        emit stackEmpty();
++    }
++
++    updateGeometry();
++    resize(size().width(), sizeHint(Qt::MinimumSize, QSizeF()).height());
++    emit updateRequested();
++}
++
++void NotificationStack::delayedRemoveNotification(Notification *notification)
++{
++    m_notificationsToRemove.append(notification);
++    if (!m_underMouse) {
++        m_delayedRemoveTimer->start(1000);
++    }
++}
++
++void NotificationStack::setCurrentNotification(Notification *notification)
++{
++    if (m_notificationWidgets.contains(notification)) {
++        if (m_currentNotificationWidget) {
++            m_currentNotificationWidget.data()->setCollapsed(true);
++        }
++        m_currentNotificationWidget = m_notificationWidgets.value(notification);
++        m_currentNotificationWidget.data()->setCollapsed(false);
++    }
++}
++
++void NotificationStack::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
++{
++    Q_UNUSED(event)
++
++    m_underMouse = true;
++    m_delayedRemoveTimer->stop();
++}
++
++void NotificationStack::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
++{
++    Q_UNUSED(event)
++
++    m_underMouse = false;
++    m_delayedRemoveTimer->start(1000);
++}
++
++void NotificationStack::mousePressEvent(QGraphicsSceneMouseEvent *event)
++{
++    event->accept();
++}
++
++void NotificationStack::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
++{
++    Q_UNUSED(event)
++
++    if (!m_canDismissTimer->isActive() &&
++        QPointF(event->buttonDownScenePos(event->button()) - event->scenePos()).manhattanLength() < KGlobalSettings::dndEventDelay()) {
++        emit hideRequested();
++    }
++}
++
++NotificationWidget *NotificationStack::currentNotificationWidget() const
++{
++    if (m_currentNotificationWidget) {
++        return m_currentNotificationWidget.data();
++    } else {
++        return 0;
++    }
++}
++
++bool NotificationStack::eventFilter(QObject *watched, QEvent *event)
++{
++    NotificationWidget *nw = qobject_cast<NotificationWidget *>(watched);
++
++    if (!nw) {
++        return false;
++    }
++
++    if (event->type() == QEvent::GraphicsSceneHoverEnter) {
++        if (m_currentNotificationWidget && m_currentNotificationWidget.data() == nw) {
++            return false;
++        } else if (m_currentNotificationWidget) {
++            m_currentNotificationWidget.data()->setCollapsed(true);
++        }
++        nw->setCollapsed(false);
++        m_currentNotificationWidget = nw;
++        m_canDismissTimer->start(1000);
++    } else if (event->type() == QEvent::GraphicsSceneMove) {
++        emit updateRequested();
++    }
++
++
++    return false;
++}
++
++void NotificationStack::popNotification()
++{
++    if (m_notificationsToRemove.isEmpty()) {
++        return;
++    }
++
++    Notification *notif = m_notificationsToRemove.first();
++    removeNotification(notif);
++    m_notificationsToRemove.pop_front();
++    m_delayedRemoveTimer->start(1000);
++}
++
++
++#include "notificationstack.moc"
+diff --git a/plasma/generic/applets/notifications/ui/notificationstack.h b/plasma/generic/applets/notifications/ui/notificationstack.h
+new file mode 100644
+index 0000000..783e5ae
+--- /dev/null
++++ b/plasma/generic/applets/notifications/ui/notificationstack.h
+@@ -0,0 +1,81 @@
++/***************************************************************************
++ *   notificationscroller.h                                                *
++ *   Copyright (C) 2010 Marco Martin <notmart@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 NOTIFICATIONSTACK_H
++#define NOTIFICATIONSTACK_H
++
++#include <QGraphicsWidget>
++
++class QGraphicsLinearLayout;
++class QTimer;
++
++class NotificationWidget;
++
++class Notification;
++
++class NotificationStack : public QGraphicsWidget
++{
++    Q_OBJECT
++
++public:
++    NotificationStack(QGraphicsItem *parent = 0);
++    ~NotificationStack();
++
++    void addNotification(Notification *notification);
++
++    //TODO:accessor
++    void setCurrentNotification(Notification *notification);
++
++    NotificationWidget *currentNotificationWidget() const;
++
++protected:
++    void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
++    void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
++    void mousePressEvent(QGraphicsSceneMouseEvent *event);
++    void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
++    bool eventFilter(QObject *watched, QEvent *event);
++
++public Q_SLOTS:
++    void removeNotification(Notification *notification);
++    void delayedRemoveNotification(Notification *notification);
++
++private Q_SLOTS:
++    void popNotification();
++    void notificationChanged(Notification *notification);
++
++Q_SIGNALS:
++    void stackEmpty();
++    void updateRequested();
++    void hideRequested();
++    void showRequested();
++
++private:
++    QList<Notification *> m_notifications;
++    QList<Notification *> m_notificationsToRemove;
++    QHash<Notification *, NotificationWidget *> m_notificationWidgets;
++    QGraphicsLinearLayout *m_mainLayout;
++    int m_size;
++    bool m_underMouse;
++    QWeakPointer<NotificationWidget> m_currentNotificationWidget;
++    QTimer *m_delayedRemoveTimer;
++    QTimer *m_canDismissTimer;
++};
++
++#endif
+diff --git a/plasma/generic/applets/notifications/ui/notificationwidget.cpp b/plasma/generic/applets/notifications/ui/notificationwidget.cpp
+new file mode 100644
+index 0000000..02ed38f
+--- /dev/null
++++ b/plasma/generic/applets/notifications/ui/notificationwidget.cpp
+@@ -0,0 +1,486 @@
++/***************************************************************************
++ *   notificationwidget.cpp                                                *
++ *                                                                         *
++ *   Copyright (C) 2008 Dmitry Suzdalev <dimsuz@gmail.com>                 *
++ *   Copyright (C) 2008 Rob Scheepmaker <r.scheepmaker@student.utwente.nl> *
++ *   Copyright (C) 2008 Jason Stubbs <jasonbstubbs@gmail.com>              *
++ *   Copyright (C) 2010 Marco Martin <notmart@gmail.com>                   *
++ *                                                                         *
++ *   This program 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 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 Library General Public License for more details.                  *
++ *                                                                         *
++ *   You should have received a copy of the GNU Library General Public     *
++ *   License along with this library; if not, write to the                 *
++ *   Free Software Foundation, Inc.,                                       *
++ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA .        *
++ ***************************************************************************/
++
++#include "notificationwidget.h"
++
++#include <QSignalMapper>
++
++#include <QtGui/QGraphicsLinearLayout>
++#include <QtGui/QGraphicsGridLayout>
++#include <QtGui/QTextDocument>
++#include <QtGui/QFontMetrics>
++#include <QtGui/QGraphicsSceneResizeEvent>
++#include <QtGui/QPainter>
++#include <QAction>
++#include <QLabel>
++#include <QPropertyAnimation>
++#include <QParallelAnimationGroup>
++
++#include <KColorScheme>
++#include <KPushButton>
++#include <KTextBrowser>
++
++#include <Plasma/Animation>
++#include <Plasma/Animator>
++#include <Plasma/Frame>
++#include <Plasma/IconWidget>
++#include <Plasma/Label>
++#include <Plasma/PushButton>
++#include <Plasma/TextBrowser>
++#include <Plasma/Theme>
++
++class NotificationWidgetPrivate
++{
++public:
++    NotificationWidgetPrivate(NotificationWidget *q)
++        : q(q),
++          destroyOnClose(true),
++          autoDelete(false),
++          collapsed(false),
++          icon(0),
++          actionsWidget(0),
++          signalMapper(new QSignalMapper(q))
++    {
++    }
++
++    void setTextFields(const QString &applicationName, const QString &summary, const QString &message);
++    void completeDetach();
++    void updateActions();
++    void updateNotification();
++    void buttonClicked();
++    void hideFinished();
++    QRectF bigIconRect() const;
++
++    NotificationWidget *q;
++
++    QWeakPointer<Notification> notification;
++    bool destroyOnClose;
++    bool autoDelete;
++    bool collapsed;
++
++    QString message;
++    Plasma::TextBrowser *messageLabel;
++    Plasma::Label *title;
++    Plasma::IconWidget *closeButton;
++    Plasma::IconWidget *icon;
++    QGraphicsLinearLayout *titleLayout;
++    QGraphicsLinearLayout *mainLayout;
++    QGraphicsGridLayout *bodyLayout;
++    QGraphicsWidget *body;
++    QGraphicsWidget *iconPlaceSmall;
++    QGraphicsWidget *iconPlaceBig;
++    QGraphicsWidget *actionsWidget;
++    QHash<QString, QString> actions;
++    QStringList actionOrder;
++    QPropertyAnimation *hideAnimation;
++    QPropertyAnimation *iconAnimation;
++    QParallelAnimationGroup *animationGroup;
++
++    QSignalMapper *signalMapper;
++};
++
++NotificationWidget::NotificationWidget(Notification *notification, QGraphicsWidget *parent)
++    : QGraphicsWidget(parent),
++      d(new NotificationWidgetPrivate(this))
++{
++    setFlag(QGraphicsItem::ItemHasNoContents, true);
++    setMinimumWidth(300);
++
++    setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
++
++
++    d->iconPlaceSmall = new QGraphicsWidget(this);
++    d->iconPlaceSmall->setMinimumSize(KIconLoader::SizeSmall, KIconLoader::SizeSmall);
++    d->iconPlaceSmall->setMaximumSize(KIconLoader::SizeSmall, KIconLoader::SizeSmall);
++    d->icon = new Plasma::IconWidget(this);
++    d->icon->setAcceptHoverEvents(false);
++    d->icon->setAcceptedMouseButtons(Qt::NoButton);
++
++    d->title = new Plasma::Label(this);
++    d->title->setWordWrap(false);
++    d->title->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
++    d->title->setAlignment(Qt::AlignCenter);
++
++    d->closeButton = new Plasma::IconWidget(this);
++    d->closeButton->setSvg("widgets/configuration-icons", "close");
++    d->closeButton->setMaximumSize(d->closeButton->sizeFromIconSize(KIconLoader::SizeSmall));
++    d->closeButton->setMinimumSize(d->closeButton->maximumSize());
++    connect(d->closeButton, SIGNAL(clicked()), notification, SLOT(deleteLater()));
++
++    d->titleLayout = new QGraphicsLinearLayout(Qt::Horizontal);
++    d->titleLayout->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
++    d->titleLayout->addItem(d->iconPlaceSmall);
++    d->titleLayout->addItem(d->title);
++    d->titleLayout->addItem(d->closeButton);
++
++
++
++    d->body = new QGraphicsWidget(this);
++    d->body->setContentsMargins(0,0,0,0);
++    d->body->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
++    d->bodyLayout = new QGraphicsGridLayout(d->body);
++    d->bodyLayout->setSpacing(0);
++    d->bodyLayout->setContentsMargins(0,0,0,0);
++
++    d->messageLabel = new Plasma::TextBrowser(d->body);
++    d->messageLabel->setPreferredWidth(0);
++    d->messageLabel->nativeWidget()->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
++    d->messageLabel->nativeWidget()->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
++    d->messageLabel->nativeWidget()->setAlignment(Qt::AlignLeft|Qt::AlignVCenter);
++    d->messageLabel->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
++    connect(d->messageLabel->nativeWidget(), SIGNAL(urlClick(QString)),
++            notification, SLOT(linkActivated(QString)));
++
++    d->iconPlaceBig = new QGraphicsWidget(this);
++    d->iconPlaceBig->setMaximumHeight(KIconLoader::SizeLarge);
++    d->iconPlaceBig->setMinimumHeight(KIconLoader::SizeLarge);
++    d->iconPlaceBig->setMaximumWidth(KIconLoader::SizeLarge);
++    d->iconPlaceBig->setMinimumWidth(KIconLoader::SizeLarge);
++    d->iconPlaceBig->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
++    d->bodyLayout->addItem(d->iconPlaceBig, 0, 0, Qt::AlignCenter);
++    d->bodyLayout->addItem(d->messageLabel, 0, 1, Qt::AlignCenter);
++
++    d->mainLayout = new QGraphicsLinearLayout(Qt::Vertical, this);
++    d->mainLayout->setSpacing(0);
++    d->mainLayout->addItem(d->titleLayout);
++    d->mainLayout->addItem(d->body);
++
++    d->notification = notification;
++
++    connect(d->signalMapper, SIGNAL(mapped(QString)),
++            notification, SLOT(triggerAction(QString)));
++    connect(notification, SIGNAL(changed()),
++            this, SLOT(updateNotification()));
++    connect(notification, SIGNAL(destroyed()),
++            this, SLOT(deleteLater()));
++
++    d->hideAnimation = new QPropertyAnimation(this, "bodyHeight", this);
++    d->hideAnimation->setDuration(250);
++    connect(d->hideAnimation, SIGNAL(finished()), this, SLOT(hideFinished()));
++
++    d->iconAnimation = new QPropertyAnimation(d->icon, "geometry", d->icon);
++    d->iconAnimation->setDuration(250);
++
++    d->animationGroup = new QParallelAnimationGroup(this);
++    d->animationGroup->addAnimation(d->hideAnimation);
++    d->animationGroup->addAnimation(d->iconAnimation);
++
++    d->updateNotification();
++
++    d->mainLayout->activate();
++    updateGeometry();
++}
++
++NotificationWidget::~NotificationWidget()
++{
++    delete d;
++}
++
++void NotificationWidget::setCollapsed(bool collapse, bool animate)
++{
++    if (collapse == d->collapsed) {
++        return;
++    }
++
++    setTitleBarVisible(true);
++
++    //use this weird way to make easy to animate
++    if (animate) {
++        setMinimumHeight(-1);
++        if (collapse) {
++            d->hideAnimation->setStartValue(d->body->size().height());
++            d->hideAnimation->setEndValue(0);
++
++            d->iconAnimation->setStartValue(d->icon->geometry());
++            d->iconAnimation->setEndValue(d->iconPlaceSmall->geometry());
++            d->animationGroup->start();
++        } else {
++            d->body->setVisible(true);
++            d->hideAnimation->setStartValue(d->body->size().height());
++            d->body->setMaximumHeight(-1);
++            d->hideAnimation->setEndValue(d->body->effectiveSizeHint(Qt::PreferredSize).height());
++
++            d->iconAnimation->setStartValue(d->icon->geometry());
++            d->iconAnimation->setEndValue(d->bigIconRect());
++            d->animationGroup->start();
++        }
++    } else {
++        if (collapse) {
++            //setMaximumHeight(d->titleLayout->geometry().bottom());
++            d->body->setMinimumHeight(0);
++            d->body->setMaximumHeight(0);
++            d->body->hide();
++            setMinimumHeight(-1);
++            d->icon->setGeometry(d->iconPlaceSmall->geometry());
++        } else {
++            d->body->show();
++            d->body->setMaximumHeight(-1);
++            d->body->setMinimumHeight(-1);
++            d->body->setMaximumHeight(d->body->effectiveSizeHint(Qt::PreferredSize).height());
++            d->body->setMinimumHeight(d->body->maximumHeight());
++            updateGeometry();
++            d->mainLayout->invalidate();
++            setMinimumHeight(sizeHint(Qt::PreferredSize, QSizeF()).height());
++
++            d->icon->setGeometry(d->bigIconRect());
++        }
++    }
++
++    if (collapse) {
++        d->messageLabel->nativeWidget()->setTextInteractionFlags(Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse|Qt::TextSelectableByKeyboard);
++    } else {
++        d->messageLabel->nativeWidget()->setTextInteractionFlags(Qt::LinksAccessibleByMouse);
++    }
++
++    d->body->setFlag(QGraphicsItem::ItemClipsChildrenToShape, true);
++
++    d->collapsed = collapse;
++}
++
++Notification *NotificationWidget::notification() const
++{
++    return d->notification.data();
++}
++
++qreal NotificationWidget::bodyHeight() const
++{
++    return d->body->maximumHeight();
++}
++
++void NotificationWidget::setBodyHeight(const qreal height)
++{
++    d->body->setMaximumHeight(height);
++    d->body->setMinimumHeight(height);
++    updateGeometry();
++    d->mainLayout->invalidate();
++    setMinimumHeight(sizeHint(Qt::PreferredSize, QSizeF()).height());
++}
++
++bool NotificationWidget::isCollapsed() const
++{
++    return d->collapsed;
++}
++
++void NotificationWidget::setTitleBarVisible(bool visible)
++{
++    if (visible) {
++        d->iconPlaceSmall->show();
++        d->title->show();
++        d->closeButton->show();
++        d->titleLayout->setMaximumHeight(QWIDGETSIZE_MAX);
++    } else {
++        d->iconPlaceSmall->hide();
++        d->title->hide();
++        d->closeButton->hide();
++        d->titleLayout->setMaximumHeight(0);
++    }
++}
++
++bool NotificationWidget::isTitleBarVisible() const
++{
++    return d->title->isVisible();
++}
++
++void NotificationWidget::resizeEvent(QGraphicsSceneResizeEvent *event)
++{
++    QGraphicsWidget::resizeEvent(event);
++    if (d->icon && !d->collapsed && d->animationGroup->state() != QAbstractAnimation::Running) {
++        d->icon->setGeometry(d->bigIconRect());
++    }
++}
++
++QRectF NotificationWidgetPrivate::bigIconRect() const
++{
++    return q->mapFromScene(iconPlaceBig->mapToScene(iconPlaceBig->boundingRect())).boundingRect();
++}
++
++void NotificationWidgetPrivate::setTextFields(const QString &applicationName,
++                                                const QString &summary, const QString &message)
++{
++    if (!summary.isEmpty()) {
++        title->setText(summary);
++    } else {
++        title->setText(i18n("Notification from %1", applicationName));
++    }
++
++
++    QString processed = message.trimmed();
++
++    /*if there is a < that is not closed as a tag, replace it with an entity*/
++    processed = processed.replace(QRegExp("<(?![^<]*>)"), "&lt;");
++    processed.replace('\n', "<br>");
++
++    QFontMetricsF fm(messageLabel->font());
++    qreal maxLine = messageLabel->rect().width();
++
++    QString parsed;
++
++    QString::const_iterator i = processed.begin();
++    bool inTag = false;
++    QString word;
++    QString sentence;
++
++    while (i != processed.end()) {
++        QChar c = *i;
++
++        if (c == '<') {
++            inTag = true;
++            sentence.append(word);
++            parsed.append(fm.elidedText(sentence, Qt::ElideRight, maxLine*4.6));
++            sentence = QString();
++            word = QString();
++            word.append(c);
++        } else if (c == '>') {
++            word.append(c);
++            if (!sentence.isEmpty()) {
++                parsed.append(fm.elidedText(sentence, Qt::ElideRight, maxLine*4.6));
++                sentence.clear();
++            }
++            inTag = false;
++            parsed.append(word);
++            word = QString();
++        } else if (c == ' ') {
++            word.append(c);
++            if (inTag) {
++                parsed.append(word);
++            } else {
++                sentence.append(word);
++            }
++            word = QString();
++        } else {
++            word.append(c);
++        }
++
++        ++i;
++    }
++
++    sentence.append(word);
++    parsed.append(fm.elidedText(sentence, Qt::ElideRight, maxLine*4.6));
++
++    messageLabel->setText(QLatin1String("<html>") + parsed + QLatin1String("</html>"));
++
++    if (!collapsed) {
++        icon->setGeometry(bigIconRect());
++    }
++}
++
++void NotificationWidgetPrivate::completeDetach()
++{
++    actions.clear();
++    actionOrder.clear();
++
++    delete actionsWidget;
++    actionsWidget = 0;
++}
++
++void NotificationWidgetPrivate::updateActions()
++{
++    if (actions.isEmpty() || actionsWidget) {
++        return;
++    }
++
++    actionsWidget = new QGraphicsWidget(body);
++    QGraphicsLinearLayout *layout = new QGraphicsLinearLayout(actionsWidget);
++    layout->setOrientation(Qt::Vertical);
++    layout->setContentsMargins(0, 0, 0, 0);
++    layout->addStretch();
++    actionsWidget->setContentsMargins(0, 0, 0, 0);
++
++    foreach (const QString &actionId, actionOrder) {
++        Plasma::PushButton *button = new Plasma::PushButton(actionsWidget);
++        QString &action = actions[actionId];
++        button->setText(action);
++        button->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
++        //TODO: we need smaller buttons but I don't like this method of accomplishing it.
++        button->setPreferredHeight(button->minimumHeight() - 6);
++
++        q->connect(button, SIGNAL(clicked()), signalMapper, SLOT(map()));
++        q->connect(button, SIGNAL(clicked()), q, SLOT(buttonClicked()));
++        signalMapper->setMapping(button, actionId);
++
++        layout->addItem(button);
++    }
++    layout->addStretch();
++    layout->activate();
++
++    if (actionsWidget->size().width() > q->size().width() * 0.4) {
++        layout->setOrientation(Qt::Horizontal);
++        bodyLayout->addItem(actionsWidget, 1, 0, 1, 2, Qt::AlignCenter);
++    } else {
++        bodyLayout->addItem(actionsWidget, 0, 2, Qt::AlignCenter);
++    }
++}
++
++void NotificationWidgetPrivate::buttonClicked()
++{
++    //a decsion has already been taken
++    if (actionsWidget) {
++        notification.data()->deleteLater();
++    }
++    emit q->actionTriggered(notification.data());
++}
++
++void NotificationWidgetPrivate::updateNotification()
++{
++    if (!notification) {
++        return;
++    }
++
++
++    //set text fields and icon
++    setTextFields(notification.data()->applicationName(), notification.data()->summary(), notification.data()->message());
++    icon->setIcon(notification.data()->applicationIcon());
++    messageLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
++
++    //set the actions provided
++    actions = notification.data()->actions();
++    actionOrder = notification.data()->actionOrder();
++    updateActions();
++
++    if (!notification.data()->image().isNull()) {
++
++        icon->setIcon(QPixmap::fromImage(notification.data()->image()));
++
++        QSize imageSize = notification.data()->image().size();
++
++        if (imageSize.width() > KIconLoader::SizeLarge || imageSize.height() > KIconLoader::SizeLarge) {
++            imageSize.scale(KIconLoader::SizeLarge, KIconLoader::SizeLarge, Qt::KeepAspectRatio);
++        }
++
++        icon->setMaximumIconSize(QSizeF(qMin((int)KIconLoader::SizeLarge, imageSize.width()),
++                                  qMin((int)KIconLoader::SizeLarge, imageSize.height())));
++    }
++
++
++    //FIXME: this sounds wrong
++    q->setPreferredHeight(mainLayout->effectiveSizeHint(Qt::MinimumSize).height());
++}
++
++void NotificationWidgetPrivate::hideFinished()
++{
++    body->setVisible(!collapsed);
++    body->setFlag(QGraphicsItem::ItemClipsChildrenToShape, false);
++}
++
++#include "notificationwidget.moc"
+diff --git a/plasma/generic/applets/notifications/ui/notificationwidget.h b/plasma/generic/applets/notifications/ui/notificationwidget.h
+new file mode 100644
+index 0000000..7c1a436
+--- /dev/null
++++ b/plasma/generic/applets/notifications/ui/notificationwidget.h
+@@ -0,0 +1,72 @@
++/***************************************************************************
++ *   notificationwidget.h                                                  *
++ *                                                                         *
++ *   Copyright (C) 2008 Dmitry Suzdalev <dimsuz@gmail.com>                 *
++ *   Copyright (C) 2008 Rob Scheepmaker <r.scheepmaker@student.utwente.nl> *
++ *   Copyright (C) 2008 Jason Stubbs <jasonbstubbs@gmail.com>              *
++ *   Copyright (C) 2010 Marco Martin <notmart@gmail.com>                   *
++ *                                                                         *
++ *   This program 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 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 Library General Public License for more details.                  *
++ *                                                                         *
++ *   You should have received a copy of the GNU Library General Public     *
++ *   License along with this library; if not, write to the                 *
++ *   Free Software Foundation, Inc.,                                       *
++ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA .        *
++ ***************************************************************************/
++
++#ifndef NOTIFICATIONWIDGET_H
++#define NOTIFICATIONWIDGET_H
++
++#include <Plasma/Frame>
++
++#include "../core/notification.h"
++
++class NotificationWidgetPrivate;
++
++/**
++ *  A graphics item, representing notification message.
++ */
++class NotificationWidget : public QGraphicsWidget
++{
++    Q_OBJECT
++    Q_PROPERTY(qreal bodyHeight READ bodyHeight WRITE setBodyHeight)
++
++public:
++    NotificationWidget(Notification *notification, QGraphicsWidget *parent);
++    ~NotificationWidget();
++
++    void setCollapsed(bool collapse, bool animate = true);
++    bool isCollapsed() const;
++
++    void setTitleBarVisible(bool visible);
++    bool isTitleBarVisible() const;
++
++    qreal bodyHeight() const;
++    void setBodyHeight(const qreal height);
++
++    Notification *notification() const;
++
++protected:
++    void resizeEvent(QGraphicsSceneResizeEvent *event);
++
++Q_SIGNALS:
++    void actionTriggered(Notification *);
++
++private:
++    friend class NotificationWidgetPrivate;
++    NotificationWidgetPrivate* const d;
++
++    Q_PRIVATE_SLOT(d, void updateNotification())
++    Q_PRIVATE_SLOT(d, void buttonClicked())
++    Q_PRIVATE_SLOT(d, void hideFinished())
++};
++
++#endif // NOTIFICATIONWIDGET_H
+diff --git a/plasma/generic/applets/notifications/ui/stackdialog.cpp b/plasma/generic/applets/notifications/ui/stackdialog.cpp
+new file mode 100644
+index 0000000..9be364e
+--- /dev/null
++++ b/plasma/generic/applets/notifications/ui/stackdialog.cpp
+@@ -0,0 +1,446 @@
++/***************************************************************************
++ *   stacdialog.h                                                          *
++ *   Copyright (C) 2010 Marco Martin <notmart@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 .        *
++ ***************************************************************************/
++
++#include "stackdialog.h"
++#include "notificationstack.h"
++#include "notificationwidget.h"
++
++#include <QApplication>
++#include <QDesktopWidget>
++#include <QGraphicsLayout>
++#include <QLayout>
++#include <QPropertyAnimation>
++#include <QTimer>
++
++#include <KWindowSystem>
++
++#include <Plasma/Applet>
++#include <Plasma/Containment>
++#include <Plasma/Corona>
++#include <Plasma/FrameSvg>
++#include <Plasma/WindowEffects>
++
++static const uint hideTimeout = 15 * 1000;
++
++StackDialog::StackDialog(QWidget *parent, Qt::WindowFlags f)
++      : Plasma::Dialog(parent, f),
++        m_applet(0),
++        m_windowToTile(0),
++        m_notificationStack(0),
++        m_view(0),
++        m_drawLeft(true),
++        m_drawRight(true),
++        m_autoHide(true),
++        m_hasCustomPosition(false)
++{
++    m_background = new Plasma::FrameSvg(this);
++    m_background->setImagePath("widgets/extender-background");
++    setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
++    KWindowSystem::setType(winId(), NET::Dock);
++
++    m_showTimer = new QTimer(this);
++    m_showTimer->setSingleShot(true);
++    m_showTimer->setInterval(0);
++    connect(m_showTimer, SIGNAL(timeout()), this, SLOT(show()));
++
++    m_hideTimer = new QTimer(this);
++    m_hideTimer->setSingleShot(true);
++    connect(m_hideTimer, SIGNAL(timeout()), this, SLOT(hideRequested()));
++}
++
++StackDialog::~StackDialog()
++{
++}
++
++void StackDialog::setNotificationStack(NotificationStack *stack)
++{
++    setGraphicsWidget(stack);
++
++    if (!m_view && layout()) {
++        m_view = qobject_cast<QGraphicsView *>(layout()->itemAt(0)->widget());
++        if (m_view) {
++            m_view->installEventFilter(this);
++        }
++    }
++
++    if (m_notificationStack) {
++        disconnect(m_notificationStack, 0, this, 0);
++    }
++
++    m_notificationStack = stack;
++
++    connect(m_notificationStack, SIGNAL(updateRequested()), this, SLOT(update()));
++    connect(m_notificationStack, SIGNAL(hideRequested()), this, SLOT(hideRequested()));
++}
++
++NotificationStack *StackDialog::notificartionStack() const
++{
++    return m_notificationStack;
++}
++
++void StackDialog::setApplet(Plasma::Applet *applet)
++{
++    m_applet = applet;
++    adjustPosition(QPoint(-1, -1));
++}
++
++Plasma::Applet *StackDialog::applet() const
++{
++    return m_applet;
++}
++
++void StackDialog::setWindowToTile(QWidget *widget)
++{
++    if (m_windowToTile) {
++        m_windowToTile->removeEventFilter(this);
++        delete m_windowToTileAnimation;
++    }
++
++    m_windowToTile = widget;
++    m_windowToTile->installEventFilter(this);
++    m_windowToTileAnimation = new QPropertyAnimation(m_windowToTile, "pos", this);
++    m_windowToTileAnimation->setDuration(250);
++    m_windowToTileAnimation->setEasingCurve(QEasingCurve::InOutQuad);
++}
++
++QWidget *StackDialog::windowToTile() const
++{
++    return m_windowToTile;
++}
++
++void StackDialog::setAutoHide(const bool autoHide)
++{
++    m_autoHide = autoHide;
++}
++
++bool StackDialog::autoHide() const
++{
++    return m_autoHide;
++}
++
++void StackDialog::adjustWindowToTilePos()
++{
++    if (m_applet && m_windowToTile && m_hasCustomPosition) {
++        m_windowToTileAnimation->setStartValue(m_windowToTile->pos());
++
++        if (isVisible()) {
++            const QRect realScreenRect = qApp->desktop()->screenGeometry(m_applet->containment()->screen());
++            if (m_applet->location() == Plasma::TopEdge || (pos().y() - realScreenRect.top()) < m_windowToTile->size().height()) {
++                m_windowToTileAnimation->setEndValue(QPoint(m_windowToTile->pos().x(), geometry().bottom()));
++            } else {
++                m_windowToTileAnimation->setEndValue(QPoint(m_windowToTile->pos().x(), pos().y() - m_windowToTile->size().height()));
++            }
++        } else if (m_applet && m_applet->containment() && m_applet->containment()->corona()) {
++            m_windowToTileAnimation->setEndValue(QPoint(m_applet->containment()->corona()->popupPosition(m_applet, m_windowToTile->size())));
++        }
++        m_windowToTileAnimation->start();
++    }
++}
++
++void StackDialog::paintEvent(QPaintEvent *e)
++{
++    Plasma::Dialog::paintEvent(e);
++
++    QPainter painter(this);
++    if (m_notificationStack) {
++        //FIXME: assumption++
++        QGraphicsLayout *mainLayout = static_cast<QGraphicsLayout *>(m_notificationStack->layout());
++
++        if (!m_notificationStack->currentNotificationWidget() || mainLayout->count() < 2) {
++            return;
++        }
++
++        for (int i = 0; i < mainLayout->count(); ++i) {
++            //assumption++ all items are NotificationWidget
++            NotificationWidget *nw = static_cast<NotificationWidget *>(mainLayout->itemAt(i));
++
++            //first element
++            if (i == 0 && m_notificationStack->currentNotificationWidget() != nw) {
++                continue;
++            } else if (i == 0) {
++                m_background->setEnabledBorders((Plasma::FrameSvg::EnabledBorders)(Plasma::FrameSvg::AllBorders&~Plasma::FrameSvg::TopBorder));
++            //last element
++            } else if (i == mainLayout->count()-1 && m_notificationStack->currentNotificationWidget() != nw) {
++                continue;
++            } else if (i == mainLayout->count()-1) {
++                m_background->setEnabledBorders((Plasma::FrameSvg::EnabledBorders)Plasma::FrameSvg::AllBorders&~Plasma::FrameSvg::BottomBorder);
++            //element under the active one
++            } else if (m_notificationStack->currentNotificationWidget()->pos().y() < nw->pos().y()) {
++                m_background->setEnabledBorders((Plasma::FrameSvg::EnabledBorders)Plasma::FrameSvg::AllBorders&~Plasma::FrameSvg::TopBorder);
++            //element over the active one
++            } else if (m_notificationStack->currentNotificationWidget()->pos().y() > nw->pos().y()) {
++                m_background->setEnabledBorders((Plasma::FrameSvg::EnabledBorders)Plasma::FrameSvg::AllBorders&~Plasma::FrameSvg::BottomBorder);
++            //active element
++            } else {
++                m_background->setEnabledBorders(Plasma::FrameSvg::AllBorders);
++            }
++
++            qreal left, top, right, bottom;
++            m_background->getMargins(left, top, right, bottom);
++            m_background->resizeFrame(QSizeF(size().width(), nw->size().height() + top + bottom));
++
++            Plasma::FrameSvg::EnabledBorders borders = m_background->enabledBorders();
++
++            if (!m_drawLeft) {
++                borders &= ~Plasma::FrameSvg::LeftBorder;
++            }
++
++            if (!m_drawRight) {
++                borders &= ~Plasma::FrameSvg::RightBorder;
++            }
++
++            m_background->setEnabledBorders(borders);
++
++            const int topMargin = contentsRect().top();
++            m_background->paintFrame(&painter, QPointF(0, nw->pos().y() - top + topMargin));
++        }
++    }
++}
++
++void StackDialog::perhapsShow()
++{
++    if (m_applet && m_applet->view()) {
++        // we use a timer here because when the stack is going to be shown, the applet is likely
++        // to also be in movement (e.g. from hidden away to now shown to the user) and that will
++        // likely result in an odd geometry for the applet when popupPosition is called on this
++        // dialog. so instead we wait a bit after the show request to allow the applet to find
++        // it's proper place
++        m_showTimer->start();
++    }
++}
++
++void StackDialog::showEvent(QShowEvent *event)
++{
++    Q_UNUSED(event)
++
++    adjustPosition(adjustedSavedPos());
++    adjustWindowToTilePos();
++
++    if (m_autoHide) {
++        m_hideTimer->start(hideTimeout);
++    }
++
++    Plasma::Dialog::showEvent(event);
++}
++
++void StackDialog::hideRequested()
++{
++    // we have this method because hide() may not always cause a hideEvent, e.g. when
++    // the StackDialog has not been shown yet .. however, we always want to ensure the
++    // show timer is stopped. we also stop it in the hideEvent for completeness and to
++    // catch any direct calls to hide() that may happen
++    m_showTimer->stop();
++    hide();
++}
++
++void StackDialog::hideEvent(QHideEvent *event)
++{
++    Q_UNUSED(event)
++
++    m_showTimer->stop();
++    m_hideTimer->stop();
++
++    adjustWindowToTilePos();
++
++    m_notificationStack->adjustSize();
++    Plasma::Dialog::hideEvent(event);
++}
++
++void StackDialog::resizeEvent(QResizeEvent *event)
++{
++    Q_UNUSED(event)
++    adjustWindowToTilePos();
++    Plasma::Dialog::resizeEvent(event);
++    if (m_hasCustomPosition) {
++        adjustPosition(pos());
++    } else if (m_applet && m_applet->containment() && m_applet->containment()->corona()) {
++        move(m_applet->containment()->corona()->popupPosition(m_applet, size()));
++    }
++}
++
++void StackDialog::moveEvent(QMoveEvent *event)
++{
++    Q_UNUSED(event)
++
++    adjustWindowToTilePos();
++    Plasma::Dialog::moveEvent(event);
++}
++
++void StackDialog::enterEvent(QEvent *event)
++{
++    Q_UNUSED(event)
++
++    m_hideTimer->stop();
++}
++
++void StackDialog::leaveEvent(QEvent *event)
++{
++    Q_UNUSED(event)
++
++    if (m_autoHide) {
++        m_hideTimer->start(hideTimeout);
++    }
++    Plasma::Dialog::leaveEvent(event);
++}
++
++void StackDialog::adjustPosition(const QPoint &pos)
++{
++    if (!m_applet) {
++        return;
++    }
++
++    if (pos == QPoint(-1, -1)) {
++        const QPoint popupPosition = m_applet->containment()->corona()->popupPosition(m_applet, size());
++        move(popupPosition);
++        Plasma::WindowEffects::slideWindow(this, m_applet->location());
++        m_hasCustomPosition = false;
++    } else {
++        QPoint customPosition = pos;
++
++        if (m_applet->containment() &&
++            m_applet->containment()->corona() &&
++            m_notificationStack) {
++            QRect screenRect = m_applet->containment()->corona()->availableScreenRegion(m_applet->containment()->screen()).boundingRect();
++
++            customPosition.rx() = qMax(customPosition.x(), screenRect.left());
++            customPosition.ry() = qMax(customPosition.y(), screenRect.top());
++            customPosition.rx() = qMin(customPosition.x() + size().width(), screenRect.right()) - size().width();
++            customPosition.ry() = qMin(customPosition.y() + size().height(), screenRect.bottom()) - size().height();
++
++            bool closerToBottom = (customPosition.ry() > (screenRect.height() / 2));
++            if (!m_lastSize.isNull() && closerToBottom
++                && (m_lastSize.height() > size().height())) {
++                customPosition.ry() += m_lastSize.height() - size().height();
++            }
++            m_lastSize = size();
++        }
++
++        move(customPosition);
++        Plasma::WindowEffects::slideWindow(this, Plasma::Desktop);
++        m_hasCustomPosition = true;
++    }
++}
++
++void StackDialog::savePosition(const QPoint& pos)
++{
++    if (!m_applet || !m_applet->containment()) {
++        return;
++    }
++
++    QByteArray horizSide, vertSide;
++    QPoint pixelsToSave;
++    const QRect realScreenRect = qApp->desktop()->screenGeometry(m_applet->containment()->screen());
++
++    int screenRelativeX = pos.x() - realScreenRect.x();
++    int diffWithRight = realScreenRect.width() - (screenRelativeX + size().width());
++    if (screenRelativeX < diffWithRight) {
++        horizSide = "l";
++        pixelsToSave.rx() = screenRelativeX;
++    } else {
++        horizSide = "r";
++        pixelsToSave.rx() = diffWithRight;
++    }
++
++    int screenRelativeY = pos.y() - realScreenRect.y();
++    int diffWithBottom = realScreenRect.height() - (screenRelativeY + size().height());
++    if (screenRelativeY < diffWithBottom) {
++        vertSide = "t";
++        pixelsToSave.ry() = screenRelativeY;
++    } else {
++        vertSide = "b";
++        pixelsToSave.ry() = diffWithBottom;
++    }
++
++    kDebug() << "Affinity-v" << vertSide;
++    kDebug() << "Affinity-h" << horizSide;
++    kDebug() << "Y: " << pixelsToSave.ry();
++    kDebug() << "X: " << pixelsToSave.rx();
++
++    m_applet->config().writeEntry("customPosition", pixelsToSave);
++    m_applet->config().writeEntry("customPositionAffinityHoriz", horizSide);
++    m_applet->config().writeEntry("customPositionAffinityVert", vertSide);
++}
++
++QPoint StackDialog::adjustedSavedPos() const
++{
++    if (!m_applet) {
++        return QPoint(-1, -1);
++    }
++
++    QPoint pos = m_applet->config().readEntry("customPosition", QPoint(-1, -1));
++
++    if (pos != QPoint(-1, -1)) {
++        const QRect realScreenRect = qApp->desktop()->screenGeometry(m_applet->containment()->screen());
++        QByteArray horizSide = m_applet->config().readEntry("customPositionAffinityHoriz").toLatin1();
++        QByteArray vertSide = m_applet->config().readEntry("customPositionAffinityVert").toLatin1();
++
++        if (horizSide == "l") {
++            pos.rx() += realScreenRect.x();
++        } else {
++            pos.rx() = realScreenRect.x() + (realScreenRect.width() - pos.rx() - size().width());
++        }
++
++        if (vertSide == "t") {
++            pos.ry() += realScreenRect.y();
++        } else {
++            pos.ry() = realScreenRect.y() + (realScreenRect.height() - pos.ry() - size().height());
++        }
++    }
++
++    return pos;
++}
++
++bool StackDialog::event(QEvent *event)
++{
++    bool ret = Dialog::event(event);
++
++    if (event->type() == QEvent::ContentsRectChange) {
++        int left, top, right, bottom;
++        getContentsMargins(&left, &top, &right, &bottom);
++
++        m_drawLeft = (left != 0);
++        m_drawRight = (right != 0);
++        update();
++    }
++
++    return ret;
++}
++
++bool StackDialog::eventFilter(QObject *watched, QEvent *event)
++{
++    if (m_windowToTile && watched == m_windowToTile &&
++        event->type() == QEvent::Show && isVisible()) {
++        adjustWindowToTilePos();
++    } else if (watched == m_notificationStack && event->type() == QEvent::GraphicsSceneMousePress) {
++        QGraphicsSceneMouseEvent *me = static_cast<QGraphicsSceneMouseEvent *>(event);
++        m_dragPos = me->pos().toPoint();
++    } else if (watched == m_notificationStack && event->type() == QEvent::GraphicsSceneMouseMove) {
++        QGraphicsSceneMouseEvent *me = static_cast<QGraphicsSceneMouseEvent *>(event);
++        adjustPosition(me->screenPos() - m_dragPos);
++    } else if (watched == m_notificationStack && event->type() == QEvent::GraphicsSceneMouseRelease) {
++        QGraphicsSceneMouseEvent *me = static_cast<QGraphicsSceneMouseEvent *>(event);
++        adjustPosition(me->screenPos() - m_dragPos);
++        savePosition(me->screenPos() - m_dragPos);
++    }
++
++    return Plasma::Dialog::eventFilter(watched, event);
++}
++
++#include "stackdialog.moc"
+diff --git a/plasma/generic/applets/notifications/ui/stackdialog.h b/plasma/generic/applets/notifications/ui/stackdialog.h
+new file mode 100644
+index 0000000..4360c4a
+--- /dev/null
++++ b/plasma/generic/applets/notifications/ui/stackdialog.h
+@@ -0,0 +1,99 @@
++/***************************************************************************
++ *   stacdialog.h                                                          *
++ *   Copyright (C) 2010 Marco Martin <notmart@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 STACKDIALOG_H
++#define STACKDIALOG_H
++
++#include <Plasma/Dialog>
++
++#include <QPoint>
++
++class QPropertyAnimation;
++class QTimer;
++
++namespace Plasma
++{
++    class Applet;
++    class FrameSvg;
++}
++
++class NotificationStack;
++
++
++class StackDialog : public Plasma::Dialog
++{
++    Q_OBJECT
++public:
++    StackDialog(QWidget *parent = 0, Qt::WindowFlags f = Qt::Window);
++    ~StackDialog();
++
++    void setNotificationStack(NotificationStack *stack);
++    NotificationStack *notificartionStack() const;
++
++    void setApplet(Plasma::Applet *applet);
++    Plasma::Applet *applet() const;
++
++    void setWindowToTile(QWidget *widget);
++    QWidget *windowToTile() const;
++
++    void setAutoHide(const bool autoHide);
++    bool autoHide() const;
++
++public Q_SLOTS:
++    void perhapsShow();
++
++protected:
++    void adjustWindowToTilePos();
++
++    void paintEvent(QPaintEvent *e);
++    void showEvent(QShowEvent *event);
++    void hideEvent(QHideEvent *event);
++    void enterEvent(QEvent *event);
++    void leaveEvent(QEvent *event);
++    void resizeEvent(QResizeEvent *event);
++    void moveEvent(QMoveEvent *event);
++    bool event(QEvent *event);
++    bool eventFilter(QObject *watched, QEvent *event);
++    void adjustPosition(const QPoint &pos = QPoint(-1, -1));
++    void savePosition(const QPoint &pos);
++    QPoint adjustedSavedPos() const;
++
++private Q_SLOTS:
++    void hideRequested();
++
++private:
++    Plasma::Applet *m_applet;
++    QWidget *m_windowToTile;
++    QPropertyAnimation *m_windowToTileAnimation;
++    QPoint m_dragPos;
++    QSize m_lastSize;
++
++    Plasma::FrameSvg *m_background;
++    NotificationStack *m_notificationStack;
++    QTimer *m_showTimer;
++    QTimer *m_hideTimer;
++    QGraphicsView *m_view;
++    bool m_drawLeft;
++    bool m_drawRight;
++    bool m_autoHide;
++    bool m_hasCustomPosition;
++};
++
++#endif

diff --git a/kde-base/plasma-workspace/files/plasma-workspace-4.10.1-noplasmalock.patch b/kde-base/plasma-workspace/files/plasma-workspace-4.10.1-noplasmalock.patch
new file mode 100644
index 0000000..2380d20
--- /dev/null
+++ b/kde-base/plasma-workspace/files/plasma-workspace-4.10.1-noplasmalock.patch
@@ -0,0 +1,11 @@
+diff --git a/plasma/screensaver/CMakeLists.txt b/plasma/screensaver/CMakeLists.txt
+index 514c856..9dcb5f4 100644
+--- a/plasma/screensaver/CMakeLists.txt
++++ b/plasma/screensaver/CMakeLists.txt
+@@ -1,6 +1,3 @@
+ add_subdirectory(containments)
+-if(NOT WIN32)
+-add_subdirectory(shell)
+-endif(NOT WIN32)
+ 
+ 

diff --git a/kde-base/plasma-workspace/metadata.xml b/kde-base/plasma-workspace/metadata.xml
new file mode 100644
index 0000000..3b3fc4f
--- /dev/null
+++ b/kde-base/plasma-workspace/metadata.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd">
+<pkgmetadata>
+<herd>kde</herd>
+<use>
+	<flag name="json">Enable JSON support via <pkg>dev-libs/qjson</pkg></flag>
+	<flag name="qalculate">Enable Qalculate runner using <pkg>sci-libs/libqalculate</pkg></flag>
+</use>
+</pkgmetadata>

diff --git a/kde-base/plasma-workspace/plasma-workspace-4.11.2-r2.ebuild b/kde-base/plasma-workspace/plasma-workspace-4.11.2-r2.ebuild
new file mode 100644
index 0000000..4ed968e
--- /dev/null
+++ b/kde-base/plasma-workspace/plasma-workspace-4.11.2-r2.ebuild
@@ -0,0 +1,125 @@
+# Copyright 1999-2013 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Header: $
+
+EAPI=5
+
+DECLARATIVE_REQUIRED="always"
+KDE_HANDBOOK="optional"
+KMNAME="kde-workspace"
+KMMODULE="plasma"
+PYTHON_COMPAT=( python2_{6,7} )
+OPENGL_REQUIRED="always"
+inherit python-single-r1 kde4-meta
+
+DESCRIPTION="Plasma: KDE desktop framework"
+KEYWORDS="~amd64 ~arm ~ppc ~ppc64 ~x86 ~amd64-linux ~x86-linux"
+IUSE="debug gps json python qalculate semantic-desktop"
+
+REQUIRED_USE="python? ( ${PYTHON_REQUIRED_USE} )"
+
+COMMONDEPEND="
+	dev-libs/libdbusmenu-qt
+	>=dev-qt/qtcore-4.8.4-r3:4
+	!kde-misc/ktouchpadenabler
+	$(add_kdebase_dep kactivities)
+	$(add_kdebase_dep kdelibs 'semantic-desktop?')
+	$(add_kdebase_dep kdepimlibs)
+	$(add_kdebase_dep kephal)
+	$(add_kdebase_dep ksysguard)
+	$(add_kdebase_dep libkworkspace)
+	$(add_kdebase_dep libplasmaclock)
+	$(add_kdebase_dep libplasmagenericshell)
+	$(add_kdebase_dep libtaskmanager)
+	x11-libs/libX11
+	x11-libs/libXcomposite
+	x11-libs/libXdamage
+	x11-libs/libXext
+	x11-libs/libXfixes
+	x11-libs/libXi
+	x11-libs/libXrender
+	gps? ( >=sci-geosciences/gpsd-2.37 )
+	json? ( dev-libs/qjson )
+	python? (
+		${PYTHON_DEPS}
+		>=dev-python/PyQt4-4.4.0[X,${PYTHON_USEDEP}]
+		$(add_kdebase_dep pykde4 "${PYTHON_USEDEP}")
+	)
+	qalculate? ( sci-libs/libqalculate )
+	semantic-desktop? (
+		dev-libs/soprano
+		$(add_kdebase_dep nepomuk-core)
+	)
+"
+DEPEND="${COMMONDEPEND}
+	dev-libs/boost
+	x11-proto/compositeproto
+	x11-proto/damageproto
+	x11-proto/fixesproto
+	x11-proto/renderproto
+"
+RDEPEND="${COMMONDEPEND}
+	$(add_kdebase_dep plasma-runtime)
+"
+
+KMEXTRA="
+	appmenu/
+	ktouchpadenabler/
+	statusnotifierwatcher/
+"
+KMEXTRACTONLY="
+	kcheckpass/
+	krunner/dbus/org.freedesktop.ScreenSaver.xml
+	krunner/dbus/org.kde.krunner.App.xml
+	ksmserver/org.kde.KSMServerInterface.xml
+	ksmserver/screenlocker/
+	libs/kephal/
+	libs/kworkspace/
+	libs/taskmanager/
+	libs/plasmagenericshell/
+	libs/ksysguard/
+	libs/kdm/kgreeterplugin.h
+	ksysguard/
+"
+
+KMLOADLIBS="libkworkspace libplasmaclock libplasmagenericshell libtaskmanager"
+
+PATCHES=( "${FILESDIR}/${PN}-4.10.1-noplasmalock.patch" "${FILESDIR}/oldnotify.patch" )
+
+pkg_setup() {
+	if use python ; then
+		python-single-r1_pkg_setup
+	fi
+	kde4-meta_pkg_setup
+}
+
+src_unpack() {
+	if use handbook; then
+		KMEXTRA+=" doc/plasma-desktop"
+	fi
+
+	kde4-meta_src_unpack
+}
+
+src_configure() {
+	mycmakeargs=(
+		$(cmake-utils_use_with gps libgps)
+		$(cmake-utils_use_with json QJSON)
+		$(cmake-utils_use_with python PythonLibrary)
+		$(cmake-utils_use_with qalculate)
+		$(cmake-utils_use_with semantic-desktop Akonadi)
+		$(cmake-utils_use_with semantic-desktop NepomukCore)
+		$(cmake-utils_use_with semantic-desktop Soprano)
+		-DWITH_Xmms=OFF
+	)
+
+	kde4-meta_src_configure
+}
+
+src_install() {
+	kde4-meta_src_install
+
+	if use python; then
+		python_optimize "${ED}"
+	fi
+}


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* [gentoo-commits] dev/dilfridge:master commit in: kde-base/plasma-workspace/files/, kde-base/plasma-workspace/
@ 2014-04-29 22:47 Andreas Hüttel
  0 siblings, 0 replies; 2+ messages in thread
From: Andreas Hüttel @ 2014-04-29 22:47 UTC (permalink / raw
  To: gentoo-commits

commit:     e8643b94912d0327564600ee9196efebc06394ec
Author:     Andreas K. Huettel (dilfridge) <dilfridge <AT> gentoo <DOT> org>
AuthorDate: Tue Apr 29 22:47:09 2014 +0000
Commit:     Andreas Hüttel <dilfridge <AT> gentoo <DOT> org>
CommitDate: Tue Apr 29 22:47:34 2014 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=dev/dilfridge.git;a=commit;h=e8643b94

[kde-base/plasma-workspace] clean up

---
 kde-base/plasma-workspace/Manifest                 |    1 -
 kde-base/plasma-workspace/files/oldnotify.patch    | 8557 --------------------
 .../plasma-workspace-4.10.1-noplasmalock.patch     |   11 -
 kde-base/plasma-workspace/metadata.xml             |    9 -
 .../plasma-workspace-4.11.2-r2.ebuild              |  125 -
 5 files changed, 8703 deletions(-)

diff --git a/kde-base/plasma-workspace/Manifest b/kde-base/plasma-workspace/Manifest
deleted file mode 100644
index 48cd387..0000000
--- a/kde-base/plasma-workspace/Manifest
+++ /dev/null
@@ -1 +0,0 @@
-DIST kde-workspace-4.11.2.tar.xz 13870828 SHA256 260e46f30b8faaa1ad834d9fa69465ab1f565cb18a174bd814327083bb28d917 SHA512 8d034e147ebb630941465b77e302aa2385c2f1419847e8a65ac19d445846435b61d78323fdb094b9a71089ab183c96af141db93c7c9c53a9b30c84ae69bddf2a WHIRLPOOL 0db07ef64caf873c0aa6398a28b92fdc9334eb04897c9a71ed0e3c54ad77e9e8dc23b13b6343844650a2ec7c2784664185f01cf64424d694a8c33167affb5720

diff --git a/kde-base/plasma-workspace/files/oldnotify.patch b/kde-base/plasma-workspace/files/oldnotify.patch
deleted file mode 100644
index c4c5c3b..0000000
--- a/kde-base/plasma-workspace/files/oldnotify.patch
+++ /dev/null
@@ -1,8557 +0,0 @@
-diff --git a/plasma/generic/applets/notifications/CMakeLists.txt b/plasma/generic/applets/notifications/CMakeLists.txt
-index 02afb93..a38fe47 100644
---- a/plasma/generic/applets/notifications/CMakeLists.txt
-+++ b/plasma/generic/applets/notifications/CMakeLists.txt
-@@ -1,2 +1,47 @@
--installPackage(. org.kde.notifications)
-+project(plasma-notifications)
-+#TODO: see if is still the case
-+# 'engineName' causes error
-+kde4_no_enable_final(plasma-notifications)
- 
-+set(notifications_SRCS
-+
-+    core/notificationsmanager.cpp
-+    core/protocol.cpp
-+    core/notification.cpp
-+    core/completedjobnotification.cpp
-+    core/job.cpp
-+
-+    protocols/notifications/dbusnotificationprotocol.cpp
-+    protocols/notifications/dbusnotification.cpp
-+
-+    protocols/jobs/dbusjobprotocol.cpp
-+    protocols/jobs/dbusjob.cpp
-+
-+    ui/busywidget.cpp
-+    ui/notifications.cpp
-+    ui/notificationwidget.cpp
-+    ui/jobtotalswidget.cpp
-+    ui/jobwidget.cpp
-+    ui/notificationgroup.cpp
-+    ui/notificationstack.cpp
-+    ui/stackdialog.cpp
-+    )
-+
-+kde4_add_ui_files(notifications_SRCS
-+                  ui/notificationsconfig.ui)
-+
-+
-+include (CheckLibraryExists)
-+check_library_exists (Xss XScreenSaverQueryInfo "" HAVE_LIBXSS)
-+configure_file (${CMAKE_CURRENT_SOURCE_DIR}/config-notifications.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-notifications.h)
-+IF (HAVE_LIBXSS)
-+   SET (IDLE_DETECTION_LIB "Xss")
-+ENDIF (HAVE_LIBXSS)
-+
-+
-+kde4_add_plugin(plasma_applet_notifications ${notifications_SRCS})
-+include_directories(${CMAKE_SOURCE_DIR})
-+target_link_libraries(plasma_applet_notifications ${KDE4_KDEUI_LIBS} ${KDE4_PLASMA_LIBS} ${X11_LIBRARIES} ${X11_Xrender_LIB} ${X11_Xfixes_LIB} ${X11_Xdamage_LIB} ${X11_Xcomposite_LIB} ${KDE4_SOLID_LIBS} ${IDLE_DETECTION_LIB})
-+
-+install(TARGETS plasma_applet_notifications DESTINATION ${PLUGIN_INSTALL_DIR})
-+install(FILES plasma-applet-notifications.desktop DESTINATION ${SERVICES_INSTALL_DIR})
-diff --git a/plasma/generic/applets/notifications/Messages.sh b/plasma/generic/applets/notifications/Messages.sh
-old mode 100644
-new mode 100755
-index bd3e2d9..5582bc6
---- a/plasma/generic/applets/notifications/Messages.sh
-+++ b/plasma/generic/applets/notifications/Messages.sh
-@@ -1,5 +1,4 @@
- #! /usr/bin/env bash
--$EXTRACTRC `find . -name \*.rc -o -name \*.ui -o -name \*.kcfg` >> rc.cpp
--$XGETTEXT `find . -name \*.qml` -L Java -o $podir/plasma_applet_org.kde.notifications.pot
--$XGETTEXT rc.cpp -jo $podir/plasma_applet_org.kde.notifications.pot
-+$EXTRACTRC `find . -name '*.ui'` >> rc.cpp
-+$XGETTEXT  `find . -name '*.cpp'` -o $podir/plasma_applet_notifications.pot
- rm -f rc.cpp
-diff --git a/plasma/generic/applets/notifications/config-notifications.h.cmake b/plasma/generic/applets/notifications/config-notifications.h.cmake
-new file mode 100644
-index 0000000..aac3113
---- /dev/null
-+++ b/plasma/generic/applets/notifications/config-notifications.h.cmake
-@@ -0,0 +1 @@
-+#cmakedefine HAVE_LIBXSS
-diff --git a/plasma/generic/applets/notifications/contents/config/main.xml b/plasma/generic/applets/notifications/contents/config/main.xml
-deleted file mode 100644
-index 399159d..0000000
---- a/plasma/generic/applets/notifications/contents/config/main.xml
-+++ /dev/null
-@@ -1,23 +0,0 @@
--<?xml version="1.0" encoding="UTF-8"?>
--<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
--      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
--      xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
--      http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
--  <kcfgfile name=""/>
--
--  <group name="General">
--    <entry name="CustomPosition" type="Point">
--      <label>where the notification popup will be</label>
--      <default>-1,-1</default>
--    </entry>
--    <entry name="ShowNotifications" type="Bool">
--      <label>Show the notifications</label>
--      <default>true</default>
--    </entry>
--    <entry name="ShowJobs" type="Bool">
--      <label>Show the jobs progress</label>
--      <default>true</default>
--    </entry>
--  </group>
--
--</kcfg>
-diff --git a/plasma/generic/applets/notifications/contents/ui/JobDelegate.qml b/plasma/generic/applets/notifications/contents/ui/JobDelegate.qml
-deleted file mode 100644
-index e94866d..0000000
---- a/plasma/generic/applets/notifications/contents/ui/JobDelegate.qml
-+++ /dev/null
-@@ -1,310 +0,0 @@
--/*
-- *   Copyright 2011 Marco Martin <notmart@gmail.com>
-- *
-- *   This program 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, 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 Library General Public License for more details
-- *
-- *   You should have received a copy of the GNU Library 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.
-- */
--
--import QtQuick 1.0
--import org.kde.plasma.core 0.1 as PlasmaCore
--import org.kde.plasma.components 0.1 as PlasmaComponents
--import org.kde.plasma.graphicswidgets 0.1 as PlasmaWidgets
--import org.kde.qtextracomponents 0.1
--
--PlasmaComponents.ListItem {
--    id: notificationItem
--    width: popupFlickable.width
--
--    property int toolIconSize: theme.smallMediumIconSize
--    property int layoutSpacing: 4
--
--    function getData(data, name, defaultValue) {
--        return data[modelData] ? (data[modelData][name] ? data[modelData][name] : defaultValue) : defaultValue;
--    }
--
--    property string labelName0: getData(jobsSource.data, "labelName0", '')
--    property string label0: getData(jobsSource.data, "label0", '')
--    property string labelName1: getData(jobsSource.data, "labelName1", '')
--    property string label1: getData(jobsSource.data, "label1", '')
--    property string jobstate: getData(jobsSource.data, "state", '')
--    property int eta: getData(jobsSource.data, "eta", 0)
--    property string speed: getData(jobsSource.data, "speed", '')
--
--    Column {
--        spacing: notificationItem.layoutSpacing
--        width: parent.width
--        PlasmaComponents.Label {
--            text: getData(jobsSource.data, "infoMessage", '')
--            font.bold: true
--            color: theme.textColor
--            anchors.horizontalCenter: parent.horizontalCenter
--        }
--        Grid {
--            anchors {
--                left: parent.left
--                right: parent.right
--                rightMargin: notificationItem.layoutSpacing
--            }
--            spacing: notificationItem.layoutSpacing
--            rows: 4
--            columns: 2
--
--            PlasmaComponents.Label {
--                id: labelName0Text
--                text: labelName0 ? i18n("%1:", labelName0) : ''
--                width: Math.max(paintedWidth, labelName1Text.paintedWidth)
--                horizontalAlignment: Text.AlignRight
--                visible: labelName0 != ''
--            }
--            PlasmaComponents.Label {
--                id: label0Text
--                text: label0 ? label0 : ''
--                width: parent.width - labelName0Text.width
--                elide: Text.ElideMiddle
--                visible: label0 != ''
--
--                PlasmaCore.ToolTip {
--                    target: label0Text
--                    subText: label0Text.truncated ? label0 : ""
--                }
--
--            }
--            PlasmaComponents.Label {
--                id: labelName1Text
--                text: labelName1 ? i18n("%1:", labelName1) : ''
--                width: Math.max(paintedWidth, labelName0Text.paintedWidth)
--                horizontalAlignment: Text.AlignRight
--                visible: labelName1 != ''
--            }
--            PlasmaComponents.Label {
--                id: label1Text
--                text: label1 ? label1 : ''
--                width: parent.width - labelName0Text.width
--                elide: Text.ElideMiddle
--                visible: label1 != ''
--
--                PlasmaCore.ToolTip {
--                    target: label1Text
--                    subText: label1Text.truncated ? label1 : ""
--                }
--            }
--            QIconItem {
--                icon: getData(jobsSource.data, "appIconName", '')
--                width: notificationItem.toolIconSize
--                height: width
--                anchors {
--                    verticalCenter: progressItem.verticalCenter
--                    right: progressItem.left
--                    rightMargin: notificationItem.layoutSpacing
--                }
--            }
--            Item {
--                id: progressItem
--                width: parent.width - labelName0Text.width
--                height: childrenRect.height
--                PlasmaComponents.ProgressBar {
--                    width: parent.width - pauseButton.width*2 - theme.largeIconSize - notificationItem.layoutSpacing*3
--                    height: 16
--                    orientation: Qt.Horizontal
--                    minimumValue: 0
--                    maximumValue: 100
--                    //percentage doesn't always exist, so doesn't get in the model
--                    value: getData(jobsSource.data, "percentage", 0)
--
--                    anchors {
--                        left: parent.left
--                        right: buttonsRow.left
--                        verticalCenter: parent.verticalCenter
--                        rightMargin: notificationItem.layoutSpacing
--                    }
--                }
--                Row {
--                    id: buttonsRow
--                    spacing: notificationItem.layoutSpacing
--                    anchors.right: parent.right
--                    PlasmaComponents.ToolButton {
--                        id: pauseButton
--                        width: notificationItem.toolIconSize
--                        height: width
--                        iconSource: jobstate == "suspended" ? "media-playback-start" : "media-playback-pause"
--                        flat: false
--                        onClicked: {
--                            var operationName = "suspend"
--                            if (jobstate == "suspended") {
--                                operationName = "resume"
--                            }
--                            var service = jobsSource.serviceForSource(modelData)
--                            var operation = service.operationDescription(operationName)
--                            service.startOperationCall(operation)
--                        }
--                    }
--                    PlasmaComponents.ToolButton {
--                        id: stopButton
--                        width: notificationItem.toolIconSize
--                        height: width
--                        iconSource: "media-playback-stop"
--                        flat: false
--                        onClicked: {
--                            var service = jobsSource.serviceForSource(modelData)
--                            var operation = service.operationDescription("stop")
--                            service.startOperationCall(operation)
--                        }
--                    }
--                }
--            }
--            PlasmaComponents.ToolButton {
--                id: expandButton
--                width: notificationItem.toolIconSize
--                height: width
--                flat: false
--                iconSource: checked ? "list-remove" : "list-add"
--                checkable: true
--                anchors {
--                    right: speedLabel.left
--                    rightMargin: notificationItem.layoutSpacing
--                    verticalCenter: speedLabel.verticalCenter
--                }
--            }
--            PlasmaComponents.Label {
--                id: speedLabel
--                text: eta > 0 ? i18nc("Speed and estimated time to completition", "%1 (%2 remaining)", speed, locale.prettyFormatDuration(eta)) : speed
--            }
--        }
--
--
--        Item {
--            id: detailsItem
--            state: expandButton.checked ? "expanded" : "collapsed"
--            anchors {
--                left: parent.left
--                right: parent.right
--                leftMargin: speedLabel.x
--            }
--            property Item contentsItem
--            Component {
--                id: detailsComponent
--                Column {
--                    id: detailsColumn
--                    anchors {
--                        left: parent.left
--                        right: parent.right
--                    }
--
--                    function localizeProcessedAmount(id) {
--                        //if bytes localise the unit
--                        if (jobsSource.data[modelData]["processedUnit"+id] == "bytes") {
--                            return i18nc("How much many bytes (or whether unit in the locale has been copied over total", "%1 of %2",
--                                    locale.formatByteSize(jobsSource.data[modelData]["processedAmount"+id]),
--                                    locale.formatByteSize(jobsSource.data[modelData]["totalAmount"+id]))
--                        //else print something only if is interesting data (ie more than one file/directory etc to copy
--                        } else if (jobsSource.data[modelData]["totalAmount"+id] > 1) {
--                            return i18n( "%1 of %2 %3",
--                                    jobsSource.data[modelData]["processedAmount"+id],
--                                    jobsSource.data[modelData]["totalAmount"+id],
--                                    jobsSource.data[modelData]["processedUnit"+id])
--                        } else {
--                            return ""
--                        }
--                    }
--                    PlasmaComponents.Label {
--                        text: jobsSource.data[modelData] ? detailsColumn.localizeProcessedAmount(0) : ""
--                        anchors.left: parent.left
--                        visible: text != ""
--                    }
--                    PlasmaComponents.Label {
--                        text: jobsSource.data[modelData] ? detailsColumn.localizeProcessedAmount(1) : ""
--                        anchors.left: parent.left
--                        visible: text != ""
--                    }
--                    PlasmaComponents.Label {
--                        text: jobsSource.data[modelData] ? detailsColumn.localizeProcessedAmount(2) : ""
--                        anchors.left: parent.left
--                        visible: text != ""
--                    }
--                    PlasmaWidgets.SignalPlotter {
--                        id: plotter
--                        width: parent.width
--                        useAutoRange: true
--                        showVerticalLines: false
--                        unit: i18n("KiB/s")
--                        height: theme.defaultFont.mSize.height * 5
--                        Component.onCompleted: plotter.addPlot(theme.highlightColor)
--                    }
--                    Connections {
--                        target: jobsSource
--                        onDataChanged: {
--                            plotter.addSample([jobsSource.data[modelData]["numericSpeed"]/1000])
--                        }
--                    }
--                }
--            }
--
--            states: [
--                State {
--                    name: "expanded"
--                    PropertyChanges {
--                        target: detailsItem
--                        height: detailsItem.childrenRect.height
--                    }
--                },
--                State {
--                    name: "collapsed"
--                    PropertyChanges {
--                        target: detailsItem
--                        height: 0
--                    }
--                }
--            ]
--            transitions : [
--                Transition {
--                    from: "collapsed"
--                    to: "expanded"
--                    SequentialAnimation {
--                        ScriptAction {
--                            script: {
--                                detailsItem.visible = true
--                                detailsItem.clip = true
--                                //create the contents if they don't exist yet
--                                if (!detailsItem.contentsItem) {
--                                    detailsItem.contentsItem = detailsComponent.createObject(detailsItem)
--                                }
--                            }
--                        }
--                        NumberAnimation {
--                            duration: 250
--                            properties: "height"
--                            easing: PropertyAnimation.EaseInOut
--                        }
--                        ScriptAction {script: detailsItem.clip = false}
--                    }
--                },
--                Transition {
--                    from: "expanded"
--                    to: "collapsed"
--                    SequentialAnimation {
--                        ScriptAction {script: detailsItem.clip = true}
--                        NumberAnimation {
--                            duration: 250
--                            properties: "height"
--                            easing: PropertyAnimation.EaseInOut
--                        }
--                        //TODO: delete the details?
--                        ScriptAction {script: detailsItem.visible = false}
--                    }
--                }
--            ]
--        }
--    }
--}
-diff --git a/plasma/generic/applets/notifications/contents/ui/Jobs.qml b/plasma/generic/applets/notifications/contents/ui/Jobs.qml
-deleted file mode 100644
-index 7e2f2a2..0000000
---- a/plasma/generic/applets/notifications/contents/ui/Jobs.qml
-+++ /dev/null
-@@ -1,105 +0,0 @@
--/*
-- *   Copyright 2012 Marco Martin <notmart@gmail.com>
-- *
-- *   This program 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, 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 Library General Public License for more details
-- *
-- *   You should have received a copy of the GNU Library 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.
-- */
--
--import QtQuick 1.1
--import org.kde.plasma.core 0.1 as PlasmaCore
--import org.kde.plasma.components 0.1 as PlasmaComponents
--
--Column {
--    id: jobsRoot
--    property alias count: jobsRepeater.count
--    anchors {
--        left: parent.left
--        right: parent.right
--    }
--
--    PlasmaCore.DataSource {
--        id: jobsSource
--        engine: "applicationjobs"
--        interval: 0
--
--        onSourceAdded: {
--            connectSource(source);
--        }
--        property variant runningJobs
--
--        onSourceRemoved: {
--            if (!notifications) {
--                return
--            }
--            var message = runningJobs[source]["label1"] ? runningJobs[source]["label1"] : runningJobs[source]["label0"]
--            notifications.addNotification(
--                source,
--                runningJobs[source]["appIconName"],
--                0,
--                runningJobs[source]["appName"],
--                i18n("%1 [Finished]", runningJobs[source]["infoMessage"]),
--                message,
--                0,
--                0,
--                [{"id": message, "text": i18n("Open")}])
--            delete runningJobs[source]
--        }
--        Component.onCompleted: {
--            jobsSource.runningJobs = new Object
--            connectedSources = sources
--        }
--        onNewData: {
--            var jobs = runningJobs
--            jobs[sourceName] = data
--            runningJobs = jobs
--        }
--        onDataChanged: {
--            var total = 0
--            for (var i = 0; i < sources.length; ++i) {
--                if (jobsSource.data[sources[i]]["percentage"]) {
--                    total += jobsSource.data[sources[i]]["percentage"]
--                }
--            }
--
--            total /= sources.length
--            notificationsApplet.globalProgress = total/100
--        }
--    }
--
--    Title {
--        visible: jobsRepeater.count > 0 && notifications && notifications.count > 0
--        text: i18n("Transfers")
--    }
--    PlasmaComponents.ListItem {
--        visible: jobsRepeater.count > 1
--        PlasmaComponents.ProgressBar {
--            anchors {
--                verticalCenter: parent.verticalCenter
--                left: parent.left
--                right: parent.right
--            }
--            minimumValue: 0
--            maximumValue: 100
--            value: notificationsApplet.globalProgress * 100
--        }
--    }
--    Repeater {
--        id: jobsRepeater
--        model: jobsSource.sources
--        delegate: JobDelegate {
--            toolIconSize: notificationsApplet.toolIconSize
--        }
--    }
--}
-\ No newline at end of file
-diff --git a/plasma/generic/applets/notifications/contents/ui/LastNotificationPopup.qml b/plasma/generic/applets/notifications/contents/ui/LastNotificationPopup.qml
-deleted file mode 100644
-index 26bce0f..0000000
---- a/plasma/generic/applets/notifications/contents/ui/LastNotificationPopup.qml
-+++ /dev/null
-@@ -1,414 +0,0 @@
--/***************************************************************************
-- *   Copyright 2011 Davide Bettio <davide.bettio@kdemail.net>              *
-- *   Copyright 2011 Marco Martin <mart@kde.org>                            *
-- *                                                                         *
-- *   This program 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 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 Library General Public License for more details.                          *
-- *                                                                         *
-- *   You should have received a copy of the GNU Library 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 .        *
-- ***************************************************************************/
--
--import QtQuick 1.1
--import org.kde.plasma.core 0.1 as PlasmaCore
--import org.kde.plasma.components 0.1 as PlasmaComponents
--import org.kde.qtextracomponents 0.1
--import org.kde.plasma.extras 0.1 as PlasmaExtras
--
--
--PlasmaCore.Dialog {
--    id: lastNotificationPopup
--
--    property variant savedPos
--    property bool customPosition: false
--
--    onHeightChanged:  setCustomPosition(lastNotificationPopup.savedPos, false)
--    onWidthChanged:   setCustomPosition(lastNotificationPopup.savedPos, false)
--
--    function popup(notification)
--    {
--        if (!lastNotificationPopup.visible) {
--            lastNotificationsModel.clear()
--        }
--        lastNotificationsModel.append(notification)
--
--        setCustomPosition(lastNotificationPopup.savedPos, false)
--
--        lastNotificationPopup.visible = true
--        lastNotificationTimer.interval = Math.max(4000, Math.min(60*1000, notificationsModel.get(0).expireTimeout))
--        notificationsView.currentIndex = lastNotificationsModel.count - 1
--        lastNotificationTimer.restart()
--        mainItem.buttonPressed = false
--    }
--
--    function setCustomPosition(pos, writeConfig)
--    {
--        var popupPos = lastNotificationPopup.popupPosition(notificationIcon, Qt.AlignCenter)
--        var finalPos
--
--        //custom
--        if ((pos.x >= 0 || pos.y >= 0) &&
--            (Math.abs(popupPos.x - pos.x) > 40 ||
--            Math.abs(popupPos.y - pos.y) > 40)) {
--            finalPos = pos
--            if (writeConfig) {
--                plasmoid.writeConfig("CustomPosition", pos)
--                lastNotificationPopup.savedPos = pos
--                lastNotificationPopup.customPosition = true
--            }
--        } else {
--            finalPos = popupPos
--            if (writeConfig) {
--                plasmoid.writeConfig("CustomPosition", QPoint(-1,-1))
--                lastNotificationPopup.savedPos = QPoint(-1,-1)
--                lastNotificationPopup.customPosition = false
--            }
--        }
--        lastNotificationPopup.x = finalPos.x
--        lastNotificationPopup.y = finalPos.y
--    }
--
--    location: customPosition ? Floating : plasmoid.location
--    windowFlags: Qt.WindowStaysOnTopHint
--    Component.onCompleted: {
--        setAttribute(Qt.WA_X11NetWmWindowTypeDock, true)
--
--        lastNotificationPopup.savedPos = plasmoid.readConfig("CustomPosition")
--        setCustomPosition(lastNotificationPopup.savedPos, true)
--        plasmoid.popupEvent.connect(lastNotificationPopup.popupEvent)
--    }
--
--    function popupEvent(popupShowing)
--    {
--        if(popupShowing) {
--           lastNotificationPopup.visible = false
--        }
--    }
--
--    mainItem: MouseEventListener {
--        id: mainItem
--        width: maximumWidth
--        height: maximumHeight
--        property int maximumWidth: theme.defaultFont.mSize.width * 35
--        property int maximumHeight: theme.defaultFont.mSize.width * 10
--        property int minimumWidth: maximumWidth
--        property int minimumHeight: maximumHeight
--
--        property int startX: 0
--        property int startY: 0
--        property int startScreenX: 0
--        property int startScreenY: 0
--        hoverEnabled: true
--        property bool buttonPressed: false
--
--        state: "controlsHidden"
--        onContainsMouseChanged: {
--            if (containsMouse) {
--                mainItem.state = "controlsShown"
--                lastNotificationTimer.running = false
--            } else {
--                mainItem.state = "controlsHidden"
--                lastNotificationTimer.restart()
--            }
--        }
--        onPressed: {
--            startX = mouse.x + lastNotificationPopup.margins.left
--            startY = mouse.y + lastNotificationPopup.margins.top
--            startScreenX = mouse.screenX
--            startScreenY = mouse.screenY
--            lastNotificationTimer.running = false
--        }
--        onReleased: {
--            //FIXME: bind startdragdistance
--            if ((navigationButtonsColumn.visible && mouse.x < navigationButtonsColumn.width) ||
--                buttonPressed ||
--                Math.sqrt(Math.pow(startScreenX - mouse.screenX, 2) + Math.pow(startScreenY - mouse.screenY, 2)) > 4) {
--            } else {
--                lastNotificationPopup.visible = false
--            }
--
--            setCustomPosition(QPoint(Math.max(0, mouse.screenX - startX), Math.max(mouse.screenY - startY)), true)
--        }
--        onPositionChanged: {
--            lastNotificationPopup.x = Math.max(0, mouse.screenX - startX)
--            lastNotificationPopup.y = Math.max(0, mouse.screenY - startY)
--        }
--        onWheelMoved: {
--            if (notificationsView.moving) {
--                return
--            }
--
--            if (wheel.delta > 0) {
--                notificationsView.currentIndex = Math.max(0, notificationsView.currentIndex-1)
--            } else {
--                notificationsView.currentIndex = Math.min(notificationsView.count-1, notificationsView.currentIndex+1)
--            }
--        }
--
--        Timer {
--            id: lastNotificationTimer
--            interval: 4000
--            repeat: false
--            running: false
--            onTriggered: lastNotificationPopup.visible = false
--        }
--
--        ListView {
--            id: notificationsView
--            clip: true
--            snapMode: ListView.SnapOneItem
--            orientation: ListView.Horizontal
--            anchors.fill: parent
--            model: ListModel {
--                id: lastNotificationsModel
--            }
--            interactive: false
--            delegate: Item {
--                height: notificationsView.height
--                width: notificationsView.width
--
--                PlasmaComponents.Label {
--                    id: titleLabel
--                    text: model.summary
--                    //font.weight: Font.Bold
--                    visible: model.summary.length > 0
--                    height: model.summary.length > 0 ? paintedHeight : 0
--                    horizontalAlignment: Text.AlignHCenter
--                    color: theme.textColor
--                    elide: Text.ElideRight
--                    anchors {
--                        left: appIconItem.y > y + height ? parent.left : appIconItem.right
--                        right: parent.right
--                        rightMargin: settingsButton.visible ? settingsButton.width + closeButton.width : closeButton.width
--                        top: parent.top
--                        topMargin: 6
--                        leftMargin: 6
--                    }
--                    onLinkActivated: plasmoid.openUrl(link)
--                }
--
--                QIconItem {
--                    id: appIconItem
--                    icon: model.appIcon
--                    width: (model.appIcon.length > 0 || imageItem.visible) ? theme.largeIconSize : 0
--                    height: theme.largeIconSize
--                    visible: !imageItem.visible
--                    anchors {
--                        left: parent.left
--                        verticalCenter: parent.verticalCenter
--                        leftMargin: navigationButtonsColumn.width
--                    }
--                }
--                QImageItem {
--                    id: imageItem
--                    anchors.fill: appIconItem
--                    image: model.image
--                    smooth: true
--                    visible: nativeWidth > 0
--                }
--               /*
--                * this extra item is for clip the overflowed body text
--                * maximumLineCount cannot control the behavior of rich text,
--                * so manual clip is required.
--                */
--                Item {
--                    id: bodyLabel
--                    clip: true
--                    height: Math.min(parent.height - (titleLabel.height+titleLabel.y), lastNotificationText.height)
--                    property bool tallText: bodyLabel.height >= (bodyLabel.parent.height - (titleLabel.height+titleLabel.y)*2)
--                    anchors {
--                        top: tallText ? titleLabel.bottom : undefined
--                        verticalCenter: tallText ? undefined : parent.verticalCenter
--                        left: appIconItem.right
--                        right: actionsColumn.left
--                        leftMargin: 6
--                        rightMargin: 6
--                    }
--                    PlasmaComponents.Label {
--                        id: lastNotificationText
--                        text: model.body
--                        width: parent.width
--                        //textFormat: Text.PlainText
--                        color: theme.textColor
--                        wrapMode: Text.Wrap
--                        elide: Text.ElideRight
--                        maximumLineCount: 4
--                        onLinkActivated: plasmoid.openUrl(link)
--                    }
--                }
--                Column {
--                    id: actionsColumn
--                    spacing: 6
--                    anchors {
--                        right: parent.right
--                        rightMargin: 6
--                        verticalCenter: parent.verticalCenter
--                    }
--                    Repeater {
--                        model: actions
--                        PlasmaComponents.Button {
--                            text: model.text
--                            width: theme.defaultFont.mSize.width * 8
--                            height: theme.defaultFont.mSize.width * 2
--                            onPressedChanged: {
--                                if (pressed) {
--                                    mainItem.buttonPressed = true
--                                } else {
--                                    mainItem.buttonPressed = false
--                                }
--                            }
--                            onClicked: {
--                                executeAction(source, model.id)
--                                actionsColumn.visible = false
--                            }
--                        }
--                    }
--                }
--            }
--        }
--
--        Column {
--            id: navigationButtonsColumn
--            opacity: 0
--            visible: backButton.enabled || nextButton.enabled
--            anchors {
--                left: parent.left
--                verticalCenter: parent.verticalCenter
--            }
--
--            PlasmaComponents.ToolButton {
--                id: nextButton
--                iconSource: "go-next"
--                width: theme.smallMediumIconSize
--                height: mainItem.height/2 - 4
--                enabled: notificationsView.currentIndex < notificationsView.count-1
--                onPressedChanged: {
--                    if (pressed) {
--                        mainItem.buttonPressed = true
--                    } else {
--                        mainItem.buttonPressed = false
--                    }
--                }
--                onClicked: {
--                    notificationsView.currentIndex = Math.min(notificationsView.count-1, notificationsView.currentIndex+1)
--                }
--            }
--
--            PlasmaComponents.ToolButton {
--                id: backButton
--                iconSource: "go-previous"
--                width: theme.smallMediumIconSize
--                height: mainItem.height/2 - 4
--                enabled: notificationsView.currentIndex > 0
--                onPressedChanged: {
--                    if (pressed) {
--                        mainItem.buttonPressed = true
--                    } else {
--                        mainItem.buttonPressed = false
--                    }
--                }
--                onClicked: {
--                    notificationsView.currentIndex = Math.max(0, notificationsView.currentIndex-1)
--                }
--            }
--        }
--        PlasmaComponents.ToolButton {
--            id: closeButton
--            opacity: 0
--            iconSource: "window-close"
--            width: theme.smallMediumIconSize
--            height: width
--            anchors {
--                right: parent.right
--                top: parent.top
--            }
--            onPressedChanged: {
--                if (pressed) {
--                    mainItem.buttonPressed = true
--                } else {
--                    mainItem.buttonPressed = false
--                }
--            }
--            onClicked: {
--                lastNotificationPopup.visible = false
--                lastNotificationTimer.running = false
--                closeNotification(notificationsModel.get((notificationsView.count-1)-notificationsView.currentIndex).source)
--                notificationsModel.remove((notificationsView.count-1)-notificationsView.currentIndex)
--            }
--        }
--        PlasmaComponents.ToolButton {
--            id: settingsButton
--            opacity: 0
--            iconSource: "configure"
--            width: theme.smallMediumIconSize
--            height: width
--            visible: notificationsModel.get((notificationsView.count-1)-notificationsView.currentIndex).configurable
--            anchors {
--                right: closeButton.left
--                top: parent.top
--                rightMargin: 5
--            }
--            onPressedChanged: {
--                if (pressed) {
--                    mainItem.buttonPressed = true
--                } else {
--                    mainItem.buttonPressed = false
--                }
--            }
--            onClicked: {
--                lastNotificationPopup.visible = false
--                configureNotification(notificationsModel.get((notificationsView.count-1)-notificationsView.currentIndex).appRealName)
--            }
--        }
--        states: [
--            State {
--                name: "controlsShown"
--                PropertyChanges {
--                    target: navigationButtonsColumn
--                    opacity: 1
--                }
--                PropertyChanges {
--                    target: closeButton
--                    opacity: 1
--                }
--                PropertyChanges {
--                    target: settingsButton
--                    opacity: 1
--                }
--            },
--            State {
--                name: "controlsHidden"
--                PropertyChanges {
--                    target: navigationButtonsColumn
--                    opacity: 0
--                }
--                PropertyChanges {
--                    target: closeButton
--                    opacity: 0
--                }
--                PropertyChanges {
--                    target: settingsButton
--                    opacity: 0
--                }
--            }
--        ]
--        transitions: [
--            Transition {
--             NumberAnimation {
--                 properties: "opacity"
--                 easing.type: Easing.InOutQuad
--                 duration: 250
--            }
--         }
--        ]
--    }
--}
-diff --git a/plasma/generic/applets/notifications/contents/ui/NotificationDelegate/NotificationDelegate.qml b/plasma/generic/applets/notifications/contents/ui/NotificationDelegate/NotificationDelegate.qml
-deleted file mode 100644
-index bf33eb1..0000000
---- a/plasma/generic/applets/notifications/contents/ui/NotificationDelegate/NotificationDelegate.qml
-+++ /dev/null
-@@ -1,253 +0,0 @@
--/*
-- *   Copyright 2011 Marco Martin <notmart@gmail.com>
-- *
-- *   This program 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, 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 Library General Public License for more details
-- *
-- *   You should have received a copy of the GNU Library 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.
-- */
--
--import QtQuick 1.1
--import org.kde.plasma.core 0.1 as PlasmaCore
--import org.kde.plasma.components 0.1 as PlasmaComponents
--import org.kde.qtextracomponents 0.1
--
--PlasmaComponents.ListItem {
--    id: notificationItem
--    opacity: 1-Math.abs(x)/width
--    width: popupFlickable.width
--    property int toolIconSize: theme.smallMediumIconSize
--    property int layoutSpacing: 4
--
--    visible: appTabBar.currentTab == allAppsTab || appTabBar.currentTab.text == appName
--
--    Component.onCompleted: {
--        allApplicationsModel.addApplication(appIcon, appName)
--        mainScrollArea.height = mainScrollArea.implicitHeight
--    }
--    Component.onDestruction: {
--        allApplicationsModel.removeApplication(model.appName)
--        mainScrollArea.height = mainScrollArea.implicitHeight
--    }
--    Timer {
--        interval: 10*60*1000
--        repeat: false
--        running: !idleTimeSource.idle
--        onTriggered: {
--            notificationsModel.remove(index)
--        }
--    }
--
--    MouseArea {
--        width: parent.width
--        height: childrenRect.height
--        drag {
--            target: notificationItem
--            axis: Drag.XAxis
--            //kind of an hack over Column being too smart
--            minimumX: -parent.width + 1
--            maximumX: parent.width - 1
--        }
--        onReleased: {
--            if (notificationItem.x < -notificationItem.width/2) {
--                removeAnimation.exitFromRight = false
--                removeAnimation.running = true
--            } else if (notificationItem.x > notificationItem.width/2 ) {
--                removeAnimation.exitFromRight = true
--                removeAnimation.running = true
--            } else {
--                resetAnimation.running = true
--            }
--        }
--        SequentialAnimation {
--            id: removeAnimation
--            property bool exitFromRight: true
--            NumberAnimation {
--                target: notificationItem
--                properties: "x"
--                to: removeAnimation.exitFromRight ? notificationItem.width-1 : 1-notificationItem.width
--                duration: 250
--                easing.type: Easing.InOutQuad
--            }
--            NumberAnimation {
--                target: notificationItem
--                properties: "height"
--                to: 0
--                duration: 250
--                easing.type: Easing.InOutQuad
--            }
--            ScriptAction {
--                script: notificationsModel.remove(index)
--            }
--        }
--        SequentialAnimation {
--            id: resetAnimation
--            NumberAnimation {
--                target: notificationItem
--                properties: "x"
--                to: 0
--                duration: 250
--                easing.type: Easing.InOutQuad
--            }
--        }
--        Column {
--            spacing: notificationItem.layoutSpacing
--            width: parent.width
--            Item {
--                width: parent.width
--                height: summaryLabel.height
--
--                PlasmaComponents.Label {
--                    id: summaryLabel
--                    text: summary
--                    height: paintedHeight
--                    anchors {
--                        left: parent.left
--                        right: parent.right
--                        leftMargin: closeButton.width
--                        rightMargin: settingsButton.visible ? settingsButton.width + closeButton.width : closeButton.width
--                    }
--                    horizontalAlignment: Text.AlignHCenter
--                    elide: Text.ElideRight
--                    onLinkActivated: plasmoid.openUrl(link)
--                }
--
--                PlasmaComponents.ToolButton {
--                    id: closeButton
--                    iconSource: "window-close"
--                    width: notificationItem.toolIconSize
--                    height: width
--                    onClicked: {
--                        if (notificationsModel.count > 1) {
--                            removeAnimation.running = true
--                        } else {
--                            closeNotification(model.source)
--                            notificationsModel.remove(index)
--                        }
--                    }
--                    anchors {
--                        top: parent.top
--                        right: parent.right
--                    }
--                }
--
--                PlasmaComponents.ToolButton {
--                    id: settingsButton
--                    iconSource: "configure"
--                    width: notificationItem.toolIconSize
--                    height: width
--                    visible: model.configurable
--                    onClicked: {
--                        plasmoid.hidePopup()
--                        configureNotification(model.appRealName)
--                    }
--                    anchors {
--                        top: parent.top
--                        right: closeButton.left
--                        rightMargin: 5
--                    }
--                }
--            }
--
--            Item {
--                height: childrenRect.height
--                width: parent.width
--                QIconItem {
--                    id: appIconItem
--                    icon: QIcon(appIcon)
--                    width: theme.largeIconSize
--                    height: theme.largeIconSize
--                    visible: !imageItem.visible
--                    anchors {
--                        left: parent.left
--                        verticalCenter: parent.verticalCenter
--                    }
--                }
--                QImageItem {
--                    id: imageItem
--                    anchors.fill: appIconItem
--                    image: model.image
--                    smooth: true
--                    visible: nativeWidth > 0
--                }
--                PlasmaComponents.ContextMenu {
--                    id: contextMenu
--                    visualParent: contextMouseArea
--                    PlasmaComponents.MenuItem {
--                        text: i18n("Copy")
--                        onClicked: bodyText.copy()
--                    }
--                    PlasmaComponents.MenuItem {
--                        text: i18n("Select All")
--                        onClicked: bodyText.selectAll()
--                    }
--                }
--                MouseArea {
--                    id: contextMouseArea
--                    anchors {
--                        left: appIconItem.right
--                        right: actionsColumn.left
--                        verticalCenter: parent.verticalCenter
--                        leftMargin: 6
--                        rightMargin: 6
--                    }
--                    acceptedButtons: Qt.RightButton
--                    height: bodyText.paintedHeight
--                    preventStealing: true
--                    onPressed: contextMenu.open(mouse.x, mouse.y)
--                    TextEdit {
--                        id: bodyText
--                        anchors.fill: parent
--                        text: body
--                        color: theme.textColor
--                        font.capitalization: theme.defaultFont.capitalization
--                        font.family: theme.defaultFont.family
--                        font.italic: theme.defaultFont.italic
--                        font.letterSpacing: theme.defaultFont.letterSpacing
--                        font.pointSize: theme.defaultFont.pointSize
--                        font.strikeout: theme.defaultFont.strikeout
--                        font.underline: theme.defaultFont.underline
--                        font.weight: theme.defaultFont.weight
--                        font.wordSpacing: theme.defaultFont.wordSpacing
--                        selectByMouse: true
--                        readOnly: true
--                        wrapMode: Text.Wrap
--                        textFormat: TextEdit.RichText
--                        onLinkActivated: plasmoid.openUrl(link)
--                    }
--                }
--                Column {
--                    id: actionsColumn
--                    spacing: notificationItem.layoutSpacing
--                    anchors {
--                        right: parent.right
--                        rightMargin: 6
--                        verticalCenter: parent.verticalCenter
--                    }
--                    Repeater {
--                        model: actions
--                        PlasmaComponents.Button {
--                            text: model.text
--                            width: theme.defaultFont.mSize.width * 8
--                            height: theme.defaultFont.mSize.width * 2
--                            onClicked: {
--                                executeAction(source, model.id)
--                                actionsColumn.visible = false
--                            }
--                        }
--                    }
--                }
--            }
--        }
--    }
--}
-diff --git a/plasma/generic/applets/notifications/contents/ui/NotificationDelegate/qmldir b/plasma/generic/applets/notifications/contents/ui/NotificationDelegate/qmldir
-deleted file mode 100644
-index 88fc37a..0000000
---- a/plasma/generic/applets/notifications/contents/ui/NotificationDelegate/qmldir
-+++ /dev/null
-@@ -1 +0,0 @@
--NotificationDelegate 0.1 NotificationDelegate.qml
-diff --git a/plasma/generic/applets/notifications/contents/ui/NotificationIcon.qml b/plasma/generic/applets/notifications/contents/ui/NotificationIcon.qml
-deleted file mode 100644
-index f12cd56..0000000
---- a/plasma/generic/applets/notifications/contents/ui/NotificationIcon.qml
-+++ /dev/null
-@@ -1,188 +0,0 @@
--/***************************************************************************
-- *   Copyright 2011 Davide Bettio <davide.bettio@kdemail.net>              *
-- *   Copyright 2011 Marco Martin <mart@kde.org>                            *
-- *                                                                         *
-- *   This program 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 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 Library General Public License for more details.                          *
-- *                                                                         *
-- *   You should have received a copy of the GNU Library 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 .        *
-- ***************************************************************************/
--
--import QtQuick 1.1
--import org.kde.plasma.core 0.1 as PlasmaCore
--import org.kde.plasma.components 0.1 as PlasmaComponents
--import org.kde.qtextracomponents 0.1
--import org.kde.plasma.extras 0.1 as PlasmaExtras
--
--
--Item {
--    PlasmaCore.SvgItem {
--        id: notificationSvgItem
--        svg: notificationSvg
--        elementId: "notification-disabled"
--        anchors.centerIn: parent
--        width: Math.min(parent.width, parent.height)
--        height: width
--        state: notificationsApplet.state
--
--        PlasmaCore.Svg {
--            id: notificationSvg
--            imagePath: "icons/notification"
--        }
--
--        Item {
--            id: jobProgressItem
--            width: notificationSvgItem.width * globalProgress
--            clip: true
--            visible: jobs.count > 0
--            anchors {
--                left: parent.left
--                top: parent.top
--                bottom: parent.bottom
--            }
--            PlasmaCore.SvgItem {
--                svg: notificationSvg
--                elementId: "notification-progress-active"
--                anchors {
--                    left: parent.left
--                    top: parent.top
--                    bottom: parent.bottom
--                }
--                width: notificationSvgItem.width
--            }
--        }
--        PlasmaComponents.BusyIndicator {
--            anchors.fill: parent
--            visible: jobs ? jobs.count > 0 : false
--            running: visible
--        }
--
--        Column {
--            id: countColumn
--            visible: false
--            anchors.centerIn: parent
--            PlasmaCore.SvgItem {
--                svg: notificationSvg
--                elementId: {
--                    switch (plasmoid.location) {
--                    case TopEdge:
--                        return "expander-top"
--                    case LeftEdge:
--                        return "expander-left"
--                    case RightEdge:
--                        return "expander-right"
--                    default:
--                        return "expander-bottom"
--                    }
--                }
--                width: naturalSize.width
--                height: naturalSize.height
--                anchors.horizontalCenter: parent.horizontalCenter
--            }
--            PlasmaComponents.Label {
--                property int totalCount: notificationsApplet.totalCount
--                text: totalCount
--
--                property int oldTotalCount: 0
--                font.pointSize: theme.smallestFont.pointSize
--                height: paintedHeight - 3
--                onTotalCountChanged: {
--                    if (totalCount > oldTotalCount) {
--                        notificationAnimation.running = true
--                    }
--                    oldTotalCount = totalCount
--                }
--            }
--        }
--
--        PlasmaCore.SvgItem {
--            id: notificationAnimatedItem
--            anchors.fill: parent
--            svg: notificationSvg
--            elementId: "notification-active"
--            opacity: 0
--            scale: 2
--
--            SequentialAnimation {
--                id: notificationAnimation
--                NumberAnimation {
--                    target: notificationAnimatedItem
--                    duration: 250
--                    properties: "opacity, scale"
--                    to: 1
--                    easing.type: Easing.InOutQuad
--                }
--                PauseAnimation { duration: 500 }
--                ParallelAnimation {
--                    NumberAnimation {
--                        target: notificationAnimatedItem
--                        duration: 250
--                        properties: "opacity"
--                        to: 0
--                        easing.type: Easing.InOutQuad
--                    }
--                    NumberAnimation {
--                        target: notificationAnimatedItem
--                        duration: 250
--                        properties: "scale"
--                        to: 2
--                        easing.type: Easing.InOutQuad
--                    }
--                }
--            }
--        }
--        MouseArea {
--            anchors.fill: parent
--            onClicked: {
--                if (notificationsApplet.totalCount > 0) {
--                    plasmoid.togglePopup()
--                } else {
--                    plasmoid.hidePopup()
--                }
--            }
--        }
--        states: [
--            State {
--                name: "default"
--                PropertyChanges {
--                    target: notificationSvgItem
--                    elementId: "notification-disabled"
--                }
--                PropertyChanges {
--                    target: countColumn
--                    visible: false
--                }
--                PropertyChanges {
--                    target: plasmoid
--                    status: PassiveStatus
--                }
--            },
--            State {
--                name: "new-notifications"
--                PropertyChanges {
--                    target: notificationSvgItem
--                    elementId: jobs.count > 0 ? "notification-progress-inactive" : "notification-empty"
--                }
--                PropertyChanges {
--                    target: countColumn
--                    visible: true
--                }
--                PropertyChanges {
--                    target: plasmoid
--                    status: ActiveStatus
--                }
--            }
--        ]
--    }
--}
--
-diff --git a/plasma/generic/applets/notifications/contents/ui/Notifications.qml b/plasma/generic/applets/notifications/contents/ui/Notifications.qml
-deleted file mode 100644
-index 114ead2..0000000
---- a/plasma/generic/applets/notifications/contents/ui/Notifications.qml
-+++ /dev/null
-@@ -1,227 +0,0 @@
--/*
-- *   Copyright 2012 Marco Martin <notmart@gmail.com>
-- *
-- *   This program 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, 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 Library General Public License for more details
-- *
-- *   You should have received a copy of the GNU Library 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.
-- */
--
--import QtQuick 1.1
--import org.kde.plasma.core 0.1 as PlasmaCore
--import org.kde.plasma.components 0.1 as PlasmaComponents
--
--import "plasmapackage:/ui/NotificationDelegate"
--
--Column {
--    id: notificationsRoot
--    property alias count: notificationsRepeater.count
--    anchors {
--        left: parent.left
--        right: parent.right
--    }
--
--    function addNotification(source, appIcon, image, appName, summary, body, expireTimeout, urgency, appRealName, configurable, actions) {
--        // Do not show duplicated notifications
--        for (var i = 0; i < notificationsModel.count; ++i) {
--            if (notificationsModel.get(i).source == source &&
--                notificationsModel.get(i).appName == appName &&
--                notificationsModel.get(i).summary == summary &&
--                notificationsModel.get(i).body == body) {
--                return
--            }
--        }
--
--        for (var i = 0; i < notificationsModel.count; ++i) {
--            if (notificationsModel.get(i).source == source) {
--                notificationsModel.remove(i)
--                break
--            }
--        }
--        if (notificationsModel.count > 20) {
--            notificationsModel.remove(notificationsModel.count-1)
--        }
--        var notification = {"source"  : source,
--                "appIcon" : appIcon,
--                "image"   : image,
--                "appName" : appName,
--                "summary" : summary,
--                "body"    : body,
--                "expireTimeout": expireTimeout,
--                "urgency" : urgency,
--                "configurable": configurable,
--                "appRealName": appRealName,
--                "actions" : actions}
--        notificationsModel.insert(0, notification);
--        if (plasmoid.popupShowing) {
--            return
--        }
--        if (!lastNotificationPopup) {
--            lastNotificationPopup = lastNotificationPopupComponent.createObject(notificationsRoot)
--        }
--        lastNotificationPopup.popup(notification)
--    }
--
--    function executeAction(source, id) {
--        //try to use the service
--        if (source.indexOf("notification") !== -1) {
--            var service = notificationsSource.serviceForSource(source)
--            var op = service.operationDescription("invokeAction")
--            op["actionId"] = id
--
--            service.startOperationCall(op)
--        //try to open the id as url
--        } else if (source.indexOf("Job") !== -1) {
--            plasmoid.openUrl(id)
--        }
--    }
--
--    function configureNotification(appRealName) {
--      var service = notificationsSource.serviceForSource("notification")
--      var op = service.operationDescription("configureNotification")
--      op["appRealName"] = appRealName;
--      service.startOperationCall(op)
--    }
--
--    function closeNotification(source) {
--      var service = notificationsSource.serviceForSource(source)
--      var op = service.operationDescription("userClosed")
--      service.startOperationCall(op)
--    }
--
--    property QtObject lastNotificationPopup
--    Component {
--        id: lastNotificationPopupComponent
--        LastNotificationPopup {
--        }
--    }
--
--    ListModel {
--        id: notificationsModel
--    }
--    ListModel {
--        id: allApplicationsModel
--        function addApplication(icon, name)
--        {
--            for (var i = 0; i < count; ++i) {
--                var item = get(i)
--                if (item.name == name) {
--                    setProperty(i, "count", item.count + 1)
--                    return
--                }
--            }
--            append({"icon": icon, "name": name, "count": 1})
--        }
--        function removeApplication(name)
--        {
--            for (var i = 0; i < count; ++i) {
--                var item = get(i)
--                if (item.name == name) {
--                    if (item.count <= 1) {
--                        remove(i)
--                        appTabBar.currentTab = allAppsTab
--                        return
--                    }
--                    setProperty(i, "count", item.count - 1)
--                    return
--                }
--            }
--        }
--    }
--
--    PlasmaCore.DataSource {
--        id: idleTimeSource
--        engine: "powermanagement"
--        interval: 30000
--        connectedSources: ["UserActivity"]
--        //Idle whith more than 5 minutes of user inactivity
--        property bool idle: data["UserActivity"]["IdleTime"] > 300000
--    }
--
--    PlasmaCore.DataSource {
--        id: notificationsSource
--        engine: "notifications"
--        interval: 0
--
--        onSourceAdded: {
--            connectSource(source);
--        }
--
--        onNewData: {
--            var actions = new Array()
--            if (data["actions"] && data["actions"].length % 2 == 0) {
--                for (var i = 0; i < data["actions"].length; i += 2) {
--                    var action = new Object()
--                    action["id"] = data["actions"][i]
--                    action["text"] = data["actions"][i+1]
--                    actions.push(action)
--                }
--            }
--            notificationsRoot.addNotification(
--                    sourceName,
--                    data["appIcon"],
--                    data["image"],
--                    data["appName"],
--                    data["summary"],
--                    data["body"],
--                    data["expireTimeout"],
--                    data["urgency"],
--                    data["appRealName"],
--                    data["configurable"],
--                    actions)
--        }
--
--    }
--
--    Title {
--        visible: notificationsRepeater.count > 1 || (jobs && jobs.count > 0 && notificationsRepeater.count > 0)
--        text: i18n("Notifications")
--        PlasmaComponents.ToolButton {
--            iconSource: "window-close"
--            width: notificationsApplet.toolIconSize
--            height: width
--            anchors {
--                right: parent.right
--                verticalCenter: parent.verticalCenter
--            }
--            onClicked: notificationsModel.clear()
--        }
--    }
--    PlasmaComponents.ListItem {
--        visible: allApplicationsModel.count > 1
--        PlasmaComponents.TabBar {
--            id: appTabBar
--            anchors.horizontalCenter: parent.horizontalCenter
--            width: Math.min(implicitWidth, parent.width-8)
--            PlasmaComponents.TabButton {
--                id: allAppsTab
--                text: i18n("All")
--                iconSource: "dialog-information"
--            }
--            Repeater {
--                model: allApplicationsModel
--                PlasmaComponents.TabButton {
--                    text: name
--                    iconSource: icon
--                }
--            }
--        }
--    }
--    Repeater {
--        id: notificationsRepeater
--        model: notificationsModel
--        delegate: NotificationDelegate {
--            toolIconSize: notificationsApplet.toolIconSize
--        }
--    }
--}
-diff --git a/plasma/generic/applets/notifications/contents/ui/Title.qml b/plasma/generic/applets/notifications/contents/ui/Title.qml
-deleted file mode 100644
-index dff4f72..0000000
---- a/plasma/generic/applets/notifications/contents/ui/Title.qml
-+++ /dev/null
-@@ -1,43 +0,0 @@
--/*
-- *   Copyright 2012 Marco Martin <notmart@gmail.com>
-- *
-- *   This program 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, 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 Library General Public License for more details
-- *
-- *   You should have received a copy of the GNU Library 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.
-- */
--
--import QtQuick 1.1
--import org.kde.plasma.core 0.1 as PlasmaCore
--import org.kde.plasma.components 0.1 as PlasmaComponents
--
--PlasmaComponents.ListItem {
--    id: root
--    property alias text: titleLabel.text
--
--
--    sectionDelegate: true
--
--    width: parent.width
--
--    PlasmaComponents.Label {
--        id: titleLabel
--        horizontalAlignment: Text.AlignHCenter
--        elide: Text.ElideRight
--        anchors {
--            verticalCenter: parent.verticalCenter
--            left: parent.left
--            right: parent.right
--        }
--    }
--}
-diff --git a/plasma/generic/applets/notifications/contents/ui/config.ui b/plasma/generic/applets/notifications/contents/ui/config.ui
-deleted file mode 100644
-index 7769bba..0000000
---- a/plasma/generic/applets/notifications/contents/ui/config.ui
-+++ /dev/null
-@@ -1,69 +0,0 @@
--<?xml version="1.0" encoding="UTF-8"?>
--<ui version="4.0">
-- <class>feedsConfig</class>
-- <widget class="QWidget" name="feedsConfig">
--  <property name="geometry">
--   <rect>
--    <x>0</x>
--    <y>0</y>
--    <width>337</width>
--    <height>181</height>
--   </rect>
--  </property>
--  <layout class="QFormLayout" name="formLayout">
--   <item row="1" column="0">
--    <widget class="QLabel" name="label_2">
--     <property name="text">
--      <string>&amp;Application notifications:</string>
--     </property>
--     <property name="buddy">
--      <cstring>kcfg_ShowNotifications</cstring>
--     </property>
--    </widget>
--   </item>
--   <item row="1" column="1">
--    <widget class="QCheckBox" name="kcfg_ShowNotifications">
--     <property name="text">
--      <string/>
--     </property>
--    </widget>
--   </item>
--   <item row="2" column="0">
--    <widget class="QLabel" name="label_3">
--     <property name="text">
--      <string>&amp;File transfers and jobs:</string>
--     </property>
--     <property name="buddy">
--      <cstring>kcfg_ShowJobs</cstring>
--     </property>
--    </widget>
--   </item>
--   <item row="2" column="1">
--    <widget class="QCheckBox" name="kcfg_ShowJobs">
--     <property name="text">
--      <string/>
--     </property>
--    </widget>
--   </item>
--   <item row="0" column="0" colspan="2">
--    <widget class="QLabel" name="label">
--     <property name="font">
--      <font>
--       <weight>75</weight>
--       <bold>true</bold>
--      </font>
--     </property>
--     <property name="text">
--      <string>Choose which information to show</string>
--     </property>
--    </widget>
--   </item>
--  </layout>
-- </widget>
-- <tabstops>
--  <tabstop>kcfg_ShowNotifications</tabstop>
--  <tabstop>kcfg_ShowJobs</tabstop>
-- </tabstops>
-- <resources/>
-- <connections/>
--</ui>
-diff --git a/plasma/generic/applets/notifications/contents/ui/main.qml b/plasma/generic/applets/notifications/contents/ui/main.qml
-deleted file mode 100644
-index 4d4b0f7..0000000
---- a/plasma/generic/applets/notifications/contents/ui/main.qml
-+++ /dev/null
-@@ -1,171 +0,0 @@
--/***************************************************************************
-- *   Copyright 2011 Davide Bettio <davide.bettio@kdemail.net>              *
-- *   Copyright 2011 Marco Martin <mart@kde.org>                            *
-- *                                                                         *
-- *   This program 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 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 Library General Public License for more details.                          *
-- *                                                                         *
-- *   You should have received a copy of the GNU Library 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 .        *
-- ***************************************************************************/
--
--import QtQuick 1.1
--import org.kde.plasma.core 0.1 as PlasmaCore
--import org.kde.plasma.components 0.1 as PlasmaComponents
--import org.kde.qtextracomponents 0.1
--import org.kde.plasma.extras 0.1 as PlasmaExtras
--import org.kde.locale 0.1 as KLocale
--
--import "plasmapackage:/ui/uiproperties.js" as UiProperties
--
--
--MouseEventListener {
--    id: notificationsApplet
--    state: "default"
--    width: 32
--    height: 32
--    property int minimumWidth: mainScrollArea.implicitWidth
--    property int minimumHeight: mainScrollArea.implicitHeight
--    property int maximumWidth: -1
--    property int maximumHeight: mainScrollArea.implicitHeight
--
--    property int toolIconSize: UiProperties.toolIconSize
--    property int layoutSpacing: UiProperties.layoutSpacing
--
--    property real globalProgress: 0
--
--    property bool showNotifications: false
--    property bool showJobs: false
--
--    property Item notifications: notificationsLoader.item
--    property Item jobs: jobsLoader.item
--
--    //notifications + jobs
--    property int totalCount: (notifications ? notifications.count : 0) + (jobs ? jobs.count : 0)
--    onTotalCountChanged: {
--        if (totalCount > 0) {
--            state = "new-notifications"
--        } else {
--            state = "default"
--            plasmoid.hidePopup()
--        }
--
--        var data = new Object
--        data["image"] = "preferences-desktop-notification"
--        data["mainText"] = i18n("Notifications and Jobs")
--        if (totalCount == 0) {
--            data["subText"] = i18n("No notifications or jobs")
--        } else if (!notifications.count) {
--            data["subText"] = i18np("%1 running job", "%1 running jobs", jobs.count)
--        } else if (!jobs.count) {
--            data["subText"] = i18np("%1 notification", "%1 notifications", notifications.count)
--        } else  {
--            data["subText"] = i18np("%1 running job", "%1 running jobs", jobs.count) + "<br/>" + i18np("%1 notification", "%1 notifications", notifications.count)
--        }
--        plasmoid.popupIconToolTip = data
--        plasmoid.passivePopup = jobs.count != 0
--    }
--
--    property Item notificationIcon
--
--    Component.onCompleted: {
--        //plasmoid.popupIcon = QIcon("preferences-desktop-notification")
--        plasmoid.aspectRatioMode = "ConstrainedSquare"
--        plasmoid.status = PassiveStatus
--        allApplications = new Object
--        plasmoid.addEventListener('ConfigChanged', configChanged);
--        configChanged()
--    }
--
--    function configChanged()
--    {
--        showNotifications = plasmoid.readConfig("ShowNotifications")
--        showJobs = plasmoid.readConfig("ShowJobs")
--    }
--
--    KLocale.Locale {
--        id: locale
--    }
--
--    PlasmaCore.Svg {
--        id: configIconsSvg
--        imagePath: "widgets/configuration-icons"
--    }
--
--    property Component compactRepresentation: Component {
--        NotificationIcon {
--            id: notificationIcon
--            Component.onCompleted: notificationsApplet.notificationIcon = notificationIcon
--        }
--    }
--
--    hoverEnabled: !UiProperties.touchInput
--
--    PlasmaExtras.ScrollArea {
--        id: mainScrollArea
--        anchors.fill: parent
--        implicitWidth: theme.defaultFont.mSize.width * 40
--        implicitHeight: Math.min(theme.defaultFont.mSize.height * 40, Math.max(theme.defaultFont.mSize.height * 6, contentsColumn.height))
--        state: ""
--
--        states: [
--            State {
--                name: "underMouse"
--                when: notificationsApplet.containsMouse
--                PropertyChanges {
--                    target: mainScrollArea
--                    implicitHeight: implicitHeight
--                }
--            },
--            State {
--                name: ""
--                when: !notificationsApplet.containsMouse
--                PropertyChanges {
--                    target: mainScrollArea
--                    implicitHeight: Math.min(theme.defaultFont.mSize.height * 40, Math.max(theme.defaultFont.mSize.height * 6, contentsColumn.height))
--                }
--            }
--        ]
--
--        Flickable {
--            id: popupFlickable
--            anchors.fill:parent
--
--            contentWidth: width
--            contentHeight: contentsColumn.height
--            clip: true
--
--            Column {
--                id: contentsColumn
--                width: popupFlickable.width
--
--                //TODO: load those on demand based on configuration
--                Loader {
--                    id: jobsLoader
--                    source: showJobs ? "Jobs.qml" : ""
--                    anchors {
--                        left: parent.left
--                        right: parent.right
--                    }
--                }
--                Loader {
--                    id: notificationsLoader
--                    source: showNotifications ? "Notifications.qml" : ""
--                    anchors {
--                        left: parent.left
--                        right: parent.right
--                    }
--                }
--            }
--        }
--    }
--}
-diff --git a/plasma/generic/applets/notifications/contents/ui/uiproperties.js b/plasma/generic/applets/notifications/contents/ui/uiproperties.js
-deleted file mode 100644
-index efad371..0000000
---- a/plasma/generic/applets/notifications/contents/ui/uiproperties.js
-+++ /dev/null
-@@ -1,23 +0,0 @@
--/*
-- *   Copyright 2012 Marco Martin <notmart@gmail.com>
-- *
-- *   This program 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, 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 Library General Public License for more details
-- *
-- *   You should have received a copy of the GNU Library 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.
-- */
--
--
--var toolIconSize = theme.smallMediumIconSize
--var layoutSpacing = 4
--var touchInput = false
-diff --git a/plasma/generic/applets/notifications/core/completedjobnotification.cpp b/plasma/generic/applets/notifications/core/completedjobnotification.cpp
-new file mode 100644
-index 0000000..9a08390
---- /dev/null
-+++ b/plasma/generic/applets/notifications/core/completedjobnotification.cpp
-@@ -0,0 +1,99 @@
-+/***************************************************************************
-+ *   completedjobnotification.h                                                          *
-+ *   Copyright (C) 2010 Marco Martin <notmart@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 .        *
-+ ***************************************************************************/
-+
-+#include "completedjobnotification.h"
-+#include "job.h"
-+
-+#include <QProcess>
-+
-+#include <KIcon>
-+#include <KLocale>
-+#include <KDebug>
-+
-+
-+static const int completedJobExpireDelay = 60 * 1000;
-+static const int completedShortJobExpireDelay = 8 * 1000;
-+static const uint shortJobsLength = 30 * 1000;
-+
-+CompletedJobNotification::CompletedJobNotification(QObject *parent)
-+    : Notification(parent)
-+{
-+}
-+
-+CompletedJobNotification::~CompletedJobNotification()
-+{
-+}
-+
-+void CompletedJobNotification::setJob(Job *job)
-+{
-+    setApplicationName(job->applicationName());
-+    setApplicationIcon(KIcon(job->applicationIconName()));
-+    setSummary(i18n("%1 [Finished]", job->message()));
-+
-+    if (job->error().isEmpty()) {
-+        setMessage(job->completedMessage());
-+    } else {
-+        setMessage(job->error());
-+    }
-+
-+    if (job->elapsed() < shortJobsLength) {
-+        setTimeout(completedShortJobExpireDelay);
-+    } else {
-+        setTimeout(completedJobExpireDelay);
-+    }
-+
-+    if (job->destination().isValid()) {
-+        QHash<QString, QString> actions;
-+        actions.insert("open", i18n("Open"));
-+        setActions(actions);
-+        setActionOrder(QStringList()<<"open");
-+
-+        // create location url as is done in job->completedMessage()
-+        KUrl location(job->destination());
-+        if (job->totalAmounts().value("files") > 1) {
-+            location.setFileName(QString());
-+        }
-+
-+        m_destinationPrettyUrl = location.prettyUrl();
-+    }
-+
-+    m_job = job;
-+}
-+
-+void CompletedJobNotification::linkActivated(const QString &url)
-+{
-+    kDebug() << "open " << url;
-+    QProcess::startDetached("kde-open", QStringList() << url);
-+}
-+
-+Job *CompletedJobNotification::job() const
-+{
-+    return m_job;
-+}
-+
-+void CompletedJobNotification::triggerAction(const QString &actionId)
-+{
-+    if (actionId == "open" && !m_destinationPrettyUrl.isNull()) {
-+        linkActivated(m_destinationPrettyUrl);
-+    }
-+}
-+
-+
-+#include "completedjobnotification.moc"
-diff --git a/plasma/generic/applets/notifications/core/completedjobnotification.h b/plasma/generic/applets/notifications/core/completedjobnotification.h
-new file mode 100644
-index 0000000..b5e1f15
---- /dev/null
-+++ b/plasma/generic/applets/notifications/core/completedjobnotification.h
-@@ -0,0 +1,51 @@
-+/***************************************************************************
-+ *   completedjobnotification.h                                            *
-+ *   Copyright (C) 2010 Marco Martin <notmart@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 COMPLETEDJOBNOTIFICATION_H
-+#define COMPLETEDJOBNOTIFICATION_H
-+
-+#include "notification.h"
-+
-+
-+class Job;
-+
-+class CompletedJobNotification : public Notification
-+{
-+    Q_OBJECT
-+
-+public:
-+    CompletedJobNotification(QObject *parent = 0);
-+    virtual ~CompletedJobNotification();
-+
-+    void setJob(Job *job);
-+    Job *job() const;
-+
-+public Q_SLOTS:
-+    void linkActivated(const QString &link);
-+    void triggerAction(const QString &actionId);
-+
-+private:
-+    Job *m_job;
-+    QString m_destinationPrettyUrl;
-+};
-+
-+
-+#endif
-+
-diff --git a/plasma/generic/applets/notifications/core/job.cpp b/plasma/generic/applets/notifications/core/job.cpp
-new file mode 100644
-index 0000000..77ea03f
---- /dev/null
-+++ b/plasma/generic/applets/notifications/core/job.cpp
-@@ -0,0 +1,360 @@
-+/***************************************************************************
-+ *   Copyright (C) 2008 Rob Scheepmaker <r.scheepmaker@student.utwente.nl> *
-+ *                                                                         *
-+ *   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 "job.h"
-+
-+#include <QtCore/QTimer>
-+#include <QtCore/QTime>
-+#include <QTextDocument>
-+#include <QFontMetrics>
-+#include <QApplication>
-+
-+#include <KDebug>
-+#include <KUrl>
-+#include <KLocalizedString>
-+
-+
-+class Job::Private
-+{
-+public:
-+    Private() :
-+        numericSpeed(0),
-+        finalElapsed(0),
-+        state(Running),
-+        percentage(0),
-+        eta(0),
-+        timerId(0),
-+        killable(false),
-+        suspendable(false),
-+        shown(false)
-+    {
-+    }
-+
-+    QString applicationName;
-+    QString applicationIconName;
-+    QString message;
-+    QString error;
-+    QString speed;
-+    QString destination;
-+    qlonglong numericSpeed;
-+
-+
-+    QMap<QString, qlonglong> totalAmounts;
-+    QMap<QString, qlonglong> processedAmounts;
-+
-+    QList<QPair<QString, QString> > labels;
-+
-+    QTime elapsed;
-+    uint finalElapsed;
-+
-+    State state;
-+    uint percentage;
-+    uint eta;
-+    int timerId;
-+
-+    bool killable : 1;
-+    bool suspendable : 1;
-+    bool shown : 1;
-+};
-+
-+Job::Job(QObject *parent)
-+    : QObject(parent),
-+      d(new Private)
-+{
-+    //delay a little the job to avoid the user to be distracted with short ones
-+    QTimer::singleShot(1500, this, SLOT(show()));
-+    d->elapsed.restart();
-+}
-+
-+Job::~Job()
-+{
-+    delete d;
-+}
-+
-+void Job::destroy()
-+{
-+    emit destroyed(this);
-+    deleteLater();
-+}
-+
-+QString Job::applicationName() const
-+{
-+    return d->applicationName;
-+}
-+
-+void Job::setApplicationName(const QString &applicationName)
-+{
-+    if (d->applicationName != applicationName) {
-+        d->applicationName = applicationName;
-+        scheduleChangedSignal();
-+    }
-+}
-+
-+QString Job::applicationIconName() const
-+{
-+    return d->applicationIconName;
-+}
-+
-+void Job::setApplicationIconName(const QString &applicationIcon)
-+{
-+    if (d->applicationIconName != applicationIcon) {
-+        d->applicationIconName = applicationIcon;
-+        scheduleChangedSignal();
-+    }
-+}
-+
-+QString Job::message() const
-+{
-+    return d->message;
-+}
-+
-+void Job::setMessage(const QString &message)
-+{
-+    if (d->message != message) {
-+        d->message = message;
-+        scheduleChangedSignal();
-+    }
-+}
-+
-+QString Job::error() const
-+{
-+    return d->error;
-+}
-+
-+void Job::setError(const QString &error)
-+{
-+    if (d->error != error) {
-+        d->error = error;
-+        scheduleChangedSignal();
-+    }
-+}
-+
-+QString Job::speed() const
-+{
-+    return d->speed;
-+}
-+
-+void Job::setSpeed(const QString &speed)
-+{
-+    if (d->speed != speed) {
-+        d->speed = speed;
-+        scheduleChangedSignal();
-+    }
-+}
-+
-+qlonglong Job::numericSpeed() const
-+{
-+    return d->numericSpeed;
-+}
-+
-+void Job::setNumericSpeed(const qlonglong speed)
-+{
-+    if (d->numericSpeed != speed) {
-+        d->numericSpeed = speed;
-+        scheduleChangedSignal();
-+    }
-+}
-+
-+QString Job::completedMessage() const
-+{
-+    KUrl location(d->destination);
-+    if (location.isValid()) {
-+        if (totalAmounts().value("files") > 1) {
-+            location.setFileName(QString());
-+        }
-+
-+        QString destinationString;
-+        if (location.isLocalFile()) {
-+            destinationString = location.toLocalFile();
-+        } else {
-+            destinationString = location.prettyUrl();
-+        }
-+
-+        //FIXME: this is visualization stuff, but putting html here is not so model as well
-+
-+        kDebug() << "href = " << location.url();
-+        QString destinationLink = QString("<a href=\"%1\">%2</a>").arg(location.url())
-+                                  .arg(Qt::escape(destinationString));
-+
-+        if (totalAmounts().value("files") > 1) {
-+            return i18np("%1 file, to: %2", "%1 files, to: %2", totalAmounts().value("files"),
-+                         destinationLink);
-+        } else {
-+            return destinationLink;
-+        }
-+    } else {
-+        return QString("%1: %2").arg(labels().value(0).first).arg(labels().value(0).second);
-+    }
-+}
-+
-+KUrl Job::destination() const
-+{
-+    return d->destination;
-+}
-+
-+ulong Job::eta() const
-+{
-+    return d->eta;
-+}
-+
-+void Job::setEta(ulong eta)
-+{
-+    d->eta = eta;
-+}
-+
-+QMap<QString, qlonglong> Job::totalAmounts() const
-+{
-+    return d->totalAmounts;
-+}
-+
-+void Job::setTotalAmounts(QMap<QString, qlonglong> amounts)
-+{
-+    d->totalAmounts = amounts;
-+    scheduleChangedSignal();
-+}
-+
-+QMap<QString, qlonglong> Job::processedAmounts() const
-+{
-+    return d->processedAmounts;
-+}
-+
-+void Job::setProcessedAmounts(QMap<QString, qlonglong> amounts)
-+{
-+    d->processedAmounts = amounts;
-+    scheduleChangedSignal();
-+}
-+
-+Job::State Job::state() const
-+{
-+    return d->state;
-+}
-+
-+void Job::setState(State state)
-+{
-+    if (d->state != state) {
-+        d->state = state;
-+        show();
-+        if (state == Stopped) {
-+            d->finalElapsed = d->elapsed.elapsed();
-+        }
-+        emit stateChanged(this);
-+    }
-+}
-+
-+QList<QPair<QString, QString> > Job::labels() const
-+{
-+    return d->labels;
-+}
-+
-+void Job::setLabels(QList<QPair<QString, QString> > labels)
-+{
-+    d->labels = labels;
-+    if (d->labels.count() > 1 && d->destination.isEmpty()) {
-+        d->destination = d->labels.value(1).second;
-+    }
-+    scheduleChangedSignal();
-+}
-+
-+uint Job::percentage() const
-+{
-+    return d->percentage;
-+}
-+
-+void Job::setPercentage(uint percentage)
-+{
-+    if (d->percentage != percentage) {
-+        d->percentage = percentage;
-+        scheduleChangedSignal();
-+    }
-+}
-+
-+uint Job::elapsed() const
-+{
-+    if (d->finalElapsed) {
-+        return d->finalElapsed;
-+    } else {
-+        return d->elapsed.elapsed();
-+    }
-+}
-+
-+bool Job::isSuspendable() const
-+{
-+    return d->suspendable;
-+}
-+
-+void Job::setSuspendable(bool suspendable)
-+{
-+    if (d->suspendable != suspendable) {
-+        d->suspendable = suspendable;
-+        scheduleChangedSignal();
-+    }
-+}
-+
-+bool Job::isKillable() const
-+{
-+    return d->killable;
-+}
-+
-+void Job::setKillable(bool killable)
-+{
-+    if (d->killable != killable) {
-+        d->killable = killable;
-+        scheduleChangedSignal();
-+    }
-+}
-+
-+void Job::suspend()
-+{
-+    kWarning() << "Suspend is not implemented in this job provider.";
-+}
-+
-+void Job::resume()
-+{
-+    kWarning() << "Resume is not implemented in this job provider.";
-+}
-+
-+void Job::stop()
-+{
-+    kWarning() << "Stop is not implemented in this job provider.";
-+}
-+
-+void Job::show()
-+{
-+    if (state() == Job::Running && !d->shown) {
-+        d->shown = true;
-+        emit ready(this);
-+    }
-+}
-+
-+void Job::scheduleChangedSignal()
-+{
-+    if (d->shown && !d->timerId) {
-+        d->timerId = startTimer(0);
-+    }
-+}
-+
-+void Job::timerEvent(QTimerEvent *)
-+{
-+    killTimer(d->timerId);
-+    d->timerId = 0;
-+    emit changed(this);
-+}
-+
-+
-+#include "job.moc"
-diff --git a/plasma/generic/applets/notifications/core/job.h b/plasma/generic/applets/notifications/core/job.h
-new file mode 100644
-index 0000000..3d2984d
---- /dev/null
-+++ b/plasma/generic/applets/notifications/core/job.h
-@@ -0,0 +1,188 @@
-+/***************************************************************************
-+ *   Copyright (C) 2008 Rob Scheepmaker <r.scheepmaker@student.utwente.nl> *
-+ *                                                                         *
-+ *   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 JOB_H
-+#define JOB_H
-+
-+#include <QtCore/QHash>
-+#include <QtCore/QObject>
-+
-+#include <KUrl>
-+
-+
-+class Job : public QObject
-+{
-+    Q_OBJECT
-+
-+public:
-+    enum State {
-+        Running = 0,
-+        Suspended = 1,
-+        Stopped = 2
-+    };
-+
-+    Job(QObject *parent = 0);
-+    virtual ~Job();
-+
-+    /**
-+     * Request and signal destruction of this object
-+     */
-+    void destroy();
-+
-+    /**
-+     * @return the name of the application which started this job.
-+     */
-+    QString applicationName() const;
-+
-+    /**
-+     * @return the name of the icon to be used for this job.
-+     */
-+    QString applicationIconName() const;
-+
-+    /**
-+     * @return the descripion of the activity that is performed.
-+     */
-+    QString message() const;
-+
-+    /**
-+     * @return the errormessage if an error has occurred.
-+     */
-+    QString error() const;
-+
-+    /**
-+     * @return the (human readable) speed at which the jobs is progressing.
-+     */
-+    QString speed() const;
-+
-+    /**
-+     * @return the (in bytes per second) speed at which the jobs is progressing.
-+     */
-+    qlonglong numericSpeed() const;
-+
-+    /**
-+     * @return a nice description of the job that has been completed.
-+     */
-+    QString completedMessage() const;
-+
-+    /**
-+     * @return the time (in seconds) in which this job is expected to complete.
-+     */
-+    ulong eta() const;
-+
-+    void setEta(ulong eta);
-+
-+    QMap<QString, qlonglong> totalAmounts() const;
-+
-+    QMap<QString, qlonglong> processedAmounts() const;
-+
-+    /**
-+     * @return a list of pairs containing label names/values in the order they should be displayed.
-+     */
-+    QList<QPair<QString, QString> > labels() const;
-+
-+    /**
-+     * @return the state this job is in.
-+     */
-+    State state() const;
-+
-+    bool isSuspendable() const;
-+
-+    bool isKillable() const;
-+
-+    /**
-+     * @retun the percentage of the job that has been completed.
-+     */
-+    uint percentage() const;
-+
-+    /**
-+     * total elapsed job time
-+     */
-+    uint elapsed() const;
-+
-+    /**
-+     * Destination url
-+     */
-+    KUrl destination() const;
-+
-+public slots:
-+    /**
-+     * suspend this job.
-+     */
-+    virtual void suspend();
-+
-+    /**
-+     * resume this job.
-+     */
-+    virtual void resume();
-+
-+    /**
-+     * stop this job.
-+     */
-+    virtual void stop();
-+
-+signals:
-+    /**
-+     * Emitted when the job is ready to be shown
-+     */
-+    void ready(Job *job);
-+
-+    /**
-+     * Emitted when the job changes state
-+     */
-+    void stateChanged(Job *job);
-+
-+    /**
-+     * Emitted when the job details change
-+     */
-+    void changed(Job *job);
-+
-+    /**
-+     * Emitted when the job is about to be destroyed
-+     **/
-+    void destroyed(Job *job);
-+
-+protected:
-+    void setApplicationName(const QString &applicationName);
-+    void setApplicationIconName(const QString &applicationIcon);
-+    void setMessage(const QString &message);
-+    void setError(const QString &error);
-+    void setSpeed(const QString &speed);
-+    void setNumericSpeed(const qlonglong speed);
-+    void setTotalAmounts(QMap<QString, qlonglong> amount);
-+    void setProcessedAmounts(QMap<QString, qlonglong> amount);
-+    void setState(State state);
-+    void setSuspendable(bool suspendable);
-+    void setKillable(bool killable);
-+    void setPercentage(uint percentage);
-+    void setLabels(QList<QPair<QString, QString> > labels);
-+    void timerEvent(QTimerEvent *);
-+
-+private slots:
-+    void show();
-+
-+private:
-+    void scheduleChangedSignal();
-+
-+    class Private;
-+    Private* const d;
-+
-+    friend class Manager;
-+};
-+
-+#endif
-diff --git a/plasma/generic/applets/notifications/core/notification.cpp b/plasma/generic/applets/notifications/core/notification.cpp
-new file mode 100644
-index 0000000..26833b6
---- /dev/null
-+++ b/plasma/generic/applets/notifications/core/notification.cpp
-@@ -0,0 +1,272 @@
-+/***************************************************************************
-+ *   notification.cpp                                                      *
-+ *                                                                         *
-+ *   Copyright (C) 2008 Jason Stubbs <jasonbstubbs@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 .        *
-+ ***************************************************************************/
-+
-+#include "notification.h"
-+
-+#include <QImage>
-+#include <QtCore/QTimer>
-+
-+#include <KDebug>
-+
-+
-+class Notification::Private
-+{
-+public:
-+    Private()
-+        : timeout(0),
-+          urgency(0),
-+          hideTimer(0),
-+          expired(false),
-+          read(false)
-+    {
-+    }
-+
-+    QString identifier;
-+    QString applicationName;
-+    QIcon applicationIcon;
-+    QString message;
-+    QString summary;
-+    int timeout;
-+    int urgency;
-+    QImage image;
-+    QTimer *deleteTimer;
-+    QTimer *hideTimer;
-+    bool expired;
-+    bool read;
-+
-+    QHash<QString, QString> actions;
-+    QStringList actionOrder;
-+};
-+
-+Notification::Notification(QObject *parent)
-+    : QObject(parent),
-+      d(new Private)
-+{
-+    d->deleteTimer = new QTimer(this);
-+    d->deleteTimer->setSingleShot(true);
-+    connect(d->deleteTimer, SIGNAL(timeout()), this, SLOT(destroy()));
-+}
-+
-+
-+Notification::~Notification()
-+{
-+    emit notificationDestroyed(this);
-+    delete d;
-+}
-+
-+void Notification::destroy()
-+{
-+    emit notificationDestroyed(this);
-+    deleteLater();
-+}
-+
-+QString Notification::applicationName() const
-+{
-+    return d->applicationName;
-+}
-+
-+
-+void Notification::setApplicationName(const QString &applicationName)
-+{
-+    d->applicationName = applicationName;
-+}
-+
-+
-+QIcon Notification::applicationIcon() const
-+{
-+    return d->applicationIcon;
-+}
-+
-+
-+void Notification::setApplicationIcon(const QIcon &applicationIcon)
-+{
-+    d->applicationIcon = applicationIcon;
-+}
-+
-+
-+QString Notification::message() const
-+{
-+    return d->message;
-+}
-+
-+
-+void Notification::setMessage(const QString &message)
-+{
-+    d->message = message;
-+}
-+
-+
-+QString Notification::summary() const
-+{
-+    return d->summary;
-+}
-+
-+
-+void Notification::setSummary(const QString &summary)
-+{
-+    d->summary = summary;
-+}
-+
-+
-+int Notification::timeout() const
-+{
-+    return d->timeout;
-+}
-+
-+QImage Notification::image() const
-+{
-+    return d->image;
-+}
-+
-+void Notification::setImage(QImage image)
-+{
-+    d->image = image;
-+}
-+
-+void Notification::setTimeout(int timeout)
-+{
-+    //show them at most 30 seconds
-+    if (!timeout) {
-+        d->timeout = 30 * 1000;
-+    } else {
-+        d->timeout = timeout;
-+    }
-+
-+    if (d->urgency >= 2) {
-+        return;
-+    }
-+
-+    if (!d->hideTimer) {
-+        d->hideTimer = new QTimer(this);
-+        d->hideTimer->setSingleShot(true);
-+        connect(d->hideTimer, SIGNAL(timeout()), this, SLOT(hide()));
-+    }
-+    d->hideTimer->start(d->timeout);
-+}
-+
-+void Notification::setUrgency(int urgency)
-+{
-+    if (urgency != d->urgency) {
-+        d->urgency = urgency;
-+        if (urgency >= 2) {
-+            if (d->hideTimer) {
-+                d->hideTimer->stop();
-+            }
-+            d->deleteTimer->stop();
-+        } else {
-+            setTimeout(d->timeout);
-+        }
-+    }
-+}
-+
-+int Notification::urgency() const
-+{
-+    return d->urgency;
-+}
-+
-+QHash<QString, QString> Notification::actions() const
-+{
-+    return d->actions;
-+}
-+
-+
-+void Notification::setActions(const QHash<QString, QString> &actions)
-+{
-+    d->actions = actions;
-+    emit changed(this);
-+}
-+
-+
-+QStringList Notification::actionOrder() const
-+{
-+    return d->actionOrder;
-+}
-+
-+
-+void Notification::setActionOrder(const QStringList &actionOrder)
-+{
-+    d->actionOrder = actionOrder;
-+}
-+
-+
-+void Notification::triggerAction(const QString &actionId)
-+{
-+    Q_UNUSED(actionId);
-+    kDebug() << "action triggered but no handler implemented";
-+}
-+
-+void Notification::remove()
-+{
-+    kDebug() << "remove requested but no handler implemented";
-+}
-+
-+void Notification::linkActivated(const QString &link)
-+{
-+    Q_UNUSED(link)
-+    kDebug() << "link activation requested but no handler implemented";
-+}
-+
-+void Notification::hide()
-+{
-+    d->expired = true;
-+    emit expired(this);
-+}
-+
-+void Notification::startDeletionCountdown()
-+{
-+    if (d->urgency >= 2) {
-+        return;
-+    }
-+
-+    //keep it available for 10 minutes
-+    d->deleteTimer->start(10*60*1000);
-+}
-+
-+bool Notification::isExpired() const
-+{
-+    return d->expired;
-+}
-+
-+void Notification::setRead(const bool read)
-+{
-+    d->read = read;
-+}
-+
-+bool Notification::isRead() const
-+{
-+    return d->read;
-+}
-+
-+void Notification::setDeleteTimeout(const int time)
-+{
-+    if (d->deleteTimer->interval() != time) {
-+        d->deleteTimer->start(time);
-+    }
-+}
-+
-+int Notification::deleteTimeOut() const
-+{
-+    return d->deleteTimer->interval();
-+}
-+
-+
-+
-+#include "notification.moc"
-diff --git a/plasma/generic/applets/notifications/core/notification.h b/plasma/generic/applets/notifications/core/notification.h
-new file mode 100644
-index 0000000..e04fdba
---- /dev/null
-+++ b/plasma/generic/applets/notifications/core/notification.h
-@@ -0,0 +1,100 @@
-+/***************************************************************************
-+ *   notification.h                                                        *
-+ *                                                                         *
-+ *   Copyright (C) 2008 Jason Stubbs <jasonbstubbs@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 NOTIFICATION_H
-+#define NOTIFICATION_H
-+
-+#include <QImage>
-+#include <QtCore/QHash>
-+#include <QtCore/QObject>
-+
-+#include <QtGui/QIcon>
-+
-+
-+
-+class Notification : public QObject
-+{
-+    Q_OBJECT
-+
-+public:
-+    Notification(QObject *parent = 0);
-+    virtual ~Notification();
-+
-+    QString applicationName() const;
-+    QIcon applicationIcon() const;
-+    QString message() const;
-+    QString summary() const;
-+    int timeout() const;
-+    QImage image() const;
-+
-+    void setUrgency(int urgency);
-+    int urgency() const;
-+
-+    QHash<QString, QString> actions() const;
-+    QStringList actionOrder() const;
-+
-+    bool isExpired() const;
-+
-+    void setRead(const bool read);
-+    bool isRead() const;
-+
-+    void setDeleteTimeout(const int time);
-+    int deleteTimeOut() const;
-+
-+public slots:
-+    virtual void triggerAction(const QString &actionId);
-+    virtual void remove();
-+    virtual void linkActivated(const QString &link);
-+    void startDeletionCountdown();
-+    void hide();
-+    void destroy();
-+
-+signals:
-+    void changed(Notification *notification = 0);
-+
-+    /**
-+     * Emitted when the notification is about to be destroyed
-+     **/
-+    void notificationDestroyed(Notification *notification = 0);
-+
-+    /**
-+     * emitted when the notification wants to hide itself
-+     */
-+    void expired(Notification *notification = 0);
-+
-+protected:
-+    void setApplicationName(const QString &applicationName);
-+    void setApplicationIcon(const QIcon &applicationIcon);
-+    void setMessage(const QString &message);
-+    void setSummary(const QString &summary);
-+    void setImage(QImage image);
-+    void setTimeout(int timeout);
-+    void setActions(const QHash<QString, QString> &actions);
-+    void setActionOrder(const QStringList &actionOrder);
-+
-+private:
-+    class Private;
-+    Private* const d;
-+};
-+
-+
-+
-+#endif
-diff --git a/plasma/generic/applets/notifications/core/notificationsmanager.cpp b/plasma/generic/applets/notifications/core/notificationsmanager.cpp
-new file mode 100644
-index 0000000..6892361
---- /dev/null
-+++ b/plasma/generic/applets/notifications/core/notificationsmanager.cpp
-@@ -0,0 +1,245 @@
-+/***************************************************************************
-+ *   manager.cpp                                                           *
-+ *                                                                         *
-+ *   Copyright (C) 2008 Jason Stubbs <jasonbstubbs@gmail.com>              *
-+ *   Copyright (C) 2010 Marco Martin <notmart@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 .        *
-+ ***************************************************************************/
-+
-+#include "notificationsmanager.h"
-+
-+#include <QTimer>
-+
-+#include <KGlobal>
-+
-+#include <plasma/applet.h>
-+
-+#include "job.h"
-+#include "notification.h"
-+#include "protocol.h"
-+
-+#include "../protocols/notifications/dbusnotificationprotocol.h"
-+#include "../protocols/jobs/dbusjobprotocol.h"
-+
-+
-+static const int idleCheckInterval = 60 * 1000;
-+
-+class Manager::Private
-+{
-+public:
-+    Private(Manager *manager)
-+        : q(manager),
-+          jobTotals(new Job(manager)),
-+          jobProtocol(0),
-+          notificationProtocol(0)
-+    {
-+    }
-+
-+    void setupProtocol(Protocol *protocol);
-+    void checkIdle();
-+
-+    Manager *q;
-+    QList<Task *> tasks;
-+    QList<Notification*> notifications;
-+    QList<Job *> jobs;
-+    Job *jobTotals;
-+    Notifications *notificationsApplet;
-+    Protocol *jobProtocol;
-+    Protocol *notificationProtocol;
-+    QTimer *idleTimer;
-+    static const int s_notificationLimit = 15;
-+};
-+
-+
-+Manager::Manager(Notifications *parentApplet)
-+    : QObject(parentApplet),
-+      d(new Private(this))
-+{
-+    d->notificationsApplet = parentApplet;
-+    d->idleTimer = new QTimer(this);
-+    d->idleTimer->setSingleShot(false);
-+    connect(d->idleTimer, SIGNAL(timeout()), this, SLOT(checkIdle()));
-+}
-+
-+Manager::~Manager()
-+{
-+    delete d;
-+}
-+
-+void Manager::registerNotificationProtocol()
-+{
-+    if (!d->notificationProtocol) {
-+        d->notificationProtocol = new DBusNotificationProtocol(this);
-+        d->setupProtocol(d->notificationProtocol);
-+    }
-+}
-+
-+void Manager::unregisterNotificationProtocol()
-+{
-+    delete d->notificationProtocol;
-+    d->notificationProtocol = 0;
-+}
-+
-+void Manager::addNotification(Notification* notification)
-+{
-+    connect(notification, SIGNAL(notificationDestroyed(Notification*)),
-+            this, SLOT(removeNotification(Notification*)));
-+    connect(notification, SIGNAL(changed(Notification*)),
-+            this, SIGNAL(notificationChanged(Notification*)));
-+    connect(notification, SIGNAL(expired(Notification*)),
-+            this, SIGNAL(notificationExpired(Notification*)));
-+
-+    d->notifications.append(notification);
-+
-+    if (!d->idleTimer->isActive()) {
-+        d->idleTimer->start(idleCheckInterval);
-+    }
-+    connect(this, SIGNAL(idleTerminated()), notification, SLOT(startDeletionCountdown()));
-+
-+    emit notificationAdded(notification);
-+
-+    if (d->notifications.count() > d->s_notificationLimit) {
-+        Notification *notification = d->notifications.first();
-+        d->notifications.pop_front();
-+        notification->deleteLater();
-+    }
-+}
-+
-+void Manager::removeNotification(Notification *notification)
-+{
-+    d->notifications.removeAll(notification);
-+    disconnect(notification, 0, this, 0);
-+    disconnect(this, 0, notification, 0);
-+
-+    if (d->notifications.isEmpty()) {
-+        d->idleTimer->stop();
-+    }
-+
-+    emit notificationRemoved(notification);
-+}
-+
-+QList<Notification*> Manager::notifications() const
-+{
-+    return d->notifications;
-+}
-+
-+void Manager::clearNotifications()
-+{
-+    qDeleteAll(d->notifications);
-+    d->notifications.clear();
-+}
-+
-+void Manager::registerJobProtocol()
-+{
-+    if (!d->jobProtocol) {
-+        d->jobProtocol = new DBusJobProtocol(this);
-+        d->setupProtocol(d->jobProtocol);
-+    }
-+}
-+
-+void Manager::unregisterJobProtocol()
-+{
-+    delete d->jobProtocol;
-+    d->jobProtocol = 0;
-+}
-+
-+void Manager::addJob(Job *job)
-+{
-+    connect(job, SIGNAL(destroyed(Job*)), this, SLOT(removeJob(Job*)));
-+    connect(job, SIGNAL(changed(Job*)), this, SIGNAL(jobChanged(Job*)));
-+    connect(job, SIGNAL(stateChanged(Job*)), this, SIGNAL(jobStateChanged(Job*)));
-+    connect(job, SIGNAL(changed(Job*)), this, SLOT(updateTotals()));
-+
-+    d->jobs.append(job);
-+    emit jobAdded(job);
-+}
-+
-+void Manager::removeJob(Job *job)
-+{
-+    d->jobs.removeAll(job);
-+    disconnect(job);
-+    updateTotals();
-+    emit jobRemoved(job);
-+}
-+
-+void Manager::updateTotals()
-+{
-+    uint totalPercent = 0;
-+    ulong totalEta = 0;
-+    foreach (Job *job, d->jobs) {
-+        totalPercent += job->percentage();
-+        if (job->eta() > totalEta) {
-+            totalEta = job->eta();
-+        }
-+    }
-+
-+    if (d->jobs.count() > 0) {
-+        d->jobTotals->setPercentage(totalPercent / d->jobs.count());
-+        d->jobTotals->setMessage(i18np("1 running job (%2 remaining)", "%1 running jobs (%2 remaining)",
-+                                 d->jobs.count(),
-+                                 KGlobal::locale()->prettyFormatDuration(totalEta)));
-+    } else {
-+        d->jobTotals->setPercentage(0);
-+        d->jobTotals->setMessage(i18n("no running jobs"));
-+    }
-+    //TODO: set a sensible icon
-+}
-+
-+Job *Manager::jobTotals() const
-+{
-+    return d->jobTotals;
-+}
-+
-+QList<Job*> Manager::jobs() const
-+{
-+    return d->jobs;
-+}
-+
-+void Manager::checkIdle()
-+{
-+    int totalIdle;
-+#ifdef HAVE_LIBXSS      // Idle detection.
-+    XScreenSaverInfo*  _mit_info;
-+    _mit_info = XScreenSaverAllocInfo();
-+    XScreenSaverQueryInfo( QX11Info::display(), QX11Info::appRootWindow(), _mit_info );
-+    totalIdle =  _mit_info->idle;
-+    XFree( _mit_info );
-+#else
-+    totalIdle = 0;
-+#endif // HAVE_LIBXSS
-+
-+    if (totalIdle < idleCheckInterval) {
-+        d->idleTimer->stop();
-+        emit idleTerminated();
-+    }
-+}
-+
-+void Manager::Private::setupProtocol(Protocol *protocol)
-+{
-+    connect(protocol, SIGNAL(jobCreated(Job*)), q, SLOT(addJob(Job*)));
-+    connect(protocol, SIGNAL(notificationCreated(Notification*)),
-+            q, SLOT(addNotification(Notification*)));
-+    protocol->init();
-+}
-+
-+Notifications *Manager::applet() const
-+{
-+    return d->notificationsApplet;
-+}
-+
-+
-+#include "notificationsmanager.moc"
-diff --git a/plasma/generic/applets/notifications/core/notificationsmanager.h b/plasma/generic/applets/notifications/core/notificationsmanager.h
-new file mode 100644
-index 0000000..a6d6639
---- /dev/null
-+++ b/plasma/generic/applets/notifications/core/notificationsmanager.h
-@@ -0,0 +1,161 @@
-+/***************************************************************************
-+ *   manager.h                                                             *
-+ *                                                                         *
-+ *   Copyright (C) 2008 Jason Stubbs <jasonbstubbs@gmail.com>              *
-+ *   Copyright (C) 2010 Marco Martin <notmart@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 NOTIFICATIONSMANAGER_H
-+#define NOTIFICATIONSMANAGER_H
-+
-+#include <QtCore/QObject>
-+
-+#include <KConfigGroup>
-+
-+#include <plasma/plasma.h>
-+#include "../ui/notifications.h"
-+
-+
-+namespace Plasma
-+{
-+class Applet;
-+}
-+
-+class Notifications;
-+class Notification;
-+class Task;
-+class Job;
-+
-+/**
-+ * w
-+ * @short Creator and amalgamator of the supported system tray specifications
-+ **/
-+class Manager : public QObject
-+{
-+    Q_OBJECT
-+
-+public:
-+    Manager(Notifications *parentApplet);
-+    ~Manager();
-+
-+    /**
-+     * @return a list of all known Notification instances
-+     **/
-+    QList<Notification*> notifications() const;
-+
-+    /**
-+     * clear all notifications
-+     */
-+    void clearNotifications();
-+
-+    /**
-+     * @return a list of all known Job instances
-+     **/
-+    QList<Job*> jobs() const;
-+
-+    /**
-+     * @return a Job instance that can be used to monitor total progress
-+     **/
-+    Job *jobTotals() const;
-+
-+    /**
-+     * Integrates the Job progress info into the applet's notification system
-+     **/
-+    void registerJobProtocol();
-+
-+    /**
-+     * Iintegrates the notifications into the applet's notification system
-+     **/
-+    void registerNotificationProtocol();
-+
-+      /**
-+     * Removes the Job progress info from the applet's notification system
-+     **/
-+    void unregisterJobProtocol();
-+
-+    /**
-+     * Removes the notifications from the applet's notification system
-+     **/
-+    void unregisterNotificationProtocol();
-+
-+    Notifications *applet() const;
-+
-+signals:
-+    /**
-+     * Emitted when a new notification has been added
-+     **/
-+    void notificationAdded(Notification *notification);
-+
-+    /**
-+     * Emitted when something about a notification changes
-+     **/
-+    void notificationChanged(Notification *notification);
-+
-+    /**
-+     * The notification is expired and wants to hide itself
-+     */
-+    void notificationExpired(Notification *notification);
-+
-+    /**
-+     * Emitted when a notification has been removed
-+     **/
-+    void notificationRemoved(Notification *notification);
-+
-+    /**
-+     * Emitted when a new job has been added
-+     **/
-+    void jobAdded(Job *job);
-+
-+    /**
-+     * Emitted when the state of a job changes
-+     **/
-+    void jobStateChanged(Job *job);
-+
-+    /**
-+     * Emitted when something about a job changes
-+     **/
-+    void jobChanged(Job *job);
-+
-+    /**
-+     * Emitted when a job has been removed
-+     **/
-+    void jobRemoved(Job *job);
-+
-+    /**
-+     * the pc is out of idle and is starting being used
-+     */
-+    void idleTerminated();
-+
-+private slots:
-+    void addNotification(Notification *notification);
-+    void removeNotification(Notification *notification);
-+    void addJob(Job *job);
-+    void removeJob(Job *job);
-+    void updateTotals();
-+    void checkIdle();
-+
-+private:
-+    class Private;
-+    Private* const d;
-+
-+    friend class Notifications;
-+};
-+
-+
-+
-+#endif
-diff --git a/plasma/generic/applets/notifications/core/protocol.cpp b/plasma/generic/applets/notifications/core/protocol.cpp
-new file mode 100644
-index 0000000..a3716a2
---- /dev/null
-+++ b/plasma/generic/applets/notifications/core/protocol.cpp
-@@ -0,0 +1,31 @@
-+/***************************************************************************
-+ *   taskprotocol.cpp                                                      *
-+ *                                                                         *
-+ *   Copyright (C) 2008 Jason Stubbs <jasonbstubbs@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 .        *
-+ ***************************************************************************/
-+
-+#include "protocol.h"
-+
-+
-+Protocol::Protocol(QObject *parent)
-+    : QObject(parent)
-+{
-+}
-+
-+
-+#include "protocol.moc"
-diff --git a/plasma/generic/applets/notifications/core/protocol.h b/plasma/generic/applets/notifications/core/protocol.h
-new file mode 100644
-index 0000000..ea47292
---- /dev/null
-+++ b/plasma/generic/applets/notifications/core/protocol.h
-@@ -0,0 +1,68 @@
-+/***************************************************************************
-+ *   taskprotocol.h                                                        *
-+ *                                                                         *
-+ *   Copyright (C) 2008 Jason Stubbs <jasonbstubbs@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 PROTOCOL_H
-+#define PROTOCOL_H
-+
-+#include <QtCore/QObject>
-+
-+
-+class Job;
-+class Notification;
-+class Task;
-+
-+
-+/**
-+ * @short System tray protocol base class
-+ *
-+ * To support a new system tray protocol, this class and Task should be
-+ * subclassed and the subclass of this class registered with the global
-+ * Manager. The Protocol subclass should emit taskCreated() for each new
-+ * task created.
-+ **/
-+class Protocol : public QObject
-+{
-+    Q_OBJECT
-+public:
-+    explicit Protocol(QObject *parent);
-+
-+    virtual void init() = 0;
-+
-+signals:
-+    /**
-+     * Signals that a new task has been created
-+     **/
-+    void taskCreated(Task *task);
-+
-+    /**
-+     * Signals that a new notification has been created
-+     **/
-+    void jobCreated(Job *job);
-+
-+    /**
-+     * Signals that a new notification has been created
-+     **/
-+    void notificationCreated(Notification *notification);
-+};
-+
-+
-+
-+#endif
-diff --git a/plasma/generic/applets/notifications/metadata.desktop b/plasma/generic/applets/notifications/metadata.desktop
-deleted file mode 100644
-index 3a2be65..0000000
---- a/plasma/generic/applets/notifications/metadata.desktop
-+++ /dev/null
-@@ -1,166 +0,0 @@
--[Desktop Entry]
--Encoding=UTF-8
--Name=Notifications
--Name[ar]=تنبيهات
--Name[ast]=Notificaciones
--Name[be]=Абвяшчэнні
--Name[be@latin]=Infarmavańnie
--Name[bg]=Уведомяване
--Name[bn]=বিজ্ঞপ্তি
--Name[bn_IN]=সূচনাবার্তা
--Name[br]=Kemenn
--Name[bs]=obavještenja
--Name[ca]=Notificacions
--Name[ca@valencia]=Notificacions
--Name[cs]=Oznamování
--Name[csb]=Dôwanié wiédzë
--Name[da]=Bekendtgørelser
--Name[de]=Benachrichtigungen
--Name[el]=Ειδοποιήσεις
--Name[en_GB]=Notifications
--Name[eo]=Atentigoj
--Name[es]=Notificaciones
--Name[et]=Märguanded
--Name[eu]=Jakinarazpenak
--Name[fa]=اخطارها
--Name[fi]=Ilmoitukset
--Name[fr]=Notifications
--Name[fy]=Notifikaasjes
--Name[ga]=Fógairt
--Name[gl]=Notificacións
--Name[gu]=નોંધણીઓ
--Name[he]=הודעות
--Name[hi]=सूचनाएँ
--Name[hne]=सूचना मन ल
--Name[hr]=Obavijesti
--Name[hu]=Rendszerüzenetek
--Name[ia]=Notificationes
--Name[id]=Notifikasi
--Name[is]=Kerfistilkynningar
--Name[it]=Notifiche
--Name[ja]=通知
--Name[kk]=Құлақтандыру
--Name[km]=សេចក្តី​ជូន​ដំណឹង​
--Name[kn]=ಸೂಚನೆಗಳು
--Name[ko]=알림
--Name[ku]=Agahdarî
--Name[lt]=Pranešimai
--Name[lv]=Paziņojumi
--Name[mai]=सूचनासभ
--Name[mk]=Известувања
--Name[ml]=അറിയിപ്പുകള്‍
--Name[mr]=सूचना
--Name[ms]=Pemberitahuan
--Name[nb]=Varslinger
--Name[nds]=Bescheden
--Name[ne]=सूचना
--Name[nl]=Meldingen
--Name[nn]=Varslingar
--Name[oc]=Notificacions
--Name[or]=ବିଜ୍ଞପ୍ତି
--Name[pa]=ਨੋਟੀਫਿਕੇਸ਼ਨ
--Name[pl]=Powiadomienia
--Name[pt]=Notificações
--Name[pt_BR]=Notificações
--Name[ro]=Notificări
--Name[ru]=Системные уведомления
--Name[se]=Dieđáhusat
--Name[si]=දැනුම් දීම්
--Name[sk]=Upozornenia
--Name[sl]=Obvestila
--Name[sr]=обавештења
--Name[sr@ijekavian]=обавјештења
--Name[sr@ijekavianlatin]=obavještenja
--Name[sr@latin]=obaveštenja
--Name[sv]=Underrättelser
--Name[ta]=Notifications
--Name[te]=నోటీసులు
--Name[tg]=Огоҳиномаҳо
--Name[th]=การแจ้งให้ทราบต่าง ๆ
--Name[tr]=Bildirimler
--Name[ug]=ئۇقتۇرۇشلار
--Name[uk]=Сповіщення
--Name[uz]=Xabarnomalar
--Name[uz@cyrillic]=Хабарномалар
--Name[wa]=Notifiaedjes
--Name[x-test]=xxNotificationsxx
--Name[zh_CN]=通知
--Name[zh_TW]=通知
--Comment=Display notifications and jobs
--Comment[ar]=أظهر التنبيهات والمهام
--Comment[ast]=Amosar notificaciones y xeres
--Comment[bg]=Показване на уведомления и задачи
--Comment[bs]=Prikazuje obavještenja i poslove
--Comment[ca]=Mostra les notificacions i els treballs
--Comment[ca@valencia]=Mostra les notificacions i els treballs
--Comment[cs]=Oznámení a úlohy
--Comment[da]=Vis bekendtgørelser og job
--Comment[de]=Benachrichtigungen und Aktionen anzeigen
--Comment[el]=Εμφανίζει ειδοποιήσεις και εργασίες
--Comment[en_GB]=Display notifications and jobs
--Comment[es]=Mostrar notificaciones y tareas
--Comment[et]=Märguannete ja tööde näitamine
--Comment[eu]=Bistaratu jakinarazpenak eta lanak
--Comment[fi]=Näyttää ilmoituksia ja töitä
--Comment[fr]=Affiche les notifications et les tâches
--Comment[ga]=Taispeáin fógraí agus jabanna
--Comment[gl]=Mostra notificacións e tarefas
--Comment[he]=משמש להצגת הודעות ועבודות
--Comment[hr]=Prikazuje obavijesti i poslove
--Comment[hu]=Értesítések és feladatok megjelenítése
--Comment[ia]=Monstra notificationes e labores
--Comment[id]=Tampilan notifikasi dan tugas
--Comment[is]=Birting tilkynninga og verka
--Comment[it]=Mostra notifiche e processi
--Comment[ja]=ディスプレイ通知とジョブ
--Comment[kk]=Құлақтандыру мен тапсырмаларды көрсету
--Comment[km]=បង្ហាញ​ការ​ជូនដំណឹង និង​ការងារ
--Comment[kn]=ಸೂಚನೆಗಳು ಹಾಗು ಕಾರ್ಯಗಳನ್ನು ಪ್ರದರ್ಶಿಸು
--Comment[ko]=알림과 작업 표시
--Comment[lt]=Rodyti pranešimus ir darbus
--Comment[lv]=Parāda paziņojumus un darbus
--Comment[mr]=सूचना व कार्यै दर्शवा
--Comment[nb]=Vis varslinger og jobber
--Comment[nds]=Bescheden un Opgaven wiesen
--Comment[nl]=Meldingen en taken tonen
--Comment[pa]=ਨੋਟੀਫਿਕੇਸ਼ਨ ਤੇ ਜਾਬ ਵੇਖੋ
--Comment[pl]=Wyświetlanie powiadomień i zadań
--Comment[pt]=Mostrar as notificações e tarefas
--Comment[pt_BR]=Exibe notificações e tarefas
--Comment[ro]=Afișează notificări și sarcini
--Comment[ru]=Уведомления и задания
--Comment[si]=කාර්ය සහ දැනුම්දීමෙ පෙන්වන්න
--Comment[sk]=Zobrazenie upozornení a úloh
--Comment[sl]=Prikazuje obvestila in opravila
--Comment[sr]=Приказује обавештења и послове
--Comment[sr@ijekavian]=Приказује обавјештења и послове
--Comment[sr@ijekavianlatin]=Prikazuje obavještenja i poslove
--Comment[sr@latin]=Prikazuje obaveštenja i poslove
--Comment[sv]=Visa underrättelser och jobb
--Comment[tg]=Иттилооти огоҳиҳо ва амалҳо
--Comment[th]=แสดงการแจ้งให้ทราบและงานต่าง ๆ
--Comment[tr]=Bildirimleri ve görevleri göster
--Comment[ug]=ئۇقتۇرۇش ۋە ۋەزىپىلەرنى كۆرسىتىدۇ
--Comment[uk]=Показ сповіщень і завдань
--Comment[vi]=Hiển thị thông báo và công việc
--Comment[wa]=Håyner notifiaedjes eyet bouyes
--Comment[x-test]=xxDisplay notifications and jobsxx
--Comment[zh_CN]=显示通知和任务
--Comment[zh_TW]=顯示通知與工作
--
--Type=Service
--Icon=preferences-desktop-notification
--X-KDE-ParentApp=
--X-KDE-PluginInfo-Author=Davide Bettio
--X-KDE-PluginInfo-Category=Tasks
--X-KDE-PluginInfo-Email=davide.bettio@kdemail.net
--X-KDE-PluginInfo-License=GPL
--X-KDE-PluginInfo-Name=org.kde.notifications
--X-KDE-PluginInfo-Version=0.1
--X-KDE-PluginInfo-Website=http://plasma.kde.org/
--X-KDE-ServiceTypes=Plasma/PopupApplet,Plasma/Applet
--X-Plasma-API=declarativeappletscript
--X-Plasma-DefaultSize=100,100
--X-Plasma-MainScript=ui/main.qml
--X-Plasma-RequiredExtensions=LaunchApp
--X-Plasma-NotificationArea=true
-diff --git a/plasma/generic/applets/notifications/plasma-applet-notifications.desktop b/plasma/generic/applets/notifications/plasma-applet-notifications.desktop
-new file mode 100644
-index 0000000..78a76f8
---- /dev/null
-+++ b/plasma/generic/applets/notifications/plasma-applet-notifications.desktop
-@@ -0,0 +1,164 @@
-+[Desktop Entry]
-+Name=Notifications
-+Name[ar]=تنبيهات
-+Name[ast]=Notificaciones
-+Name[be]=Абвяшчэнні
-+Name[be@latin]=Infarmavańnie
-+Name[bg]=Уведомяване
-+Name[bn]=বিজ্ঞপ্তি
-+Name[bn_IN]=সূচনাবার্তা
-+Name[br]=Kemenn
-+Name[bs]=obavještenja
-+Name[ca]=Notificacions
-+Name[ca@valencia]=Notificacions
-+Name[cs]=Oznamování
-+Name[csb]=Dôwanié wiédzë
-+Name[da]=Bekendtgørelser
-+Name[de]=Benachrichtigungen
-+Name[el]=Ειδοποιήσεις
-+Name[en_GB]=Notifications
-+Name[eo]=Atentigoj
-+Name[es]=Notificaciones
-+Name[et]=Märguanded
-+Name[eu]=Jakinarazpenak
-+Name[fa]=اخطارها
-+Name[fi]=Ilmoitukset
-+Name[fr]=Notifications
-+Name[fy]=Notifikaasjes
-+Name[ga]=Fógairt
-+Name[gl]=Notificacións
-+Name[gu]=નોંધણીઓ
-+Name[he]=הודעות
-+Name[hi]=सूचनाएँ
-+Name[hne]=सूचना मन ल
-+Name[hr]=Obavijesti
-+Name[hu]=Rendszerüzenetek
-+Name[ia]=Notificationes
-+Name[id]=Notifikasi
-+Name[is]=Kerfistilkynningar
-+Name[it]=Notifiche
-+Name[ja]=通知
-+Name[kk]=Құлақтандыру
-+Name[km]=សេចក្តី​ជូន​ដំណឹង​
-+Name[kn]=ಸೂಚನೆಗಳು
-+Name[ko]=알림
-+Name[ku]=Agahdarî
-+Name[lt]=Pranešimai
-+Name[lv]=Paziņojumi
-+Name[mai]=सूचनासभ
-+Name[mk]=Известувања
-+Name[ml]=അറിയിപ്പുകള്‍
-+Name[mr]=सूचना
-+Name[ms]=Pemberitahuan
-+Name[nb]=Varslinger
-+Name[nds]=Bescheden
-+Name[ne]=सूचना
-+Name[nl]=Meldingen
-+Name[nn]=Varslingar
-+Name[oc]=Notificacions
-+Name[or]=ବିଜ୍ଞପ୍ତି
-+Name[pa]=ਨੋਟੀਫਿਕੇਸ਼ਨ
-+Name[pl]=Powiadomienia
-+Name[pt]=Notificações
-+Name[pt_BR]=Notificações
-+Name[ro]=Notificări
-+Name[ru]=Системные уведомления
-+Name[se]=Dieđáhusat
-+Name[si]=දැනුම් දීම්
-+Name[sk]=Upozornenia
-+Name[sl]=Obvestila
-+Name[sr]=обавештења
-+Name[sr@ijekavian]=обавјештења
-+Name[sr@ijekavianlatin]=obavještenja
-+Name[sr@latin]=obaveštenja
-+Name[sv]=Underrättelser
-+Name[ta]=Notifications
-+Name[te]=నోటీసులు
-+Name[tg]=Огоҳиномаҳо
-+Name[th]=การแจ้งให้ทราบต่าง ๆ
-+Name[tr]=Bildirimler
-+Name[ug]=ئۇقتۇرۇشلار
-+Name[uk]=Сповіщення
-+Name[uz]=Xabarnomalar
-+Name[uz@cyrillic]=Хабарномалар
-+Name[wa]=Notifiaedjes
-+Name[x-test]=xxNotificationsxx
-+Name[zh_CN]=通知
-+Name[zh_TW]=通知
-+Comment=Display notifications and jobs
-+Comment[ar]=أظهر التنبيهات والمهام
-+Comment[ast]=Amosar notificaciones y xeres
-+Comment[bg]=Показване на уведомления и задачи
-+Comment[bs]=Prikazuje obavještenja i poslove
-+Comment[ca]=Mostra les notificacions i els treballs
-+Comment[ca@valencia]=Mostra les notificacions i els treballs
-+Comment[cs]=Oznámení a úlohy
-+Comment[da]=Vis bekendtgørelser og job
-+Comment[de]=Benachrichtigungen und Aktionen anzeigen
-+Comment[el]=Εμφανίζει ειδοποιήσεις και εργασίες
-+Comment[en_GB]=Display notifications and jobs
-+Comment[es]=Mostrar notificaciones y tareas
-+Comment[et]=Märguannete ja tööde näitamine
-+Comment[eu]=Bistaratu jakinarazpenak eta lanak
-+Comment[fi]=Näyttää ilmoituksia ja töitä
-+Comment[fr]=Affiche les notifications et les tâches
-+Comment[ga]=Taispeáin fógraí agus jabanna
-+Comment[gl]=Mostra notificacións e tarefas
-+Comment[he]=משמש להצגת הודעות ועבודות
-+Comment[hr]=Prikazuje obavijesti i poslove
-+Comment[hu]=Értesítések és feladatok megjelenítése
-+Comment[ia]=Monstra notificationes e labores
-+Comment[id]=Tampilan notifikasi dan tugas
-+Comment[is]=Birting tilkynninga og verka
-+Comment[it]=Mostra notifiche e processi
-+Comment[ja]=ディスプレイ通知とジョブ
-+Comment[kk]=Құлақтандыру мен тапсырмаларды көрсету
-+Comment[km]=បង្ហាញ​ការ​ជូនដំណឹង និង​ការងារ
-+Comment[kn]=ಸೂಚನೆಗಳು ಹಾಗು ಕಾರ್ಯಗಳನ್ನು ಪ್ರದರ್ಶಿಸು
-+Comment[ko]=알림과 작업 표시
-+Comment[lt]=Rodyti pranešimus ir darbus
-+Comment[lv]=Parāda paziņojumus un darbus
-+Comment[nb]=Vis varslinger og jobber
-+Comment[nds]=Bescheden un Opgaven wiesen
-+Comment[nl]=Meldingen en taken tonen
-+Comment[pa]=ਨੋਟੀਫਿਕੇਸ਼ਨ ਤੇ ਜਾਬ ਵੇਖੋ
-+Comment[pl]=Wyświetlanie powiadomień i zadań
-+Comment[pt]=Mostrar as notificações e tarefas
-+Comment[pt_BR]=Exibe notificações e tarefas
-+Comment[ro]=Afișează notificări și sarcini
-+Comment[ru]=Уведомления и задания
-+Comment[si]=කාර්ය සහ දැනුම්දීමෙ පෙන්වන්න
-+Comment[sk]=Zobrazenie upozornení a úloh
-+Comment[sl]=Prikazuje obvestila in opravila
-+Comment[sr]=Приказује обавештења и послове
-+Comment[sr@ijekavian]=Приказује обавјештења и послове
-+Comment[sr@ijekavianlatin]=Prikazuje obavještenja i poslove
-+Comment[sr@latin]=Prikazuje obaveštenja i poslove
-+Comment[sv]=Visa underrättelser och jobb
-+Comment[tg]=Иттилооти огоҳиҳо ва амалҳо
-+Comment[th]=แสดงการแจ้งให้ทราบและงานต่าง ๆ
-+Comment[tr]=Bildirimleri ve görevleri göster
-+Comment[ug]=ئۇقتۇرۇش ۋە ۋەزىپىلەرنى كۆرسىتىدۇ
-+Comment[uk]=Показ сповіщень і завдань
-+Comment[vi]=Hiển thị thông báo và công việc
-+Comment[wa]=Håyner notifiaedjes eyet bouyes
-+Comment[x-test]=xxDisplay notifications and jobsxx
-+Comment[zh_CN]=显示通知和任务
-+Comment[zh_TW]=顯示通知與工作
-+
-+Icon=dialog-information
-+Type=Service
-+X-KDE-ServiceTypes=Plasma/Applet
-+
-+X-KDE-Library=plasma_applet_notifications
-+X-KDE-PluginInfo-Author=Marco Martin
-+X-KDE-PluginInfo-Email=notmart@gmail.com
-+X-KDE-PluginInfo-Name=notifications
-+X-KDE-PluginInfo-Version=1.0
-+X-KDE-PluginInfo-Website=http://plasma.kde.org/
-+X-KDE-PluginInfo-Category=System Information
-+X-KDE-PluginInfo-Depends=
-+X-KDE-PluginInfo-License=GPL v2+
-+X-KDE-PluginInfo-EnabledByDefault=true
-+
-+X-Plasma-NotificationArea=true
-diff --git a/plasma/generic/applets/notifications/platformcontents/touch/ui/NotificationDelegate/NotificationDelegate.qml b/plasma/generic/applets/notifications/platformcontents/touch/ui/NotificationDelegate/NotificationDelegate.qml
-deleted file mode 100644
-index bdb74c2..0000000
---- a/plasma/generic/applets/notifications/platformcontents/touch/ui/NotificationDelegate/NotificationDelegate.qml
-+++ /dev/null
-@@ -1,195 +0,0 @@
--/*
-- *   Copyright 2011 Marco Martin <notmart@gmail.com>
-- *
-- *   This program 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, 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 Library General Public License for more details
-- *
-- *   You should have received a copy of the GNU Library 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.
-- */
--
--import QtQuick 1.0
--import org.kde.plasma.core 0.1 as PlasmaCore
--import org.kde.plasma.components 0.1 as PlasmaComponents
--import org.kde.qtextracomponents 0.1
--
--PlasmaComponents.ListItem {
--    id: notificationItem
--    opacity: 1-Math.abs(x)/width
--    width: popupFlickable.width
--    property int toolIconSize: theme.smallMediumIconSize
--    property int layoutSpacing: 4
--
--    visible: appTabBar.currentTab == allAppsTab || appTabBar.currentTab.text == appName
--
--    Component.onCompleted: {
--        allApplicationsModel.addApplication(appIcon, appName)
--        mainScrollArea.height = mainScrollArea.implicitHeight
--    }
--    Component.onDestruction: {
--        allApplicationsModel.removeApplication(model.appName)
--        mainScrollArea.height = mainScrollArea.implicitHeight
--    }
--    Timer {
--        interval: 10*60*1000
--        repeat: false
--        running: !idleTimeSource.idle
--        onTriggered: {
--            notificationsModel.remove(index)
--        }
--    }
--
--
--    MouseArea {
--        width: parent.width
--        height: childrenRect.height
--        drag {
--            target: notificationItem
--            axis: Drag.XAxis
--            //kind of an hack over Column being too smart
--            minimumX: -parent.width + 1
--            maximumX: parent.width - 1
--        }
--        onReleased: {
--            if (notificationItem.x < -notificationItem.width/2) {
--                removeAnimation.exitFromRight = false
--                removeAnimation.running = true
--            } else if (notificationItem.x > notificationItem.width/2 ) {
--                removeAnimation.exitFromRight = true
--                removeAnimation.running = true
--            } else {
--                resetAnimation.running = true
--            }
--        }
--        SequentialAnimation {
--            id: removeAnimation
--            property bool exitFromRight: true
--            NumberAnimation {
--                target: notificationItem
--                properties: "x"
--                to: removeAnimation.exitFromRight ? notificationItem.width-1 : 1-notificationItem.width
--                duration: 250
--                easing.type: Easing.InOutQuad
--            }
--            NumberAnimation {
--                target: notificationItem
--                properties: "height"
--                to: 0
--                duration: 250
--                easing.type: Easing.InOutQuad
--            }
--            ScriptAction {
--                script: notificationsModel.remove(index)
--            }
--        }
--        SequentialAnimation {
--            id: resetAnimation
--            NumberAnimation {
--                target: notificationItem
--                properties: "x"
--                to: 0
--                duration: 250
--                easing.type: Easing.InOutQuad
--            }
--        }
--        Column {
--            spacing: notificationItem.layoutSpacing
--            width: parent.width
--            Item {
--                width: parent.width
--                height: summaryLabel.height
--
--                PlasmaComponents.Label {
--                    id: summaryLabel
--                    text: summary
--                    height: paintedHeight
--                    anchors {
--                        left: parent.left
--                        right: parent.right
--                        leftMargin: closeButton.width
--                        rightMargin: closeButton.width
--                    }
--                    horizontalAlignment: Text.AlignHCenter
--                    elide: Text.ElideRight
--                }
--
--                PlasmaComponents.ToolButton {
--                    id: closeButton
--                    iconSource: "window-close"
--                    width: notificationItem.toolIconSize
--                    height: width
--                    onClicked: removeAnimation.running = true
--                    anchors {
--                        top: parent.top
--                        right: parent.right
--                    }
--                }
--            }
--
--            Item {
--                height: childrenRect.height
--                width: parent.width
--                QIconItem {
--                    id: appIconItem
--                    icon: QIcon(appIcon)
--                    width: theme.largeIconSize
--                    height: theme.largeIconSize
--                    visible: !imageItem.visible
--                    anchors {
--                        left: parent.left
--                        verticalCenter: parent.verticalCenter
--                    }
--                }
--                QImageItem {
--                    id: imageItem
--                    anchors.fill: appIconItem
--                    image: model.image
--                    smooth: true
--                    visible: nativeWidth > 0
--                }
--                PlasmaComponents.Label {
--                    text: body
--                    color: theme.textColor
--                    anchors {
--                        left: appIconItem.right
--                        right: actionsColumn.left
--                        verticalCenter: parent.verticalCenter
--                        leftMargin: 6
--                        rightMargin: 6
--                    }
--                    wrapMode: Text.Wrap
--                }
--                Column {
--                    id: actionsColumn
--                    spacing: notificationItem.layoutSpacing
--                    anchors {
--                        right: parent.right
--                        rightMargin: 6
--                        verticalCenter: parent.verticalCenter
--                    }
--                    Repeater {
--                        model: actions
--                        PlasmaComponents.Button {
--                            text: model.text
--                            width: theme.defaultFont.mSize.width * 8
--                            height: theme.defaultFont.mSize.width * 3
--                            onClicked: {
--                                executeAction(source, model.id)
--                                actionsColumn.visible = false
--                            }
--                        }
--                    }
--                }
--            }
--        }
--    }
--}
-diff --git a/plasma/generic/applets/notifications/platformcontents/touch/ui/NotificationDelegate/qmldir b/plasma/generic/applets/notifications/platformcontents/touch/ui/NotificationDelegate/qmldir
-deleted file mode 100644
-index 88fc37a..0000000
---- a/plasma/generic/applets/notifications/platformcontents/touch/ui/NotificationDelegate/qmldir
-+++ /dev/null
-@@ -1 +0,0 @@
--NotificationDelegate 0.1 NotificationDelegate.qml
-diff --git a/plasma/generic/applets/notifications/platformcontents/touch/ui/uiproperties.js b/plasma/generic/applets/notifications/platformcontents/touch/ui/uiproperties.js
-deleted file mode 100644
-index f2f3d6b..0000000
---- a/plasma/generic/applets/notifications/platformcontents/touch/ui/uiproperties.js
-+++ /dev/null
-@@ -1,23 +0,0 @@
--/*
-- *   Copyright 2012 Marco Martin <notmart@gmail.com>
-- *
-- *   This program 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, 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 Library General Public License for more details
-- *
-- *   You should have received a copy of the GNU Library 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.
-- */
--
--
--var toolIconSize = theme.mediumIconSize
--var layoutSpacing = 6
--var touchInput = true
-diff --git a/plasma/generic/applets/notifications/protocols/jobs/dbusjob.cpp b/plasma/generic/applets/notifications/protocols/jobs/dbusjob.cpp
-new file mode 100644
-index 0000000..7c89275
---- /dev/null
-+++ b/plasma/generic/applets/notifications/protocols/jobs/dbusjob.cpp
-@@ -0,0 +1,54 @@
-+/***************************************************************************
-+ *   Copyright (C) 2008 Rob Scheepmaker <r.scheepmaker@student.utwente.nl> *
-+ *                                                                         *
-+ *   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 "dbusjob.h"
-+
-+#include <KDebug>
-+
-+
-+
-+DBusJob::DBusJob(const QString &source, QObject *parent)
-+    : Job(parent),
-+      m_source(source)
-+{
-+}
-+
-+DBusJob::~DBusJob()
-+{
-+    emit jobDeleted(m_source);
-+}
-+
-+void DBusJob::suspend()
-+{
-+    emit suspend(m_source);
-+    kDebug() << "suspend";
-+}
-+
-+void DBusJob::resume()
-+{
-+    emit resume(m_source);
-+    kDebug() << "resume";
-+}
-+
-+void DBusJob::stop()
-+{
-+    emit stop(m_source);
-+    kDebug() << "cancel";
-+}
-+
-diff --git a/plasma/generic/applets/notifications/protocols/jobs/dbusjob.h b/plasma/generic/applets/notifications/protocols/jobs/dbusjob.h
-new file mode 100644
-index 0000000..2e973d6
---- /dev/null
-+++ b/plasma/generic/applets/notifications/protocols/jobs/dbusjob.h
-@@ -0,0 +1,54 @@
-+/***************************************************************************
-+ *   Copyright (C) 2008 Rob Scheepmaker <r.scheepmaker@student.utwente.nl> *
-+ *                                                                         *
-+ *   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 DBUSJOB_H
-+#define DBUSJOB_H
-+
-+#include "../../core/job.h"
-+
-+
-+
-+class DBusJob : public Job
-+{
-+    Q_OBJECT
-+
-+    friend class DBusJobProtocol;
-+
-+public:
-+    DBusJob(const QString &source, QObject *parent = 0);
-+    ~DBusJob();
-+
-+public slots:
-+    void suspend();
-+    void resume();
-+    void stop();
-+
-+signals:
-+    void jobDeleted(const QString &source);
-+    void suspend(const QString &source);
-+    void resume(const QString &source);
-+    void stop(const QString &source);
-+
-+private:
-+    QString m_source;
-+};
-+
-+
-+
-+#endif
-diff --git a/plasma/generic/applets/notifications/protocols/jobs/dbusjobprotocol.cpp b/plasma/generic/applets/notifications/protocols/jobs/dbusjobprotocol.cpp
-new file mode 100644
-index 0000000..dff6dc9
---- /dev/null
-+++ b/plasma/generic/applets/notifications/protocols/jobs/dbusjobprotocol.cpp
-@@ -0,0 +1,180 @@
-+/***************************************************************************
-+ *   Copyright (C) 2008 Rob Scheepmaker <r.scheepmaker@student.utwente.nl> *
-+ *                                                                         *
-+ *   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 "dbusjob.h"
-+#include "dbusjobprotocol.h"
-+
-+
-+#include <KConfigGroup>
-+
-+#include <Plasma/DataEngineManager>
-+#include <Plasma/Service>
-+#include <Plasma/ServiceJob>
-+
-+static const char engineName[] = "applicationjobs";
-+
-+DBusJobProtocol::DBusJobProtocol(Manager *parent)
-+    : Protocol(parent),
-+      m_manager(parent),
-+      m_engine(0)
-+{
-+}
-+
-+
-+DBusJobProtocol::~DBusJobProtocol()
-+{
-+    if (m_engine) {
-+        Plasma::DataEngineManager::self()->unloadEngine(engineName);
-+    }
-+
-+    foreach (DBusJob *job, m_jobs) {
-+        disconnect(job);
-+        job->destroy();
-+    }
-+
-+    m_jobs.clear();
-+}
-+
-+
-+void DBusJobProtocol::init()
-+{
-+    m_engine = Plasma::DataEngineManager::self()->loadEngine(engineName);
-+
-+    if (!m_engine->isValid()) {
-+        Plasma::DataEngineManager::self()->unloadEngine(engineName);
-+        m_engine = 0;
-+        return;
-+    }
-+
-+    connect(m_engine, SIGNAL(sourceAdded(QString)),
-+            this, SLOT(prepareJob(QString)));
-+    connect(m_engine, SIGNAL(sourceRemoved(QString)),
-+            this, SLOT(removeJob(QString)));
-+}
-+
-+void DBusJobProtocol::prepareJob(const QString &source)
-+{
-+    m_engine->connectSource(source, this);
-+}
-+
-+void DBusJobProtocol::dataUpdated(const QString &source, const Plasma::DataEngine::Data &data)
-+{
-+    DBusJob *job = m_jobs.value(source, 0);
-+
-+    if (!job) {
-+        job = new DBusJob(source, this);
-+        m_jobs.insert(source, job);
-+        connect(job, SIGNAL(jobDeleted(QString)),
-+                this, SLOT(removeJob(QString)));
-+        connect(job, SIGNAL(suspend(QString)),
-+                this, SLOT(suspend(QString)));
-+        connect(job, SIGNAL(resume(QString)),
-+                this, SLOT(resume(QString)));
-+        connect(job, SIGNAL(stop(QString)),
-+                this, SLOT(stop(QString)));
-+        connect(job, SIGNAL(ready(Job*)),
-+                this, SIGNAL(jobCreated(Job*)));
-+    }
-+
-+    job->setApplicationName(data.value("appName").toString());
-+    job->setApplicationIconName(data.value("appIconName").toString());
-+    job->setPercentage(data["percentage"].toUInt());
-+    job->setError(data["error"].toString());
-+    job->setMessage(data["infoMessage"].toString());
-+    job->setSuspendable(data["suspendable"].toBool());
-+    job->setKillable(data["killable"].toBool());
-+    job->setSpeed(data["speed"].toString());
-+    job->setNumericSpeed(data["numericSpeed"].toLongLong());
-+    job->setEta(data["eta"].toULongLong());
-+
-+    if (data["state"].toString() == "running") {
-+        job->setState(Job::Running);
-+    } else if (data["state"].toString() == "suspended") {
-+        job->setState(Job::Suspended);
-+    } else {
-+        job->setState(Job::Stopped);
-+    }
-+
-+    int i = 0;
-+    QList<QPair<QString, QString> > labels;
-+    while (data.contains(QString("label%1").arg(i))) {
-+        QPair<QString, QString> label;
-+        label.first = data[QString("labelName%1").arg(i)].toString();
-+        label.second = data[QString("label%1").arg(i)].toString();
-+        labels << label;
-+        i++;
-+    }
-+    job->setLabels(labels);
-+
-+    i = 0;
-+    QMap<QString, qlonglong> totalAmounts;
-+    while (data.contains(QString("totalUnit%1").arg(i))) {
-+        QString unit = data[QString("totalUnit%1").arg(i)].toString();
-+        qlonglong amount = data[QString("totalAmount%1").arg(i)].toLongLong();
-+        totalAmounts[unit] = amount;
-+        i++;
-+    }
-+    job->setTotalAmounts(totalAmounts);
-+
-+    i = 0;
-+    QMap<QString, qlonglong> processedAmounts;
-+    while (data.contains(QString("processedUnit%1").arg(i))) {
-+        QString unit = data[QString("processedUnit%1").arg(i)].toString();
-+        qlonglong amount = data[QString("processedAmount%1").arg(i)].toLongLong();
-+        processedAmounts[unit] = amount;
-+        i++;
-+    }
-+
-+    job->setProcessedAmounts(processedAmounts);
-+}
-+
-+void DBusJobProtocol::removeJob(const QString &source)
-+{
-+    if (m_jobs.contains(source)) {
-+        DBusJob *job = m_jobs.take(source);
-+        job->setState(Job::Stopped);
-+        job->destroy();
-+    }
-+}
-+
-+void DBusJobProtocol::suspend(const QString &source)
-+{
-+    Plasma::Service *service = m_engine->serviceForSource(source);
-+    KConfigGroup op = service->operationDescription("suspend");
-+    KJob *job = service->startOperationCall(op);
-+    connect(job, SIGNAL(finished(KJob*)), service, SLOT(deleteLater()));
-+}
-+
-+void DBusJobProtocol::resume(const QString &source)
-+{
-+    Plasma::Service *service = m_engine->serviceForSource(source);
-+    KConfigGroup op = service->operationDescription("resume");
-+    KJob *job = service->startOperationCall(op);
-+    connect(job, SIGNAL(finished(KJob*)), service, SLOT(deleteLater()));
-+}
-+
-+void DBusJobProtocol::stop(const QString &source)
-+{
-+    Plasma::Service *service = m_engine->serviceForSource(source);
-+    KConfigGroup op = service->operationDescription("stop");
-+    KJob *job = service->startOperationCall(op);
-+    connect(job, SIGNAL(finished(KJob*)), service, SLOT(deleteLater()));
-+}
-+
-+#include "dbusjobprotocol.moc"
-diff --git a/plasma/generic/applets/notifications/protocols/jobs/dbusjobprotocol.h b/plasma/generic/applets/notifications/protocols/jobs/dbusjobprotocol.h
-new file mode 100644
-index 0000000..230356c
---- /dev/null
-+++ b/plasma/generic/applets/notifications/protocols/jobs/dbusjobprotocol.h
-@@ -0,0 +1,57 @@
-+/***************************************************************************
-+ *   Copyright (C) 2008 Rob Scheepmaker <r.scheepmaker@student.utwente.nl> *
-+ *                                                                         *
-+ *   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 DBUSJOBPROTOCOL_H
-+#define DBUSJOBPROTOCOL_H
-+
-+#include "../../core/protocol.h"
-+#include "../../core/notificationsmanager.h"
-+
-+#include <plasma/dataengine.h>
-+
-+
-+class DBusJob;
-+
-+class DBusJobProtocol : public Protocol
-+{
-+    Q_OBJECT
-+
-+public:
-+    DBusJobProtocol(Manager *parent);
-+    ~DBusJobProtocol();
-+    void init();
-+
-+private slots:
-+    void prepareJob(const QString &source);
-+    void dataUpdated(const QString &source, const Plasma::DataEngine::Data &data);
-+    void removeJob(const QString &source);
-+    //void relayAction(const QString &source, const QString &actionName);
-+    void suspend(const QString &source);
-+    void resume(const QString &source);
-+    void stop(const QString &source);
-+
-+private:
-+    Manager *m_manager;
-+    Plasma::DataEngine *m_engine;
-+    QHash<QString, DBusJob*> m_jobs;
-+};
-+
-+
-+
-+#endif
-diff --git a/plasma/generic/applets/notifications/protocols/notifications/dbusnotification.cpp b/plasma/generic/applets/notifications/protocols/notifications/dbusnotification.cpp
-new file mode 100644
-index 0000000..2c28ff2
---- /dev/null
-+++ b/plasma/generic/applets/notifications/protocols/notifications/dbusnotification.cpp
-@@ -0,0 +1,48 @@
-+/***************************************************************************
-+ *   dbusnotification.cpp                                                  *
-+ *                                                                         *
-+ *   Copyright (C) 2008 Jason Stubbs <jasonbstubbs@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 .        *
-+ ***************************************************************************/
-+
-+#include "dbusnotification.h"
-+
-+#include <KDebug>
-+
-+
-+DBusNotification::DBusNotification(const QString &source, QObject *parent)
-+    : Notification(parent),
-+      m_source(source)
-+{
-+}
-+
-+DBusNotification::~DBusNotification()
-+{
-+    emit notificationDeleted(m_source);
-+}
-+
-+void DBusNotification::remove()
-+{
-+    emit unregisterNotification(m_source);
-+    deleteLater();
-+}
-+
-+void DBusNotification::triggerAction(const QString &actionId)
-+{
-+    emit actionTriggered(m_source, actionId);
-+}
-+
-diff --git a/plasma/generic/applets/notifications/protocols/notifications/dbusnotification.h b/plasma/generic/applets/notifications/protocols/notifications/dbusnotification.h
-new file mode 100644
-index 0000000..213cc71
---- /dev/null
-+++ b/plasma/generic/applets/notifications/protocols/notifications/dbusnotification.h
-@@ -0,0 +1,54 @@
-+/***************************************************************************
-+ *   dbusnotification.h                                                    *
-+ *                                                                         *
-+ *   Copyright (C) 2008 Jason Stubbs <jasonbstubbs@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 DBUSNOTIFICATION_H
-+#define DBUSNOTIFICATION_H
-+
-+#include "../../core/notification.h"
-+
-+
-+
-+class DBusNotification : public Notification
-+{
-+    Q_OBJECT
-+
-+    friend class DBusNotificationProtocol;
-+
-+public:
-+    DBusNotification(const QString &source, QObject *parent = 0);
-+    ~DBusNotification();
-+
-+public slots:
-+    void remove();
-+    void triggerAction(const QString &actionId);
-+
-+signals:
-+    void notificationDeleted(const QString &source);
-+    void actionTriggered(const QString &source, const QString &actionId);
-+    void unregisterNotification(const QString &source);
-+
-+private:
-+    QString m_source;
-+};
-+
-+
-+
-+#endif
-diff --git a/plasma/generic/applets/notifications/protocols/notifications/dbusnotificationprotocol.cpp b/plasma/generic/applets/notifications/protocols/notifications/dbusnotificationprotocol.cpp
-new file mode 100644
-index 0000000..fd94048
---- /dev/null
-+++ b/plasma/generic/applets/notifications/protocols/notifications/dbusnotificationprotocol.cpp
-@@ -0,0 +1,192 @@
-+/***************************************************************************
-+ *   fdoprotocol.cpp                                                       *
-+ *                                                                         *
-+ *   Copyright (C) 2008 Jason Stubbs <jasonbstubbs@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 .        *
-+ ***************************************************************************/
-+
-+#include "dbusnotification.h"
-+#include "dbusnotificationprotocol.h"
-+
-+#include <KConfigGroup>
-+#include <KDebug>
-+#include <KIcon>
-+
-+#include <Plasma/DataEngineManager>
-+#include <Plasma/Service>
-+#include <Plasma/ServiceJob>
-+
-+
-+static const char engineName[] = "notifications";
-+
-+DBusNotificationProtocol::DBusNotificationProtocol(Manager *parent)
-+    : Protocol(parent),
-+      m_manager(parent),
-+      m_engine(0)
-+{
-+}
-+
-+
-+DBusNotificationProtocol::~DBusNotificationProtocol()
-+{
-+    if (m_engine) {
-+        Plasma::DataEngineManager::self()->unloadEngine(engineName);
-+    }
-+}
-+
-+
-+void DBusNotificationProtocol::init()
-+{
-+    m_engine = Plasma::DataEngineManager::self()->loadEngine(engineName);
-+
-+    if (!m_engine->isValid()) {
-+        m_engine = 0;
-+        Plasma::DataEngineManager::self()->unloadEngine(engineName);
-+        return;
-+    }
-+
-+    connect(m_engine, SIGNAL(sourceAdded(QString)),
-+            this, SLOT(prepareNotification(QString)));
-+    connect(m_engine, SIGNAL(sourceRemoved(QString)),
-+            this, SLOT(hideNotification(QString)));
-+}
-+
-+
-+void DBusNotificationProtocol::prepareNotification(const QString &source)
-+{
-+    if (m_engine) {
-+        m_engine->connectSource(source, this);
-+    }
-+}
-+
-+
-+void DBusNotificationProtocol::dataUpdated(const QString &source, const Plasma::DataEngine::Data &data)
-+{
-+    bool isNew = !m_notifications.contains(source);
-+
-+    if (isNew) {
-+        DBusNotification * notification = new DBusNotification(source, this);
-+        connect(notification, SIGNAL(unregisterNotification(QString)),
-+                this, SLOT(unregisterNotification(QString)));
-+        connect(notification, SIGNAL(notificationDeleted(QString)),
-+                this, SLOT(notificationDeleted(QString)));
-+        connect(notification, SIGNAL(actionTriggered(QString,QString)),
-+                this, SLOT(relayAction(QString,QString)));
-+        m_notifications[source] = notification;
-+    }
-+
-+    DBusNotification* notification = m_notifications[source];
-+    notification->setApplicationName(data.value("appName").toString());
-+    notification->setApplicationIcon(KIcon(data.value("appIcon").toString()));
-+    notification->setSummary(data.value("summary").toString());
-+    notification->setMessage(data.value("body").toString());
-+    notification->setTimeout(data.value("expireTimeout").toInt());
-+    notification->setUrgency(data.value("urgency").toInt());
-+
-+    if (data.contains("image")) {
-+        QImage image = qvariant_cast<QImage>(data.value("image"));
-+        notification->setImage(image);
-+    }
-+
-+    QStringList codedActions = data.value("actions").toStringList();
-+    if (codedActions.count() % 2 != 0) {
-+        kDebug() << "Invalid actions" << codedActions << "from" << notification->applicationName();
-+        codedActions.clear();
-+    }
-+
-+    QHash<QString, QString> actions;
-+    QStringList actionOrder;
-+
-+    while (!codedActions.isEmpty()) {
-+        QString actionId = codedActions.takeFirst();
-+        QString actionName = codedActions.takeFirst();
-+        actions.insert(actionId, actionName);
-+        actionOrder.append(actionId);
-+    }
-+
-+    notification->setActions(actions);
-+    notification->setActionOrder(actionOrder);
-+
-+    if (isNew) {
-+        emit notificationCreated(notification);
-+    } else {
-+        emit notification->changed(notification);
-+    }
-+}
-+
-+
-+void DBusNotificationProtocol::relayAction(const QString &source, const QString &actionId)
-+{
-+    if (!m_engine) {
-+        return;
-+    }
-+
-+    Plasma::Service *service = m_engine->serviceForSource(source);
-+    KConfigGroup op = service->operationDescription("invokeAction");
-+
-+    if (op.isValid()) {
-+        op.writeEntry("actionId", actionId);
-+        KJob *job = service->startOperationCall(op);
-+        connect(job, SIGNAL(finished(KJob*)), service, SLOT(deleteLater()));
-+    } else {
-+        delete service;
-+        kDebug() << "invalid operation";
-+    }
-+}
-+
-+void DBusNotificationProtocol::unregisterNotification(const QString &source)
-+{
-+    if (!m_engine) {
-+        return;
-+    }
-+
-+    Plasma::Service *service = m_engine->serviceForSource(source);
-+    KConfigGroup op = service->operationDescription("userClosed");
-+    KJob *job = service->startOperationCall(op);
-+    connect(job, SIGNAL(finished(KJob*)), service, SLOT(deleteLater()));
-+}
-+
-+void DBusNotificationProtocol::hideNotification(const QString &source)
-+{
-+    if (m_notifications.contains(source)) {
-+        m_notifications.value(source)->hide();
-+    }
-+}
-+
-+void DBusNotificationProtocol::removeNotification(const QString &source)
-+{
-+    if (m_notifications.contains(source)) {
-+        m_notifications.take(source)->destroy();
-+    }
-+}
-+
-+void DBusNotificationProtocol::notificationDeleted(const QString &source)
-+{
-+    if (!m_engine) {
-+        return;
-+    }
-+
-+    Plasma::Service *service = m_engine->serviceForSource(source);
-+    KConfigGroup op = service->operationDescription("userClosed");
-+    KJob *job = service->startOperationCall(op);
-+    connect(job, SIGNAL(finished(KJob*)), service, SLOT(deleteLater()));
-+
-+    m_notifications.remove(source);
-+}
-+
-+
-+#include "dbusnotificationprotocol.moc"
-diff --git a/plasma/generic/applets/notifications/protocols/notifications/dbusnotificationprotocol.h b/plasma/generic/applets/notifications/protocols/notifications/dbusnotificationprotocol.h
-new file mode 100644
-index 0000000..e52dfd9
---- /dev/null
-+++ b/plasma/generic/applets/notifications/protocols/notifications/dbusnotificationprotocol.h
-@@ -0,0 +1,62 @@
-+/***************************************************************************
-+ *   dbusnotificationprotocol.h                                            *
-+ *                                                                         *
-+ *   Copyright (C) 2008 Jason Stubbs <jasonbstubbs@gmail.com>              *
-+ *   Copyright (C) 2008 Dmitry Suzdalev <dimsuz@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 DBUSNOTIFICATIONPROTOCOL_H
-+#define DBUSNOTIFICATIONPROTOCOL_H
-+
-+#include "../../core/protocol.h"
-+#include "../../core/notificationsmanager.h"
-+
-+#include <QHash>
-+
-+#include <Plasma/DataEngine>
-+
-+
-+class DBusNotification;
-+
-+class DBusNotificationProtocol : public Protocol
-+{
-+    Q_OBJECT
-+
-+public:
-+    DBusNotificationProtocol(Manager *parent);
-+    ~DBusNotificationProtocol();
-+    void init();
-+
-+private slots:
-+    void prepareNotification(const QString &source);
-+    void dataUpdated(const QString &source, const Plasma::DataEngine::Data &data);
-+    void removeNotification(const QString &source);
-+    void notificationDeleted(const QString &source);
-+    void relayAction(const QString &source, const QString &actionId);
-+    void unregisterNotification(const QString&);
-+    void hideNotification(const QString &source);
-+
-+private:
-+    Manager *m_manager;
-+    Plasma::DataEngine *m_engine;
-+    QHash<QString, DBusNotification*> m_notifications;
-+};
-+
-+
-+
-+#endif
-diff --git a/plasma/generic/applets/notifications/ui/busywidget.cpp b/plasma/generic/applets/notifications/ui/busywidget.cpp
-new file mode 100644
-index 0000000..6bce0d7
---- /dev/null
-+++ b/plasma/generic/applets/notifications/ui/busywidget.cpp
-@@ -0,0 +1,352 @@
-+/***************************************************************************
-+ *   Copyright (C) 2008, 2009 Rob Scheepmaker <r.scheepmaker@student.utwente.nl> *
-+ *   Copyright (C) 2010 Marco Martin <notmart@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 .        *
-+ ***************************************************************************/
-+
-+#include "busywidget.h"
-+#include <fixx11h.h>
-+
-+#include <QtGui/QPainter>
-+#include <QtGui/QTextOption>
-+#include <QtGui/QStyleOptionGraphicsItem>
-+#include <QtGui/QWidget> // QWIDGETSIZE_MAX
-+#include <QSequentialAnimationGroup>
-+
-+#include <plasma/extender.h>
-+#include <plasma/extenderitem.h>
-+#include <plasma/extendergroup.h>
-+#include <plasma/popupapplet.h>
-+#include <plasma/tooltipmanager.h>
-+#include <plasma/theme.h>
-+#include <Plasma/Animation>
-+#include <Plasma/Animator>
-+
-+#include <KIcon>
-+#include <KGlobalSettings>
-+
-+#include "../core/notificationsmanager.h"
-+#include "../core/job.h"
-+#include "../core/notification.h"
-+#include "../core/completedjobnotification.h"
-+
-+
-+
-+BusyWidget::BusyWidget(Plasma::PopupApplet *parent, const Manager *manager)
-+    : Plasma::BusyWidget(parent),
-+      m_icon("dialog-information"),
-+      m_state(Empty),
-+      m_svg(new Plasma::Svg(this)),
-+      m_systray(parent),
-+      m_manager(manager),
-+      m_total(0),
-+      m_suppressToolTips(false)
-+{
-+    setAcceptsHoverEvents(true);
-+    m_svg->setImagePath("icons/notification");
-+    m_svg->setContainsMultipleImages(true);
-+    setRunning(false);
-+
-+    m_fadeInAnimation = Plasma::Animator::create(Plasma::Animator::PixmapTransitionAnimation);
-+    m_fadeInAnimation->setTargetWidget(this);
-+    m_fadeInAnimation->setProperty("duration", 1000);
-+    m_fadeInAnimation->setProperty("targetPixmap", m_svg->pixmap("notification-active"));
-+
-+    m_fadeOutAnimation = Plasma::Animator::create(Plasma::Animator::PixmapTransitionAnimation);
-+    m_fadeOutAnimation->setTargetWidget(this);
-+    m_fadeOutAnimation->setProperty("duration", 1000);
-+    m_fadeOutAnimation->setProperty("startPixmap", m_svg->pixmap("notification-active"));
-+
-+
-+    m_fadeGroup = new QSequentialAnimationGroup(this);
-+    m_fadeGroup->addAnimation(m_fadeInAnimation);
-+    m_fadeGroup->addAnimation(m_fadeOutAnimation);
-+
-+    connect(manager, SIGNAL(notificationAdded(Notification*)),
-+            this, SLOT(updateTask()));
-+    connect(manager, SIGNAL(notificationRemoved(Notification*)),
-+            this, SLOT(updateTask()));
-+    connect(manager, SIGNAL(notificationChanged(Notification*)),
-+            this, SLOT(updateTask()));
-+    connect(manager, SIGNAL(notificationExpired(Notification*)),
-+            this, SLOT(updateTask()));
-+    connect(manager, SIGNAL(jobAdded(Job*)),
-+            this, SLOT(updateTask()));
-+    connect(manager, SIGNAL(jobRemoved(Job*)),
-+            this, SLOT(updateTask()));
-+    connect(manager, SIGNAL(jobStateChanged(Job*)),
-+            this, SLOT(updateTask()));
-+
-+    Plasma::Extender *extender = qobject_cast<Plasma::Extender *>(m_systray->graphicsWidget());
-+    if (extender) {
-+        connect(extender, SIGNAL(itemDetached(Plasma::ExtenderItem*)),
-+                this, SLOT(updateTask()));
-+    }
-+
-+    Plasma::ToolTipManager::self()->registerWidget(this);
-+    updateTask();
-+}
-+
-+void BusyWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
-+{
-+    QRectF iconRect(0, 0, qMin(size().width(), size().height()), qMin(size().width(), size().height()));
-+    iconRect.moveCenter(boundingRect().center());
-+
-+    if (m_state == Running) {
-+        const int arcStart = 90*16;
-+        const int arcEnd = -(360*(qreal)m_manager->jobTotals()->percentage()/100)*16;
-+
-+        Plasma::BusyWidget::paint(painter, option, widget);
-+
-+        //kDebug() << arcStart << arcEnd;
-+
-+        QPixmap activePixmap(iconRect.size().toSize());
-+        activePixmap.fill(Qt::transparent);
-+        QPixmap inActivePixmap(iconRect.size().toSize());
-+        inActivePixmap.fill(Qt::transparent);
-+        QRect pieRect(QPoint(0, 0), activePixmap.size()*2);
-+        pieRect.moveCenter(activePixmap.rect().center());
-+
-+        QPainter p(&activePixmap);
-+        p.setPen(Qt::NoPen);
-+        p.setBrush(Qt::black);
-+        p.setCompositionMode(QPainter::CompositionMode_Source);
-+        p.drawPie(pieRect, arcStart, arcEnd);
-+        p.setCompositionMode(QPainter::CompositionMode_SourceIn);
-+        m_svg->paint(&p, QRectF(QPointF(0, 0), iconRect.size()), "notification-progress-active");
-+        p.end();
-+
-+        p.begin(&inActivePixmap);
-+        p.setPen(Qt::NoPen);
-+        p.setBrush(Qt::black);
-+        p.setCompositionMode(QPainter::CompositionMode_Source);
-+        p.drawPie(pieRect, arcStart, (360*16)+arcEnd);
-+        p.setCompositionMode(QPainter::CompositionMode_SourceIn);
-+        m_svg->paint(&p, QRectF(QPointF(0, 0), iconRect.size()), "notification-progress-inactive");
-+        p.end();
-+
-+        painter->drawPixmap(iconRect.topLeft().toPoint(), activePixmap);
-+        painter->drawPixmap(iconRect.topLeft().toPoint(), inActivePixmap);
-+
-+        Plasma::BusyWidget::paint(painter, option, widget);
-+
-+    } else if (m_state == Empty && m_manager->notifications().count() > 0) {
-+        m_svg->paint(painter, iconRect, "notification-inactive");
-+    } else if (m_state == Empty && m_manager->notifications().count() == 0) {
-+        m_svg->paint(painter, iconRect, "notification-disabled");
-+    } else {
-+        // m_state ==  Info
-+        m_svg->paint(painter, iconRect, "notification-empty");
-+        QFont font(KGlobalSettings::smallestReadableFont());
-+        painter->setFont(font);
-+        QRectF r = rect();
-+
-+        painter->setPen(Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor));
-+
-+        const QFontMetrics fm(font);
-+        const QSize textSize = fm.boundingRect(label()).size();
-+        const bool textFits = textSize.width() <= r.width() && textSize.height() <= r.height();
-+        if (m_svg && m_svg->hasElement(expanderElement())) {
-+            QSizeF arrowSize(m_svg->elementSize(expanderElement()));
-+            QRectF arrowRect(r.center() - QPointF(arrowSize.width() / 2, arrowSize.height() + fm.xHeight() / 2), arrowSize);
-+            m_svg->paint(painter, arrowRect, expanderElement());
-+
-+            r.setTop(arrowRect.bottom());
-+
-+            if (textFits) {
-+                painter->drawText(r, Qt::AlignHCenter|Qt::AlignTop, label());
-+            }
-+        } else if (textFits) {
-+            painter->drawText(r, Qt::AlignCenter, label());
-+        }
-+    }
-+
-+    if (m_fadeInAnimation->state() == QAbstractAnimation::Running) {
-+        QPixmap pix = m_fadeInAnimation->property("currentPixmap").value<QPixmap>();
-+        painter->drawPixmap(iconRect, pix, pix.rect());
-+    } else if (m_fadeOutAnimation->state() == QAbstractAnimation::Running) {
-+        QPixmap pix = m_fadeOutAnimation->property("currentPixmap").value<QPixmap>();
-+        painter->drawPixmap(iconRect, pix, pix.rect());
-+    }
-+}
-+
-+void BusyWidget::resizeEvent(QGraphicsSceneResizeEvent *)
-+{
-+    //regenerate pixmaps
-+    m_svg->resize(contentsRect().size());
-+    m_fadeInAnimation->setProperty("targetPixmap", m_svg->pixmap("notification-active"));
-+    m_fadeOutAnimation->setProperty("startPixmap", m_svg->pixmap("notification-active"));
-+    m_svg->resize();
-+}
-+
-+void BusyWidget::setState(State state)
-+{
-+    if (m_state == state) {
-+        return;
-+    }
-+
-+    m_state = state;
-+    setRunning(m_state == Running);
-+    update();
-+}
-+
-+QString BusyWidget::expanderElement() const
-+{
-+    switch (m_systray->location()) {
-+        case Plasma::TopEdge:
-+            return "expander-top";
-+        case Plasma::RightEdge:
-+            return "expander-right";
-+        case Plasma::LeftEdge:
-+            return "expander-left";
-+        case Plasma::BottomEdge:
-+        default:
-+            return "expander-bottom";
-+    }
-+}
-+
-+void BusyWidget::getJobCounts(int &runningJobs, int &pausedJobs, int &completedJobs, int &jobSpeed)
-+{
-+    runningJobs = pausedJobs = completedJobs = jobSpeed = 0;
-+    foreach (const Job *job, m_manager->jobs()) {
-+        switch (job->state()) {
-+            case Job::Running:
-+                jobSpeed += job->numericSpeed();
-+                ++runningJobs;
-+                break;
-+            case Job::Suspended:
-+                ++pausedJobs;
-+                break;
-+            default:
-+                break;
-+        }
-+    }
-+
-+}
-+
-+void BusyWidget::updateTask()
-+{
-+    int runningJobs, pausedJobs, completedJobs, jobSpeed;
-+    getJobCounts(runningJobs, pausedJobs, completedJobs, jobSpeed);
-+
-+    int total = m_manager->jobs().count();
-+    int activeNotifications = 0;
-+    bool hasOldNotifications = false;
-+
-+    foreach (Notification *notification, m_manager->notifications()) {
-+        if (qobject_cast<CompletedJobNotification *>(notification)) {
-+            ++completedJobs;
-+        } else if (notification->isExpired()) {
-+            hasOldNotifications = true;
-+        } else {
-+            ++activeNotifications;
-+        }
-+    }
-+
-+    total += completedJobs + activeNotifications;
-+
-+    if (total + m_manager->notifications().count() < 0) {
-+        m_systray->hidePopup();
-+    }
-+
-+    if (total > m_total) {
-+        m_fadeGroup->start();
-+    }
-+
-+    m_total = total;
-+
-+    if (activeNotifications > 0) {
-+        m_systray->setStatus(Plasma::NeedsAttentionStatus);
-+    } else if (m_total > 0 || hasOldNotifications) {
-+        m_systray->setStatus(Plasma::ActiveStatus);
-+    } else {
-+        m_systray->setStatus(Plasma::PassiveStatus);
-+    }
-+
-+    if (!total) {
-+        setState(BusyWidget::Empty);
-+        setLabel(QString());
-+    } else if (runningJobs) {
-+        setState(BusyWidget::Running);
-+        setLabel(QString("%1").arg(QString::number(total)));
-+    } else {
-+        setState(BusyWidget::Info);
-+        setLabel(QString::number(total));
-+    }
-+
-+    if (Plasma::ToolTipManager::self()->isVisible(this)) {
-+        toolTipAboutToShow();
-+    }
-+}
-+
-+void BusyWidget::suppressToolTips(bool suppress)
-+{
-+    m_suppressToolTips = suppress;
-+}
-+
-+void BusyWidget::toolTipAboutToShow()
-+{
-+    if (m_suppressToolTips) {
-+        Plasma::ToolTipManager::self()->setContent(this, Plasma::ToolTipContent());
-+        return;
-+    }
-+
-+    int runningJobs, pausedJobs, completedJobs, jobSpeed;
-+    getJobCounts(runningJobs, pausedJobs, completedJobs, jobSpeed);
-+
-+    //make a nice plasma tooltip
-+    QString tooltipContent;
-+    if (runningJobs > 0) {
-+        tooltipContent += i18ncp("Number of jobs and the speed at which they are downloading",
-+                                 "%1 running job (%2/s)", "%1 running jobs (%2/s)", runningJobs,
-+                                 KGlobal::locale()->formatByteSize(jobSpeed));
-+        if (pausedJobs > 0 || completedJobs > 0 || !m_manager->notifications().isEmpty()) {
-+            tooltipContent += "<br>";
-+        }
-+    }
-+
-+    if (pausedJobs > 0) {
-+        tooltipContent += i18np("%1 suspended job", "%1 suspended jobs", pausedJobs);
-+        if (completedJobs > 0 || !m_manager->notifications().isEmpty()) {
-+            tooltipContent += "<br>";
-+        }
-+    }
-+
-+    if (completedJobs > 0) {
-+        tooltipContent += i18np("%1 completed job", "%1 completed jobs", completedJobs);
-+        if (!m_manager->notifications().isEmpty()) {
-+            tooltipContent += "<br>";
-+        }
-+    }
-+
-+    if (!m_manager->notifications().isEmpty()) {
-+        tooltipContent += i18np("%1 notification", "%1 notifications",
-+                                m_manager->notifications().count());
-+    }
-+
-+    if (tooltipContent.isEmpty()) {
-+        tooltipContent = i18n("No active jobs or notifications");
-+    }
-+
-+    Plasma::ToolTipContent data(i18n("Notifications and jobs"),
-+                                tooltipContent,
-+                                KIcon("help-about"));
-+    Plasma::ToolTipManager::self()->setContent(this, data);
-+}
-+
-+
-+#include "busywidget.moc"
-diff --git a/plasma/generic/applets/notifications/ui/busywidget.h b/plasma/generic/applets/notifications/ui/busywidget.h
-new file mode 100644
-index 0000000..ae5f994
---- /dev/null
-+++ b/plasma/generic/applets/notifications/ui/busywidget.h
-@@ -0,0 +1,80 @@
-+/***************************************************************************
-+ *   Copyright (C) 2008 Rob Scheepmaker <r.scheepmaker@student.utwente.nl> *
-+ *   Copyright (C) 2010 Marco Martin <notmart@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 NOTIFICATIONBUSYWIDGET_H
-+#define NOTIFICATIONBUSYWIDGET_H
-+
-+#include <KIcon>
-+
-+#include <Plasma/BusyWidget>
-+
-+class QStyleOptionGraphicsItem;
-+class QSequentialAnimationGroup;
-+
-+namespace Plasma
-+{
-+    class Animation;
-+    class Extender;
-+    class PopupApplet;
-+    class Svg;
-+}
-+
-+
-+class Manager;
-+
-+class BusyWidget : public Plasma::BusyWidget
-+{
-+    Q_OBJECT
-+
-+public:
-+    enum State { Empty, Info, Running };
-+
-+    BusyWidget(Plasma::PopupApplet *parent, const Manager *manager);
-+    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0);
-+    void setState(State state);
-+    void suppressToolTips(bool suppress);
-+
-+public slots:
-+    void toolTipAboutToShow();
-+
-+protected:
-+    void resizeEvent(QGraphicsSceneResizeEvent *event);
-+
-+protected slots:
-+    void updateTask();
-+
-+private:
-+    QString expanderElement() const;
-+    void getJobCounts(int &runningJobs, int &pausedJobs, int &completedJobs, int &jobSpeed);
-+
-+    KIcon m_icon;
-+    State m_state;
-+    Plasma::Svg *m_svg;
-+    Plasma::PopupApplet *m_systray;
-+    const Manager *m_manager;
-+    Plasma::Animation *m_fadeInAnimation;
-+    Plasma::Animation *m_fadeOutAnimation;
-+    QSequentialAnimationGroup *m_fadeGroup;
-+    int m_total;
-+    bool m_suppressToolTips;
-+};
-+
-+
-+#endif
-diff --git a/plasma/generic/applets/notifications/ui/jobtotalswidget.cpp b/plasma/generic/applets/notifications/ui/jobtotalswidget.cpp
-new file mode 100644
-index 0000000..6552ed3
---- /dev/null
-+++ b/plasma/generic/applets/notifications/ui/jobtotalswidget.cpp
-@@ -0,0 +1,94 @@
-+/***************************************************************************
-+ *   Copyright 2009 by Rob Scheepmaker <r.scheepmaker@student.utwente.nl>  *
-+ *                                                                         *
-+ *   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 "jobtotalswidget.h"
-+#include "../core/job.h"
-+
-+#include <Plasma/ExtenderItem>
-+#include <Plasma/Meter>
-+
-+static const int UPDATE_TIMER_INTERVAL = 200;
-+
-+
-+JobTotalsWidget::JobTotalsWidget(Job *job, QGraphicsWidget *parent)
-+    : Meter(parent),
-+      m_job(job),
-+      m_updateTimerId(0)
-+{
-+    m_extenderGroup = qobject_cast<Plasma::ExtenderGroup *>(parent),
-+
-+    setSvg("widgets/bar_meter_horizontal");
-+    setMeterType(Plasma::Meter::BarMeterHorizontal);
-+
-+    setMinimumWidth(350);
-+    setMinimumHeight(16);
-+    setMaximumHeight(16);
-+    setMaximum(100);
-+    setValue(0);
-+
-+    if (m_job) {
-+        connect(m_job, SIGNAL(changed(Job*)),
-+                this, SLOT(scheduleJobUpdate()));
-+
-+        updateJob();
-+    }
-+}
-+
-+JobTotalsWidget::~JobTotalsWidget()
-+{
-+}
-+
-+void JobTotalsWidget::scheduleJobUpdate()
-+{
-+    if (!m_updateTimerId) {
-+        m_updateTimerId = startTimer(UPDATE_TIMER_INTERVAL);
-+    }
-+}
-+
-+void JobTotalsWidget::timerEvent(QTimerEvent *event)
-+{
-+    if (event->timerId() == m_updateTimerId) {
-+        killTimer(m_updateTimerId);
-+        m_updateTimerId = 0;
-+        updateJob();
-+    } else {
-+        Meter::timerEvent(event);
-+    }
-+}
-+
-+void JobTotalsWidget::updateJob()
-+{
-+    setValue(m_job->percentage());
-+
-+    if (m_extenderGroup) {
-+        if (m_extenderGroup->items().count() > 1 || m_extenderGroup->isGroupCollapsed()) {
-+            m_extenderGroup->setTitle(m_job->message());
-+        } else {
-+            m_extenderGroup->setTitle(i18nc("Generic title for the job transfer popup", "Jobs"));
-+        }
-+        m_extenderGroup->setIcon(m_job->applicationIconName());
-+    } else {
-+        setLabelAlignment(0, Qt::AlignLeft|Qt::AlignVCenter);
-+        setLabel(0, m_job->message());
-+    }
-+}
-+
-+
-+#include "jobtotalswidget.moc"
-+
-diff --git a/plasma/generic/applets/notifications/ui/jobtotalswidget.h b/plasma/generic/applets/notifications/ui/jobtotalswidget.h
-new file mode 100644
-index 0000000..4f07c86
---- /dev/null
-+++ b/plasma/generic/applets/notifications/ui/jobtotalswidget.h
-@@ -0,0 +1,65 @@
-+/***************************************************************************
-+ *   Copyright 2009 by Rob Scheepmaker <r.scheepmaker@student.utwente.nl   *
-+ *                                                                         *
-+ *   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 JOBTOTALSWIDGET_H
-+#define JOBTOTALSWIDGET_H
-+
-+#include "../core/job.h"
-+
-+
-+#include <QGraphicsWidget>
-+
-+#include <plasma/widgets/meter.h>
-+#include <Plasma/Service>
-+#include <Plasma/ExtenderGroup>
-+#include <plasma/dataengine.h>
-+
-+namespace Plasma
-+{
-+    class ExtenderItem;
-+    class Meter;
-+} // namespace Plasma
-+
-+
-+class Job;
-+
-+class JobTotalsWidget : public Plasma::Meter
-+{
-+    Q_OBJECT
-+
-+    public:
-+        explicit JobTotalsWidget(Job *job, QGraphicsWidget *parent);
-+        ~JobTotalsWidget();
-+
-+    protected:
-+        void timerEvent(QTimerEvent *event);
-+
-+    private Q_SLOTS:
-+        void scheduleJobUpdate();
-+
-+    private:
-+        void updateJob();
-+
-+        Plasma::ExtenderGroup *m_extenderGroup;
-+        Job *m_job;
-+        int m_updateTimerId;
-+};
-+
-+
-+#endif
-diff --git a/plasma/generic/applets/notifications/ui/jobwidget.cpp b/plasma/generic/applets/notifications/ui/jobwidget.cpp
-new file mode 100644
-index 0000000..06096fd
---- /dev/null
-+++ b/plasma/generic/applets/notifications/ui/jobwidget.cpp
-@@ -0,0 +1,435 @@
-+/***************************************************************************
-+ *   Copyright 2008 by Rob Scheepmaker <r.scheepmaker@student.utwente.nl>  *
-+ *                                                                         *
-+ *   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 "jobwidget.h"
-+#include "../core/job.h"
-+
-+
-+#include <QFont>
-+#include <QAction>
-+#include <QGraphicsGridLayout>
-+#include <QLabel>
-+
-+#include <KIconLoader>
-+
-+#include <Plasma/DataEngine>
-+#include <Plasma/Extender>
-+#include <Plasma/ExtenderItem>
-+#include <Plasma/Label>
-+#include <Plasma/Meter>
-+#include <Plasma/PopupApplet>
-+#include <Plasma/PushButton>
-+#include <Plasma/Service>
-+#include <Plasma/SignalPlotter>
-+#include <Plasma/IconWidget>
-+#include <Plasma/Theme>
-+#include <Plasma/ToolTipManager>
-+
-+static const int UPDATE_INTERVAL = 200;
-+
-+JobWidget::JobWidget(Job *job, Plasma::ExtenderItem *parent)
-+    : QGraphicsWidget(parent),
-+      m_extenderItem(parent),
-+      m_job(job),
-+      m_updateTimerId(0),
-+      m_extenderItemDestroyed(false)
-+{
-+    Q_ASSERT(m_extenderItem);
-+
-+    m_meter = new Plasma::Meter(this);
-+    m_meter->setSvg("widgets/bar_meter_horizontal");
-+    m_meter->setMeterType(Plasma::Meter::BarMeterHorizontal);
-+    m_meter->setMaximumHeight(16);
-+    m_meter->setMaximum(100);
-+    m_meter->setValue(0);
-+
-+    m_plotter = new Plasma::SignalPlotter(this);
-+    m_plotter->setUseAutoRange(true);
-+    m_plotter->setShowVerticalLines(false);
-+    m_plotter->setUnit(i18n("KiB/s"));
-+    m_plotter->addPlot(Plasma::Theme::defaultTheme()->color(Plasma::Theme::HighlightColor));
-+
-+    m_fromNameLabel = new Plasma::Label(this);
-+    m_fromLabel = new Plasma::Label(this);
-+    m_toNameLabel = new Plasma::Label(this);
-+    m_toLabel = new Plasma::Label(this);
-+    m_totalBytesLabel = new Plasma::Label(this);
-+    m_dirCountLabel = new Plasma::Label(this);
-+    m_fileCountLabel = new Plasma::Label(this);
-+    m_eta = new Plasma::Label(this);
-+    m_details = new Plasma::IconWidget(this);
-+    m_details->setSvg("widgets/action-overlays", "add-normal");
-+    m_details->setMaximumSize(KIconLoader::SizeSmallMedium, KIconLoader::SizeSmallMedium);
-+    m_details->setMinimumSize(KIconLoader::SizeSmallMedium, KIconLoader::SizeSmallMedium);
-+
-+    m_totalBytesLabel->setVisible(false);
-+    m_dirCountLabel->setVisible(false);
-+    m_fileCountLabel->setVisible(false);
-+    m_plotter->setVisible(false);
-+
-+    m_fromNameLabel->setAlignment(Qt::AlignRight);
-+    m_fromLabel->setAlignment(Qt::AlignLeft);
-+    m_toNameLabel->setAlignment(Qt::AlignRight);
-+    m_toLabel->setAlignment(Qt::AlignLeft);
-+    m_totalBytesLabel->setAlignment(Qt::AlignRight);
-+    m_dirCountLabel->setAlignment(Qt::AlignRight);
-+    m_fileCountLabel->setAlignment(Qt::AlignRight);
-+    m_eta->setAlignment(Qt::AlignRight);
-+
-+    m_fromLabel->nativeWidget()->setWordWrap(false);
-+    m_toLabel->nativeWidget()->setWordWrap(false);
-+    m_dirCountLabel->nativeWidget()->setWordWrap(false);
-+    m_fileCountLabel->nativeWidget()->setWordWrap(false);
-+    m_totalBytesLabel->nativeWidget()->setWordWrap(false);
-+    m_eta->nativeWidget()->setWordWrap(false);
-+
-+    m_layout = new QGraphicsGridLayout(this);
-+    m_layout->addItem(m_fromNameLabel, 0, 0);
-+    m_layout->addItem(m_fromLabel, 0, 1);
-+    m_layout->addItem(m_toNameLabel, 1, 0);
-+    m_layout->addItem(m_toLabel, 1, 1);
-+    m_layout->addItem(m_eta, 2, 1);
-+    m_layout->addItem(m_details, 3, 0, Qt::AlignVCenter|Qt::AlignRight);
-+    m_layout->addItem(m_meter, 3, 1, Qt::AlignCenter);
-+
-+    setMinimumWidth(350);
-+
-+    if (m_job.data()) {
-+        m_details->setToolTip(i18n("More"));
-+        m_details->setSvg("widgets/action-overlays", "add-normal");
-+
-+        connect(m_job.data(), SIGNAL(stateChanged(Job*)), this, SLOT(updateJobState()));
-+        connect(m_job.data(), SIGNAL(destroyed(Job*)), this, SLOT(destroyExtenderItem()));
-+        connect(m_details, SIGNAL(clicked()), this, SLOT(detailsClicked()));
-+
-+        //the suspend action
-+        QAction *suspendAction = new QAction(m_extenderItem);
-+        suspendAction->setIcon(KIcon("media-playback-pause"));
-+        suspendAction->setEnabled(true);
-+        suspendAction->setVisible(false);
-+        suspendAction->setToolTip(i18n("Pause job"));
-+        m_extenderItem->addAction("suspend", suspendAction);
-+        connect(suspendAction, SIGNAL(triggered()), m_job.data(), SLOT(suspend()));
-+
-+        //the resume action
-+        QAction *resumeAction = new QAction(m_extenderItem);
-+        resumeAction->setIcon(KIcon("media-playback-start"));
-+        resumeAction->setEnabled(true);
-+        resumeAction->setVisible(false);
-+        resumeAction->setToolTip(i18n("Resume job"));
-+        m_extenderItem->addAction("resume", resumeAction);
-+        connect(resumeAction, SIGNAL(triggered()), m_job.data(), SLOT(resume()));
-+
-+        //the friendly stop action
-+        QAction *stopAction = new QAction(m_extenderItem);
-+        stopAction->setIcon(KIcon("media-playback-stop"));
-+        stopAction->setEnabled(true);
-+        stopAction->setVisible(true);
-+        stopAction->setToolTip(i18n("Cancel job"));
-+        m_extenderItem->addAction("stop", stopAction);
-+        connect(stopAction, SIGNAL(triggered()), m_job.data(), SLOT(stop()));
-+
-+        updateJob();
-+        updateJobState();  // make sure to set the title
-+    } else {
-+        m_extenderItem->showCloseButton();
-+
-+        labelName0 = m_extenderItem->config().readEntry("labelName0", "");
-+        label0= m_extenderItem->config().readEntry("label0", "");
-+        labelName1 = m_extenderItem->config().readEntry("labelName1", "");
-+        label1 = m_extenderItem->config().readEntry("label1", "");
-+
-+        updateLabels();
-+    }
-+}
-+
-+JobWidget::~JobWidget()
-+{
-+}
-+
-+void JobWidget::destroyExtenderItem()
-+{
-+    m_extenderItem->destroy();
-+    m_extenderItemDestroyed = true;
-+}
-+
-+void JobWidget::scheduleUpdateJob()
-+{
-+    if (m_extenderItemDestroyed) {
-+        return;
-+    }
-+
-+    if (!m_updateTimerId) {
-+        m_updateTimerId = startTimer(UPDATE_INTERVAL);
-+    }
-+}
-+
-+void JobWidget::updateJobState()
-+{
-+    if (m_extenderItemDestroyed && m_job.data()) {
-+        return;
-+    }
-+
-+    //show the current status in the title.
-+    if (!m_job.data()->error().isEmpty()) {
-+        m_extenderItem->setTitle(m_job.data()->error());
-+    } else if (m_job.data()->state() == Job::Running) {
-+        m_extenderItem->setTitle(m_job.data()->message());
-+        if (m_job.data()->eta()) {
-+            m_eta->setText(i18n("%1 (%2 remaining)", m_job.data()->speed(),
-+                                 KGlobal::locale()->prettyFormatDuration(m_job.data()->eta())));
-+        } else {
-+            m_eta->setText(QString());
-+        }
-+    } else if (m_job.data()->state() == Job::Suspended) {
-+        m_extenderItem->setTitle(
-+            i18nc("%1 is the name of the job, can be things like Copying, deleting, moving",
-+                  "%1 [Paused]", m_job.data()->message()));
-+        m_eta->setText(i18n("Paused"));
-+    } else {
-+        m_extenderItem->setTitle(
-+            i18nc("%1 is the name of the job, can be things like Copying, deleting, moving",
-+                  "%1 [Finished]", m_job.data()->message()));
-+        m_extenderItem->showCloseButton();
-+    }
-+}
-+
-+void JobWidget::updateJob()
-+{
-+    if (m_extenderItemDestroyed || !m_job.data()) {
-+        return;
-+    }
-+
-+    m_meter->setValue(m_job.data()->percentage());
-+
-+    //Update the ETA and job speed (only if running)
-+    if (m_job.data()->state() == Job::Running) {
-+        if (m_job.data()->eta()) {
-+            m_eta->setText(i18n("%1 (%2 remaining)", m_job.data()->speed(),
-+                                 KGlobal::locale()->prettyFormatDuration(m_job.data()->eta())));
-+        } else {
-+            m_eta->setText(QString());
-+        }
-+    }
-+
-+    if (m_job.data()->labels().count() > 0) {
-+        labelName0 = m_job.data()->labels().value(0).first;
-+        label0 = m_job.data()->labels().value(0).second;
-+    }
-+    if (m_job.data()->labels().count() > 1) {
-+        labelName1 = m_job.data()->labels().value(1).first;
-+        label1 = m_job.data()->labels().value(1).second;
-+    }
-+
-+    //TODO: can we write this at some later point?
-+    KConfigGroup cg = m_extenderItem->config();
-+    cg.writeEntry("labelName0", labelName0);
-+    cg.writeEntry("label0", label0);
-+    cg.writeEntry("labelName1", labelName1);
-+    cg.writeEntry("label1", label1);
-+
-+    updateLabels();
-+
-+    //set the correct actions to visible.
-+    if (m_extenderItem->action("suspend")) {
-+        m_extenderItem->action("suspend")->setVisible(m_job.data()->isSuspendable() &&
-+                                            m_job.data()->state() == Job::Running);
-+    }
-+
-+    if (m_extenderItem->action("resume")) {
-+        m_extenderItem->action("resume")->setVisible(m_job.data()->isSuspendable() &&
-+                                           m_job.data()->state() == Job::Suspended);
-+    }
-+
-+    if (m_extenderItem->action("stop")) {
-+        m_extenderItem->action("stop")->setVisible(m_job.data()->isKillable() &&
-+                                         m_job.data()->state() != Job::Stopped);
-+    }
-+
-+    QMap<QString, qlonglong> processed = m_job.data()->processedAmounts();
-+    QMap<QString, qlonglong> totals = m_job.data()->totalAmounts();
-+
-+    qlonglong dirs = totals.value("dirs");
-+    if (dirs > 1) {
-+        m_dirCountLabel->setText(i18np("%2 / 1 folder", "%2 / %1 folders", dirs, processed["dirs"]));
-+        m_dirCountLabel->setMaximumHeight(INT_MAX);
-+    } else {
-+        m_dirCountLabel->setMaximumHeight(0);
-+    }
-+
-+    qlonglong files = totals.value("files");
-+    if (files > 1) {
-+        m_fileCountLabel->setText(i18np("%2 / 1 file", "%2 / %1 files", files, processed["files"]));
-+        m_fileCountLabel->setMaximumHeight(INT_MAX);
-+    } else {
-+        m_fileCountLabel->setMaximumHeight(0);
-+    }
-+
-+    QList<double> sample;
-+    sample << m_job.data()->numericSpeed()/1000;
-+    m_plotter->addSample(sample);
-+
-+    qlonglong total = totals["bytes"];
-+    if (total > 0) {
-+        QString processedString = KGlobal::locale()->formatByteSize(processed["bytes"]);
-+        QString totalsString = KGlobal::locale()->formatByteSize(total);
-+        m_totalBytesLabel->setText(QString("%1 / %2").arg(processedString, totalsString));
-+    } else {
-+        m_details->hide();
-+        m_totalBytesLabel->hide();
-+    }
-+
-+    if (m_totalBytesLabel->text().isEmpty() &&
-+        m_dirCountLabel->text().isEmpty() &&
-+        m_fileCountLabel->text().isEmpty()) {
-+        m_details->hide();
-+    } else {
-+        m_details->show();
-+    }
-+
-+    m_extenderItem->setIcon(m_job.data()->applicationIconName());
-+}
-+
-+void JobWidget::showEvent(QShowEvent *)
-+{
-+    if (!m_job.data()) {
-+        return;
-+    }
-+
-+    Plasma::PopupApplet *applet = qobject_cast<Plasma::PopupApplet *>(m_extenderItem->extender()->applet());
-+    if (applet && applet->isPopupShowing()) {
-+        updateJob();
-+        disconnect(m_job.data(), SIGNAL(changed(Job*)), this, SLOT(scheduleUpdateJob()));
-+        connect(m_job.data(), SIGNAL(changed(Job*)), this, SLOT(scheduleUpdateJob()));
-+        return;
-+    }
-+}
-+
-+void JobWidget::hideEvent(QHideEvent *)
-+{
-+    if (!m_job.data()) {
-+        return;
-+    }
-+
-+    disconnect(m_job.data(), SIGNAL(changed(Job*)), this, SLOT(scheduleUpdateJob()));
-+}
-+
-+void JobWidget::poppedUp(bool shown)
-+{
-+    if (!m_job.data()) {
-+        return;
-+    }
-+
-+    disconnect(m_job.data(), SIGNAL(changed(Job*)), this, SLOT(scheduleUpdateJob()));
-+
-+    if (shown && isVisible()) {
-+        updateJob();
-+        connect(m_job.data(), SIGNAL(changed(Job*)), this, SLOT(scheduleUpdateJob()));
-+        return;
-+    }
-+}
-+
-+Job *JobWidget::job() const
-+{
-+    return m_job.data();
-+}
-+
-+void JobWidget::resizeEvent(QGraphicsSceneResizeEvent *event)
-+{
-+    Q_UNUSED(event)
-+    updateLabels();
-+}
-+
-+void JobWidget::timerEvent(QTimerEvent *event)
-+{
-+    if (event->timerId() == m_updateTimerId) {
-+        killTimer(m_updateTimerId);
-+        m_updateTimerId = 0;
-+        updateJob();
-+    }
-+}
-+
-+void JobWidget::updateLabels()
-+{
-+    QFontMetricsF fm = m_fromLabel->nativeWidget()->fontMetrics();
-+    if (!labelName0.isEmpty()) {
-+        m_fromNameLabel->setText(QString("%1: ").arg(labelName0));
-+    }
-+    if (label0.startsWith(QLatin1String("file://"))) {
-+        label0 = KUrl(label0).toLocalFile();
-+    }
-+
-+    const QString shortLabel0(fm.elidedText(label0, Qt::ElideMiddle, m_fromLabel->size().width()));
-+    m_fromLabel->setText(shortLabel0);
-+
-+
-+    Plasma::ToolTipContent data;
-+
-+    if (label0.length() > shortLabel0.length()) {
-+        data.setSubText(label0);
-+        Plasma::ToolTipManager::self()->setContent(m_fromLabel, data);
-+    }
-+
-+    if (!labelName1.isEmpty()) {
-+        m_toNameLabel->setText(QString("%1: ").arg(labelName1));
-+    }
-+    if (label1.startsWith(QLatin1String("file://"))) {
-+        label1 = KUrl(label1).toLocalFile();
-+    }
-+
-+    const QString shortLabel1(fm.elidedText(label1, Qt::ElideMiddle, m_toLabel->size().width()));
-+    m_toLabel->setText(shortLabel1);
-+
-+    if (label1.length() > shortLabel1.length()) {
-+        data.setSubText(label1);
-+        Plasma::ToolTipManager::self()->setContent(m_toLabel, data);
-+    }
-+}
-+
-+void JobWidget::detailsClicked()
-+{
-+    if (!m_totalBytesLabel->isVisible()) {
-+        m_details->setToolTip(i18n("Less"));
-+        m_details->setSvg("widgets/action-overlays", "remove-normal");
-+        m_totalBytesLabel->setVisible(true);
-+        m_dirCountLabel->setVisible(true);
-+        m_fileCountLabel->setVisible(true);
-+        m_plotter->setVisible(true);
-+        m_layout->addItem(m_totalBytesLabel, 4, 1);
-+        m_layout->addItem(m_fileCountLabel, 5, 1);
-+        m_layout->addItem(m_dirCountLabel, 6, 1);
-+        m_layout->addItem(m_plotter, 7, 1);
-+        m_extenderItem->setCollapsed(m_extenderItem->isCollapsed());
-+    } else {
-+        m_details->setToolTip(i18n("More"));
-+        m_details->setSvg("widgets/action-overlays", "add-normal");
-+        m_totalBytesLabel->setVisible(false);
-+        m_dirCountLabel->setVisible(false);
-+        m_fileCountLabel->setVisible(false);
-+        m_plotter->setVisible(false);
-+        for (int i = 0; i < 4; i++) {
-+            m_layout->removeAt(m_layout->count() - 1);
-+        }
-+        m_layout->updateGeometry();
-+        m_extenderItem->setCollapsed(m_extenderItem->isCollapsed());
-+    }
-+}
-+
-+#include "jobwidget.moc"
-+
-diff --git a/plasma/generic/applets/notifications/ui/jobwidget.h b/plasma/generic/applets/notifications/ui/jobwidget.h
-new file mode 100644
-index 0000000..b949bac
---- /dev/null
-+++ b/plasma/generic/applets/notifications/ui/jobwidget.h
-@@ -0,0 +1,102 @@
-+/***************************************************************************
-+ *   Copyright 2008 by Rob Scheepmaker <r.scheepmaker@student.utwente.nl   *
-+ *                                                                         *
-+ *   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 JOBWIDGET_H
-+#define JOBWIDGET_H
-+
-+#include "../core/job.h"
-+
-+
-+#include <QGraphicsWidget>
-+#include <QGraphicsGridLayout>
-+
-+#include <Plasma/Service>
-+#include <Plasma/ExtenderItem>
-+#include <plasma/dataengine.h>
-+#include <Plasma/PushButton>
-+
-+namespace Plasma
-+{
-+    class ExtenderItem;
-+    class PushButton;
-+    class Label;
-+    class Meter;
-+    class IconWidget;
-+    class SignalPlotter;
-+} // namespace Plasma
-+
-+class Job;
-+
-+
-+class JobWidget : public QGraphicsWidget
-+{
-+    Q_OBJECT
-+
-+    public:
-+        explicit JobWidget(Job *job, Plasma::ExtenderItem *parent);
-+        ~JobWidget();
-+
-+        void poppedUp(bool shown);
-+
-+        Job *job() const;
-+
-+    protected:
-+        void resizeEvent(QGraphicsSceneResizeEvent *event);
-+        void timerEvent(QTimerEvent *event);
-+        void showEvent(QShowEvent *event);
-+        void hideEvent(QHideEvent *event);
-+
-+    private Q_SLOTS:
-+        void detailsClicked();
-+        void destroyExtenderItem();
-+        void scheduleUpdateJob();
-+        void updateJobState();
-+
-+    private:
-+        void updateLabels();
-+        void updateJob();
-+
-+        Plasma::ExtenderItem *m_extenderItem;
-+        QWeakPointer<Job>m_job;
-+
-+        Plasma::Meter *m_meter;
-+        Plasma::Label *m_fromNameLabel;
-+        Plasma::Label *m_fromLabel;
-+        Plasma::Label *m_toNameLabel;
-+        Plasma::Label *m_toLabel;
-+        Plasma::Label *m_totalBytesLabel;
-+        Plasma::Label *m_dirCountLabel;
-+        Plasma::Label *m_fileCountLabel;
-+        Plasma::Label *m_eta;
-+        Plasma::IconWidget *m_details;
-+        Plasma::SignalPlotter *m_plotter;
-+
-+        QGraphicsGridLayout *m_layout;
-+
-+        QString labelName0;
-+        QString labelName1;
-+        QString label0;
-+        QString label1;
-+
-+        int m_updateTimerId;
-+
-+        bool m_extenderItemDestroyed;
-+};
-+
-+#endif
-diff --git a/plasma/generic/applets/notifications/ui/notificationgroup.cpp b/plasma/generic/applets/notifications/ui/notificationgroup.cpp
-new file mode 100644
-index 0000000..f27e2c3
---- /dev/null
-+++ b/plasma/generic/applets/notifications/ui/notificationgroup.cpp
-@@ -0,0 +1,239 @@
-+/***************************************************************************
-+ *   notificationgroup.cpp                                                *
-+ *   Copyright (C) 2010 Marco Martin <notmart@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 .        *
-+ ***************************************************************************/
-+
-+#include "notificationgroup.h"
-+#include "../core/notification.h"
-+#include "notificationwidget.h"
-+
-+#include <QGraphicsLinearLayout>
-+#include <QWidget>
-+
-+#include <KDebug>
-+#include <KIcon>
-+#include <KLocale>
-+
-+#include <Plasma/TabBar>
-+#include <Plasma/ExtenderItem>
-+
-+
-+NotificationGroup::NotificationGroup(Plasma::Extender *parent, uint groupId)
-+   : Plasma::ExtenderGroup(parent, groupId)
-+{
-+    setTransient(true);
-+    config().writeEntry("type", "notification");
-+    setName("notifications");
-+    setTitle(i18n("Notifications"));
-+    setIcon("dialog-information");
-+    showCloseButton();
-+
-+
-+    m_notificationBar = new Plasma::TabBar(this);
-+    m_notificationBar->nativeWidget()->setMaximumWidth(400);
-+    m_notificationBar->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
-+    m_notificationBar->addTab(KIcon("dialog-information"), i18nc("Show all  notifications", "All"));
-+    connect(m_notificationBar, SIGNAL(currentChanged(int)), this, SLOT(tabSwitched(int)));
-+
-+
-+    QGraphicsWidget *widget = new QGraphicsWidget(this);
-+    QGraphicsLinearLayout *tabsLayout = new QGraphicsLinearLayout(Qt::Horizontal, widget);
-+    widget->setContentsMargins(0, 4, 0, 0);
-+    tabsLayout->setContentsMargins(0, 0, 0, 0);
-+    tabsLayout->addStretch();
-+    tabsLayout->addItem(m_notificationBar);
-+    tabsLayout->addStretch();
-+
-+    setWidget(widget);
-+    setCollapsed(true);
-+    setAutoCollapse(false);
-+}
-+
-+NotificationGroup::~NotificationGroup()
-+{
-+    m_extenderItemsForNotification.clear();
-+    m_notificationForExtenderItems.clear();
-+    qDeleteAll(m_notifications);
-+}
-+
-+
-+void NotificationGroup::addNotification(Notification *notification)
-+{
-+    connect(notification, SIGNAL(notificationDestroyed(Notification*)), this, SLOT(removeNotification(Notification*)));
-+
-+    NotificationWidget *notificationWidget = new NotificationWidget(notification, this);
-+    notificationWidget->setTitleBarVisible(false);
-+    Plasma::ExtenderItem *extenderItem = new ExtenderItem(extender());
-+    extenderItem->setGroup(this, QPointF(0,0));
-+    extenderItem->setTransient(true);
-+    extenderItem->config().writeEntry("type", "notification");
-+    extenderItem->setWidget(notificationWidget);
-+    extenderItem->setIcon(QIcon());
-+    extenderItem->showCloseButton();
-+    connect(extenderItem, SIGNAL(destroyed(Plasma::ExtenderItem*)), this, SLOT(extenderItemDestroyed(Plasma::ExtenderItem*)));
-+    connect(notificationWidget, SIGNAL(destroyed()), extenderItem, SLOT(deleteLater()));
-+
-+    if (!notification->summary().isEmpty()) {
-+        extenderItem->setTitle(notification->summary());
-+    } else {
-+        extenderItem->setTitle(i18n("Notification from %1", notification->applicationName()));
-+    }
-+
-+    m_extenderItemsForNotification[notification] = extenderItem;
-+    m_notificationForExtenderItems[extenderItem] = notification;
-+    m_notifications.append(notification);
-+    m_notificationsForApp[notification->applicationName()].insert(notification);
-+    m_appForNotification[notification] = notification->applicationName();
-+
-+    if (!m_currentFilter.isNull() && m_currentFilter != notification->applicationName()) {
-+        extenderItem->setMaximumHeight(0);
-+        extenderItem->setVisible(false);
-+    }
-+
-+    //adjust tabbar
-+    bool found = false;
-+    for (int i = 0; i < m_notificationBar->count(); ++i) {
-+        if (m_notificationBar->tabText(i) == notification->applicationName()) {
-+            found = true;
-+            break;
-+        }
-+    }
-+
-+    if (!found) {
-+        m_notificationBar->addTab(notification->applicationIcon(), notification->applicationName());
-+        if (m_notificationBar->count() > 2) {
-+            setCollapsed(false);
-+            setAutoCollapse(true);
-+        }
-+    }
-+
-+    if (items().count() == 1) {
-+        //ensure the notifications group is the last item
-+        Plasma::ExtenderGroup *jobGroup = extender()->group("jobGroup");
-+        if (jobGroup && jobGroup->isVisible()) {
-+            if (extender()->appearance() == Plasma::Extender::TopDownStacked) {
-+                setExtender(extender(), QPointF(0,0));
-+            } else {
-+                setExtender(extender(), jobGroup->geometry().bottomLeft());
-+            }
-+        }
-+    }
-+
-+    notificationWidget->layout()->activate();
-+}
-+
-+void NotificationGroup::extenderItemDestroyed(Plasma::ExtenderItem *object)
-+{
-+    if (m_extenderItemsForNotification.isEmpty()) {
-+        // either we aren't tracking this notification or else we're being deleted
-+        return;
-+    }
-+
-+    Notification *n = m_notificationForExtenderItems.value(object);
-+
-+    if (n) {
-+        m_notificationForExtenderItems.remove(object);
-+        removeNotification(n);
-+        n->deleteLater();
-+    }
-+}
-+
-+void NotificationGroup::removeNotification(Notification *notification)
-+{
-+    if (m_extenderItemsForNotification.isEmpty()) {
-+        // either we aren't tracking this notification or else we're being deleted
-+        return;
-+    }
-+
-+    Plasma::ExtenderItem *item = m_extenderItemsForNotification.value(notification);
-+    if (item) {
-+        m_notificationForExtenderItems.remove(item);
-+    }
-+
-+    m_extenderItemsForNotification.remove(notification);
-+    m_notifications.removeAll(notification);
-+    QString applicationName = m_appForNotification.value(notification);
-+
-+    if (applicationName.isEmpty()) {
-+        return;
-+    }
-+
-+    m_appForNotification.remove(notification);
-+
-+    if (m_notificationsForApp.contains(applicationName)) {
-+        m_notificationsForApp[applicationName].remove(notification);
-+        if (m_notificationsForApp[applicationName].isEmpty()) {
-+            m_notificationsForApp.remove(applicationName);
-+        }
-+    }
-+
-+    //clear tabbar
-+    for (int i = 1; i < m_notificationBar->count(); ++i) {
-+        if (!m_notificationsForApp.contains(m_notificationBar->tabText(i))) {
-+            if (i == m_notificationBar->currentIndex()) {
-+                m_notificationBar->setCurrentIndex(0);
-+            }
-+            m_notificationBar->removeTab(i);
-+            //2 tabs means just "all" and a single application, no need to display it
-+            if (m_notificationBar->count() <= 2) {
-+                setCollapsed(true);
-+                setAutoCollapse(false);
-+            }
-+        }
-+    }
-+
-+    if (m_notifications.count() == 0) {
-+        emit scrollerEmpty();
-+        return;
-+    }
-+}
-+
-+
-+void NotificationGroup::filterNotificationsByOwner(const QString &owner)
-+{
-+    foreach (Notification *notification, m_notifications) {
-+        Plasma::ExtenderItem *item = m_extenderItemsForNotification.value(notification);
-+
-+        if (!item || item->group() != this) {
-+            continue;
-+        }
-+
-+        if (owner.isNull() || notification->applicationName() == owner) {
-+            item->setMaximumHeight(QWIDGETSIZE_MAX);
-+            item->setVisible(true);
-+        } else {
-+            item->setMaximumHeight(0);
-+            item->setVisible(false);
-+        }
-+    }
-+
-+    m_currentFilter = owner;
-+}
-+
-+void NotificationGroup::tabSwitched(int index)
-+{
-+    if (index > 0) {
-+        filterNotificationsByOwner(m_notificationBar->tabText(index));
-+    } else {
-+        filterNotificationsByOwner(QString());
-+    }
-+}
-+
-+
-+#include "notificationgroup.moc"
-+
-diff --git a/plasma/generic/applets/notifications/ui/notificationgroup.h b/plasma/generic/applets/notifications/ui/notificationgroup.h
-new file mode 100644
-index 0000000..ffa2112
---- /dev/null
-+++ b/plasma/generic/applets/notifications/ui/notificationgroup.h
-@@ -0,0 +1,85 @@
-+/***************************************************************************
-+ *   notificationgroup.h                                                *
-+ *   Copyright (C) 2010 Marco Martin <notmart@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 NOTIFICATIONGROUP_H
-+#define NOTIFICATIONGROUP_H
-+
-+
-+#include <Plasma/Extender>
-+#include <Plasma/ExtenderGroup>
-+
-+
-+#include <Plasma/Plasma>
-+
-+class QGraphicsLinearLayout;
-+
-+namespace Plasma
-+{
-+    class ExtenderItem;
-+    class TabBar;
-+    class Extender;
-+}
-+
-+class NotificationWidget;
-+class Notification;
-+
-+class NotificationGroup : public Plasma::ExtenderGroup
-+{
-+    Q_OBJECT
-+
-+public:
-+    NotificationGroup(Plasma::Extender *parent, uint groupId = 0);
-+    ~NotificationGroup();
-+
-+    void addNotification(Notification *notification);
-+
-+    void filterNotificationsByOwner(const QString &owner);
-+
-+
-+public Q_SLOTS:
-+    void removeNotification(Notification *notification);
-+
-+protected Q_SLOTS:
-+    void tabSwitched(int index);
-+    void extenderItemDestroyed(Plasma::ExtenderItem *object);
-+
-+Q_SIGNALS:
-+    void scrollerEmpty();
-+
-+private:
-+    Plasma::TabBar *m_notificationBar;
-+
-+    //housekeeping data structures
-+    QList<Notification *>m_notifications;
-+
-+    //Those two are kept on both ways since we are not sure the thing
-+    //contained in the hash is still valid so we couldn't obtain the
-+    //info to remove the proper key, unless both ways are stored
-+    QHash<QString, QSet<Notification *> > m_notificationsForApp;
-+    QHash<Notification *, QString> m_appForNotification;
-+
-+    QHash<Notification *, Plasma::ExtenderItem *>m_extenderItemsForNotification;
-+    QHash<Plasma::ExtenderItem *, Notification *>m_notificationForExtenderItems;
-+
-+    QString m_currentFilter;
-+};
-+
-+
-+#endif
-diff --git a/plasma/generic/applets/notifications/ui/notifications.cpp b/plasma/generic/applets/notifications/ui/notifications.cpp
-new file mode 100644
-index 0000000..eea1d72
---- /dev/null
-+++ b/plasma/generic/applets/notifications/ui/notifications.cpp
-@@ -0,0 +1,434 @@
-+/***************************************************************************
-+ *   applet.cpp                                                            *
-+ *                                                                         *
-+ *   Copyright (C) 2008 Jason Stubbs <jasonbstubbs@gmail.com>              *
-+ *   Copyright (C) 2008 Sebastian Sauer                                    *
-+ *   Copyright (C) 2010 Marco Martin <notmart@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 .        *
-+ ***************************************************************************/
-+
-+#include "notifications.h"
-+
-+#include <QtGui/QApplication>
-+#include <QtGui/QGraphicsLayout>
-+#include <QtGui/QGraphicsLinearLayout>
-+#include <QtGui/QVBoxLayout>
-+#include <QtGui/QIcon>
-+#include <QtGui/QLabel>
-+#include <QtGui/QListWidget>
-+#include <QtGui/QTreeWidget>
-+#include <QtGui/QCheckBox>
-+#include <QtGui/QPainter>
-+#include <QtGui/QX11Info>
-+#include <QtCore/QProcess>
-+
-+
-+#include <KConfigDialog>
-+#include <KComboBox>
-+#include <KWindowSystem>
-+#include <KIconLoader>
-+
-+#include <Solid/Device>
-+
-+#include <plasma/extender.h>
-+#include <plasma/extenderitem.h>
-+#include <plasma/extendergroup.h>
-+#include <plasma/framesvg.h>
-+#include <plasma/widgets/label.h>
-+#include <plasma/theme.h>
-+#include <plasma/dataenginemanager.h>
-+#include <plasma/dataengine.h>
-+#include <Plasma/TabBar>
-+#include <Plasma/Animator>
-+#include <Plasma/Animation>
-+#include <Plasma/Containment>
-+#include <Plasma/Corona>
-+#include <Plasma/Dialog>
-+#include <Plasma/WindowEffects>
-+
-+#include "config-notifications.h"
-+#ifdef HAVE_LIBXSS      // Idle detection.
-+#include <X11/Xlib.h>
-+#include <X11/Xutil.h>
-+#include <X11/extensions/scrnsaver.h>
-+#include <fixx11h.h>
-+#endif // HAVE_LIBXSS
-+
-+#include "../core/notificationsmanager.h"
-+#include "../core/notification.h"
-+#include "../core/completedjobnotification.h"
-+#include "busywidget.h"
-+#include "jobwidget.h"
-+#include "jobtotalswidget.h"
-+#include "notificationgroup.h"
-+#include "notificationstack.h"
-+#include "stackdialog.h"
-+
-+
-+K_EXPORT_PLASMA_APPLET(notifications, Notifications)
-+
-+
-+Notifications::Notifications(QObject *parent, const QVariantList &arguments)
-+    : Plasma::PopupApplet(parent, arguments),
-+      m_jobSummaryWidget(0),
-+      m_autoHidePopup(true),
-+      m_notificationStack(0),
-+      m_notificationStackDialog(0),
-+      m_standaloneJobSummaryWidget(0),
-+      m_standaloneJobSummaryDialog(0),
-+      m_busyWidget(0)
-+{
-+    m_manager = new Manager(this);
-+
-+    setPopupIcon(QIcon());
-+    setPassivePopup(true);
-+    setAspectRatioMode(Plasma::IgnoreAspectRatio);
-+    setBackgroundHints(NoBackground);
-+    setHasConfigurationInterface(true);
-+    setMinimumSize(KIconLoader::SizeSmall, KIconLoader::SizeSmall);
-+}
-+
-+Notifications::~Notifications()
-+{
-+    // stop listening to the manager
-+    disconnect(m_manager, 0, this, 0);
-+    if (m_notificationStackDialog) {
-+        disconnect(m_notificationStackDialog, 0, this, 0);
-+    }
-+
-+    foreach (Notification *notification, m_manager->notifications()) {
-+        // we don't want a destroyed managed after the destruction of manager
-+        disconnect(notification, 0, this, 0);
-+    }
-+
-+    //has to be deleted before the manager because it will access it
-+    delete m_busyWidget;
-+    delete m_notificationStackDialog;
-+    delete m_standaloneJobSummaryDialog;
-+}
-+
-+void Notifications::init()
-+{
-+    extender()->setEmptyExtenderMessage(i18n("No notifications and no jobs"));
-+
-+    m_busyWidget = new BusyWidget(this, m_manager);
-+    connect(m_busyWidget, SIGNAL(clicked()), this, SLOT(togglePopup()));
-+    QGraphicsLinearLayout *lay = new QGraphicsLinearLayout(this);
-+    setContentsMargins(0, 0, 0, 0);
-+    lay->setContentsMargins(0, 0, 0, 0);
-+    lay->addItem(m_busyWidget);
-+
-+    configChanged();
-+    setStatus(Plasma::PassiveStatus);
-+}
-+
-+void Notifications::configChanged()
-+{
-+    KConfigGroup cg = config();
-+
-+    m_autoHidePopup = cg.readEntry("AutoHidePopup", true);
-+    if (m_notificationStackDialog) {
-+        m_notificationStackDialog->setAutoHide(m_autoHidePopup);
-+    }
-+
-+    if (cg.readEntry("ShowJobs", true)) {
-+        createJobGroups();
-+
-+        m_manager->registerJobProtocol();
-+        connect(m_manager, SIGNAL(jobAdded(Job*)),
-+                this, SLOT(addJob(Job*)), Qt::UniqueConnection);
-+        connect(m_manager, SIGNAL(jobRemoved(Job*)),
-+                this, SLOT(finishJob(Job*)), Qt::UniqueConnection);
-+    } else {
-+        delete extender()->group("jobGroup");
-+        m_manager->unregisterJobProtocol();
-+        disconnect(m_manager, SIGNAL(jobAdded(Job*)),
-+                   this, SLOT(addJob(Job*)));
-+        disconnect(m_manager, SIGNAL(jobRemoved(Job*)),
-+                   this, SLOT(finishJob(Job*)));
-+    }
-+
-+    if (cg.readEntry("ShowNotifications", true)) {
-+        m_manager->registerNotificationProtocol();
-+        connect(m_manager, SIGNAL(notificationAdded(Notification*)),
-+                this, SLOT(addNotification(Notification*)), Qt::UniqueConnection);
-+    } else {
-+        m_manager->unregisterNotificationProtocol();
-+        disconnect(m_manager, SIGNAL(notificationAdded(Notification*)),
-+                   this, SLOT(addNotification(Notification*)));
-+    }
-+}
-+
-+void Notifications::syncNotificationBarNeeded()
-+{
-+    if (!m_manager) {
-+        return;
-+    }
-+
-+    if (m_manager->notifications().isEmpty()) {
-+        if (extender()->item("notifications")) {
-+            //don't let him in the config file
-+            extender()->item("notifications")->destroy();
-+        }
-+    } else if (!extender()->item("notifications")) {
-+        m_notificationGroup = new NotificationGroup(extender());
-+    }
-+}
-+
-+Manager *Notifications::manager() const
-+{
-+    return m_manager;
-+}
-+
-+void Notifications::createConfigurationInterface(KConfigDialog *parent)
-+{
-+    if (!m_notificationInterface) {
-+        KConfigGroup cg = config();
-+        m_notificationInterface = new QWidget();
-+
-+        m_notificationUi.setupUi(m_notificationInterface.data());
-+
-+        m_notificationUi.showJobs->setChecked(cg.readEntry("ShowJobs", true));
-+        m_notificationUi.showNotifications->setChecked(cg.readEntry("ShowNotifications", true));
-+
-+        m_notificationUi.autoHide->setChecked(config().readEntry("AutoHidePopup", true));
-+
-+        connect(parent, SIGNAL(applyClicked()), this, SLOT(configAccepted()));
-+        connect(parent, SIGNAL(okClicked()), this, SLOT(configAccepted()));
-+
-+        parent->addPage(m_notificationInterface.data(), i18n("Information"),
-+                        "preferences-desktop-notification",
-+                        i18n("Choose which information to show"));
-+
-+        connect(m_notificationUi.showNotifications, SIGNAL(stateChanged(int)), parent, SLOT(settingsModified()));
-+        connect(m_notificationUi.showJobs, SIGNAL(stateChanged(int)), parent, SLOT(settingsModified()));
-+        connect(m_notificationUi.autoHide, SIGNAL(stateChanged(int)), parent, SLOT(settingsModified()));
-+    }
-+}
-+
-+void Notifications::configAccepted()
-+{
-+    //TODO put in a single page
-+    //cg.writeEntry("AutoHidePopup", m_autoHideUi.autoHide->isChecked());
-+
-+    KConfigGroup cg = config();
-+    cg.writeEntry("ShowJobs", m_notificationUi.showJobs->isChecked());
-+    cg.writeEntry("ShowNotifications", m_notificationUi.showNotifications->isChecked());
-+    cg.writeEntry("AutoHidePopup", m_notificationUi.autoHide->isChecked());
-+
-+    emit configNeedsSaving();
-+}
-+
-+void Notifications::addNotification(Notification *notification)
-+{
-+    syncNotificationBarNeeded();
-+
-+    //At this point we are sure the pointer is valid
-+    m_notificationGroup.data()->addNotification(notification);
-+
-+
-+    if (isPopupShowing()) {
-+        return;
-+    }
-+
-+    if (!m_notificationStack) {
-+        m_notificationStack = new NotificationStack(this);
-+        if (containment() && containment()->corona()) {
-+            containment()->corona()->addOffscreenWidget(m_notificationStack);
-+        }
-+        m_notificationStackDialog = new StackDialog;
-+        m_notificationStackDialog->setNotificationStack(m_notificationStack);
-+        m_notificationStackDialog->setApplet(this);
-+        connect(m_notificationStack, SIGNAL(stackEmpty()), m_notificationStackDialog, SLOT(hide()));
-+        connect(m_notificationStack, SIGNAL(showRequested()), m_notificationStackDialog, SLOT(perhapsShow()));
-+        m_notificationStackDialog->setAutoHide(m_autoHidePopup);
-+
-+        if (m_standaloneJobSummaryDialog) {
-+            m_notificationStackDialog->setWindowToTile(m_standaloneJobSummaryDialog);
-+        }
-+    }
-+
-+
-+    m_notificationStack->addNotification(notification);
-+    m_notificationStackDialog->syncToGraphicsWidget();
-+
-+    if (containment() && containment()->corona()) {
-+        if (!m_notificationStackDialog->isVisible()) {
-+            m_notificationStack->setCurrentNotification(notification);
-+        }
-+
-+        KWindowSystem::setOnAllDesktops(m_notificationStackDialog->winId(), true);
-+        m_notificationStackDialog->perhapsShow();
-+    }
-+
-+    Plasma::Animation *pulse = Plasma::Animator::create(Plasma::Animator::PulseAnimation, m_busyWidget);
-+    pulse->setTargetWidget(m_busyWidget);
-+    pulse->start(QAbstractAnimation::DeleteWhenStopped);
-+}
-+
-+void Notifications::addJob(Job *job)
-+{
-+    Plasma::ExtenderGroup *group = extender()->group("jobGroup");
-+
-+    Plasma::ExtenderItem *extenderItem = new Plasma::ExtenderItem(extender());
-+    extenderItem->setTransient(true);
-+    extenderItem->config().writeEntry("type", "job");
-+    extenderItem->setWidget(new JobWidget(job, extenderItem));
-+
-+    extenderItem->setGroup(group);
-+
-+    if (group) {
-+        group->setCollapsed(group->items().count() < 2);
-+    }
-+
-+    if (isPopupShowing()) {
-+        return;
-+    }
-+
-+    //show the tiny standalone overview
-+    if (!m_standaloneJobSummaryWidget) {
-+        m_standaloneJobSummaryDialog = new Plasma::Dialog();
-+        KWindowSystem::setType(m_standaloneJobSummaryDialog->winId(), NET::Dock);
-+        if (m_notificationStackDialog) {
-+            m_notificationStackDialog->setWindowToTile(m_standaloneJobSummaryDialog);
-+        }
-+
-+        m_standaloneJobSummaryWidget = new JobTotalsWidget(m_manager->jobTotals(), this);
-+        if (containment() && containment()->corona()) {
-+            containment()->corona()->addOffscreenWidget(m_standaloneJobSummaryWidget);
-+        }
-+        m_standaloneJobSummaryDialog->setGraphicsWidget(m_standaloneJobSummaryWidget);
-+        //FIXME:sizing hack and layout issues..
-+        m_standaloneJobSummaryWidget->resize(m_standaloneJobSummaryWidget->size().width(), 32);
-+        m_standaloneJobSummaryWidget->setMaximumHeight(32);
-+        m_standaloneJobSummaryWidget->setMinimumHeight(32);
-+        m_standaloneJobSummaryWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
-+    }
-+
-+    m_standaloneJobSummaryDialog->syncToGraphicsWidget();
-+    KWindowSystem::setState(m_standaloneJobSummaryDialog->winId(), NET::KeepBelow);
-+
-+    if (containment() && containment()->corona()) {
-+        m_standaloneJobSummaryDialog->move(containment()->corona()->popupPosition(this, m_standaloneJobSummaryDialog->size()));
-+        m_standaloneJobSummaryDialog->show();
-+        Plasma::WindowEffects::slideWindow(m_standaloneJobSummaryDialog, location());
-+
-+        KWindowSystem::setOnAllDesktops(m_standaloneJobSummaryDialog->winId(), true);
-+        KWindowSystem::clearState(m_standaloneJobSummaryDialog->winId(), NET::KeepAbove|NET::StaysOnTop);
-+
-+        KWindowSystem::setState(m_standaloneJobSummaryDialog->winId(), NET::SkipTaskbar|NET::SkipPager);
-+        KWindowSystem::raiseWindow(m_standaloneJobSummaryDialog->winId());
-+        KWindowSystem::setOnAllDesktops(m_standaloneJobSummaryDialog->winId(), true);
-+    }
-+}
-+
-+void Notifications::initExtenderItem(Plasma::ExtenderItem *extenderItem)
-+{
-+    if (extenderItem->name() == "jobGroup") {
-+        m_jobSummaryWidget = new JobTotalsWidget(m_manager->jobTotals(), extenderItem);
-+        extenderItem->setWidget(m_jobSummaryWidget);
-+        Plasma::ExtenderGroup *group = qobject_cast<Plasma::ExtenderGroup*>(extenderItem);
-+        if (group) {
-+            extenderItem->setCollapsed(!group->isGroupCollapsed());
-+        }
-+        return;
-+    }
-+
-+    if (extenderItem->config().readEntry("type", QString()) == "job") {
-+        extenderItem->setWidget(new JobWidget(0, extenderItem));
-+    } else {
-+        //unknown type, this should never happen
-+        extenderItem->destroy();
-+    }
-+
-+}
-+
-+void Notifications::popupEvent(bool show)
-+{
-+    if (m_busyWidget) {
-+        m_busyWidget->suppressToolTips(show);
-+    }
-+
-+    //decide about showing the tiny progressbar or not
-+    if (m_standaloneJobSummaryDialog) {
-+        if (show || !m_manager->jobs().isEmpty()) {
-+            if (!show) {
-+                KWindowSystem::raiseWindow(m_standaloneJobSummaryDialog->winId());
-+                KWindowSystem::setState(m_standaloneJobSummaryDialog->winId(), NET::SkipTaskbar|NET::SkipPager);
-+                KWindowSystem::setState(m_standaloneJobSummaryDialog->winId(), NET::KeepBelow);
-+            } else {
-+                m_standaloneJobSummaryDialog->hide();
-+            }
-+        }
-+    }
-+
-+    if (m_notificationStackDialog && show) {
-+        m_notificationStackDialog->hide();
-+    }
-+
-+    Plasma::ExtenderGroup * jobGroup = extender()->group("jobGroup");
-+    if (!jobGroup) {
-+        return;
-+    }
-+
-+    foreach (Plasma::ExtenderItem *item, jobGroup->items()) {
-+        JobWidget *job = dynamic_cast<JobWidget *>(item->widget());
-+        if (job) {
-+            job->poppedUp(show);
-+        }
-+    }
-+}
-+
-+void Notifications::finishJob(Job *job)
-+{
-+    //finished all jobs? hide the mini progressbar
-+    if (m_standaloneJobSummaryDialog && m_manager->jobs().isEmpty()) {
-+        m_standaloneJobSummaryDialog->hide();
-+    }
-+
-+    //create a fake notification
-+    CompletedJobNotification *notification = new CompletedJobNotification(this);
-+    notification->setJob(job);
-+    m_manager->addNotification(notification);
-+
-+    Plasma::ExtenderGroup *group = extender()->group("jobGroup");
-+    if (group) {
-+        // < 3 because the second still hasn't been removed from the extendergroup
-+        group->setCollapsed(!group->isGroupCollapsed() && group->items().count() < 3);
-+    }
-+}
-+
-+void Notifications::open(const QString &url)
-+{
-+    //kDebug() << "open " << url;
-+    QProcess::startDetached("kde-open", QStringList() << url);
-+}
-+
-+void Notifications::createJobGroups()
-+{
-+    if (!extender()->hasItem("jobGroup")) {
-+        Plasma::ExtenderGroup *extenderGroup = new Plasma::ExtenderGroup(extender());
-+        extenderGroup->setName("jobGroup");
-+        initExtenderItem(extenderGroup);
-+        extenderGroup->setAutoHide(true);
-+    } else if (extender()->group("jobGroup")) {
-+        extender()->group("jobGroup")->setAutoHide(true);
-+    }
-+}
-+
-+
-+#include "notifications.moc"
-diff --git a/plasma/generic/applets/notifications/ui/notifications.h b/plasma/generic/applets/notifications/ui/notifications.h
-new file mode 100644
-index 0000000..827b28e
---- /dev/null
-+++ b/plasma/generic/applets/notifications/ui/notifications.h
-@@ -0,0 +1,101 @@
-+/***************************************************************************
-+ *   applet.h                                                              *
-+ *                                                                         *
-+ *   Copyright (C) 2008 Jason Stubbs <jasonbstubbs@gmail.com>              *
-+ *   Copyright (C) 2010 Marco Martin <notmart@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 NOTIFICATIONS_H
-+#define NOTIFICATIONS_H
-+
-+#include <plasma/popupapplet.h>
-+
-+#include "ui_notificationsconfig.h"
-+
-+
-+namespace Plasma
-+{
-+class ExtenderItem;
-+class TabBar;
-+class Dialog;
-+}
-+
-+class NotificationWidget;
-+class StackDialog;
-+
-+
-+class Job;
-+class JobTotalsWidget;
-+class Manager;
-+class Notification;
-+class NotificationGroup;
-+class NotificationStack;
-+class BusyWidget;
-+
-+class Notifications : public Plasma::PopupApplet
-+{
-+    Q_OBJECT
-+
-+public:
-+    explicit Notifications(QObject *parent, const QVariantList &arguments = QVariantList());
-+    ~Notifications();
-+
-+    void init();
-+    Manager *manager() const;
-+
-+protected:
-+    void createConfigurationInterface(KConfigDialog *parent);
-+    void initExtenderItem(Plasma::ExtenderItem *extenderItem);
-+    void configChanged();
-+
-+    void popupEvent(bool show);
-+
-+private slots:
-+    void configAccepted();
-+    void addNotification(Notification *notification);
-+    void addJob(Job *job);
-+    void finishJob(Job *job);
-+    void open(const QString &url);
-+    void syncNotificationBarNeeded();
-+
-+private:
-+    void createJobGroups();
-+
-+    Manager *m_manager;
-+    static int s_managerUsage;
-+
-+    QWeakPointer<QWidget> m_notificationInterface;
-+    QDateTime m_lastActivity;
-+
-+    JobTotalsWidget *m_jobSummaryWidget;
-+    bool m_autoHidePopup;
-+
-+    QWeakPointer<NotificationGroup> m_notificationGroup;
-+    NotificationStack *m_notificationStack;
-+    StackDialog *m_notificationStackDialog;
-+    JobTotalsWidget *m_standaloneJobSummaryWidget;
-+    Plasma::Dialog *m_standaloneJobSummaryDialog;
-+
-+    BusyWidget *m_busyWidget;
-+
-+    Ui::NotificationsConfig m_notificationUi;
-+};
-+
-+
-+
-+#endif
-diff --git a/plasma/generic/applets/notifications/ui/notificationsconfig.ui b/plasma/generic/applets/notifications/ui/notificationsconfig.ui
-new file mode 100644
-index 0000000..aaa6a82
---- /dev/null
-+++ b/plasma/generic/applets/notifications/ui/notificationsconfig.ui
-@@ -0,0 +1,114 @@
-+<?xml version="1.0" encoding="UTF-8"?>
-+<ui version="4.0">
-+ <class>NotificationsConfig</class>
-+ <widget class="QWidget" name="ProtocolsConfig">
-+  <property name="geometry">
-+   <rect>
-+    <x>0</x>
-+    <y>0</y>
-+    <width>213</width>
-+    <height>236</height>
-+   </rect>
-+  </property>
-+  <layout class="QFormLayout" name="formLayout">
-+   <property name="fieldGrowthPolicy">
-+    <enum>QFormLayout::ExpandingFieldsGrow</enum>
-+   </property>
-+   <item row="0" column="0" colspan="2">
-+    <widget class="QLabel" name="label_2">
-+     <property name="font">
-+      <font>
-+       <weight>75</weight>
-+       <bold>true</bold>
-+      </font>
-+     </property>
-+     <property name="text">
-+      <string>Pop Up Notices</string>
-+     </property>
-+    </widget>
-+   </item>
-+   <item row="2" column="0">
-+    <widget class="QLabel" name="label_4">
-+     <property name="text">
-+      <string>Application notifications</string>
-+     </property>
-+     <property name="buddy">
-+      <cstring>showNotifications</cstring>
-+     </property>
-+    </widget>
-+   </item>
-+   <item row="2" column="1">
-+    <widget class="QCheckBox" name="showNotifications">
-+     <property name="text">
-+      <string/>
-+     </property>
-+    </widget>
-+   </item>
-+   <item row="4" column="0">
-+    <widget class="QLabel" name="label_5">
-+     <property name="text">
-+      <string>File transfers and other jobs</string>
-+     </property>
-+     <property name="buddy">
-+      <cstring>showJobs</cstring>
-+     </property>
-+    </widget>
-+   </item>
-+   <item row="4" column="1">
-+    <widget class="QCheckBox" name="showJobs">
-+     <property name="text">
-+      <string/>
-+     </property>
-+    </widget>
-+   </item>
-+   <item row="8" column="0">
-+    <spacer name="verticalSpacer">
-+     <property name="orientation">
-+      <enum>Qt::Vertical</enum>
-+     </property>
-+     <property name="sizeType">
-+      <enum>QSizePolicy::Fixed</enum>
-+     </property>
-+     <property name="sizeHint" stdset="0">
-+      <size>
-+       <width>20</width>
-+       <height>6</height>
-+      </size>
-+     </property>
-+    </spacer>
-+   </item>
-+   <item row="9" column="0" colspan="2">
-+    <widget class="QLabel" name="label_3">
-+     <property name="font">
-+      <font>
-+       <weight>75</weight>
-+       <bold>true</bold>
-+      </font>
-+     </property>
-+     <property name="text">
-+      <string>Popup</string>
-+     </property>
-+    </widget>
-+   </item>
-+   <item row="10" column="1">
-+    <widget class="QCheckBox" name="autoHide">
-+     <property name="text">
-+      <string/>
-+     </property>
-+    </widget>
-+   </item>
-+   <item row="10" column="0">
-+    <widget class="QLabel" name="label_10">
-+     <property name="text">
-+      <string>Automatically hide</string>
-+     </property>
-+     <property name="buddy">
-+      <cstring>autoHide</cstring>
-+     </property>
-+    </widget>
-+   </item>
-+  </layout>
-+ </widget>
-+ <resources/>
-+ <connections/>
-+</ui>
-diff --git a/plasma/generic/applets/notifications/ui/notificationstack.cpp b/plasma/generic/applets/notifications/ui/notificationstack.cpp
-new file mode 100644
-index 0000000..f0fc52e
---- /dev/null
-+++ b/plasma/generic/applets/notifications/ui/notificationstack.cpp
-@@ -0,0 +1,233 @@
-+/***************************************************************************
-+ *   notificationstack.cpp                                                *
-+ *   Copyright (C) 2010 Marco Martin <notmart@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 .        *
-+ ***************************************************************************/
-+
-+#include "notificationstack.h"
-+#include "../core/notification.h"
-+#include "notificationwidget.h"
-+
-+#include <QGraphicsLinearLayout>
-+#include <QTimer>
-+
-+#include <KDebug>
-+#include <KGlobalSettings>
-+
-+#include <Plasma/FrameSvg>
-+#include <Plasma/Dialog>
-+
-+NotificationStack::NotificationStack(QGraphicsItem *parent)
-+   : QGraphicsWidget(parent),
-+     m_size(4),
-+     m_underMouse(false)
-+{
-+    m_mainLayout = new QGraphicsLinearLayout(Qt::Vertical, this);
-+    m_canDismissTimer = new QTimer(this);
-+    m_canDismissTimer->setSingleShot(true);
-+
-+    m_delayedRemoveTimer = new QTimer(this);
-+    m_delayedRemoveTimer->setSingleShot(true);
-+    connect(m_delayedRemoveTimer, SIGNAL(timeout()), this, SLOT(popNotification()));
-+
-+    setAcceptsHoverEvents(true);
-+}
-+
-+NotificationStack::~NotificationStack()
-+{
-+}
-+
-+void NotificationStack::addNotification(Notification *notification)
-+{
-+    m_canDismissTimer->start(1000);
-+    connect(notification, SIGNAL(notificationDestroyed(Notification*)), this, SLOT(removeNotification(Notification*)), Qt::UniqueConnection);
-+    connect(notification, SIGNAL(expired(Notification*)), this, SLOT(delayedRemoveNotification(Notification*)),  Qt::UniqueConnection);
-+    connect(notification, SIGNAL(changed(Notification*)), this, SLOT(notificationChanged(Notification*)), Qt::UniqueConnection);
-+
-+    NotificationWidget *notificationWidget = new NotificationWidget(notification, this);
-+    notificationWidget->installEventFilter(this);
-+    notificationWidget->setAcceptsHoverEvents(this);
-+    connect(notificationWidget, SIGNAL(actionTriggered(Notification*)), this, SLOT(removeNotification(Notification*)));
-+
-+    m_notificationWidgets[notification] = notificationWidget;
-+    m_notifications.append(notification);
-+
-+    if (m_notifications.size() > 1) {
-+        notificationWidget->setCollapsed(true, false);
-+    } else {
-+        m_currentNotificationWidget = notificationWidget;
-+    }
-+
-+    if (m_notifications.size() > m_size) {
-+        bool found = false;
-+
-+        //try to kill the oldest notification of the same app
-+        foreach (Notification *notif, m_notifications) {
-+            if (notif->applicationName() == notification->applicationName()) {
-+                m_notificationWidgets[notif]->deleteLater();
-+                m_notificationWidgets.remove(notif);
-+                m_notifications.removeAll(notif);
-+                found = true;
-+                break;
-+            }
-+        }
-+        //or kill the oldest one
-+        if (!found) {
-+            Notification *notif = m_notifications.first();
-+            m_notificationWidgets[notif]->deleteLater();
-+            m_notificationWidgets.remove(notif);
-+            m_notifications.pop_front();
-+        }
-+    }
-+
-+    m_mainLayout->insertItem(0, notificationWidget);
-+    m_mainLayout->activate();
-+    updateGeometry();
-+    resize(size().width(), effectiveSizeHint(Qt::MinimumSize).height());
-+    emit updateRequested();
-+}
-+
-+void NotificationStack::notificationChanged(Notification *notification)
-+{
-+    //if it was gone away put in on the stack again
-+    if (!m_notificationWidgets.contains(notification)) {
-+        addNotification(notification);
-+    }
-+    emit showRequested();
-+}
-+
-+void NotificationStack::removeNotification(Notification *notification)
-+{
-+    NotificationWidget *nw = m_notificationWidgets.value(notification);
-+    if (nw) {
-+        nw->deleteLater();
-+    }
-+    m_mainLayout->removeItem(nw);
-+    m_notificationWidgets.remove(notification);
-+    m_notifications.removeAll(notification);
-+
-+    if (m_notifications.count() > 0) {
-+        setCurrentNotification(m_notifications.first());
-+    }
-+
-+    if (m_notifications.count() == 0) {
-+        emit stackEmpty();
-+    }
-+
-+    updateGeometry();
-+    resize(size().width(), sizeHint(Qt::MinimumSize, QSizeF()).height());
-+    emit updateRequested();
-+}
-+
-+void NotificationStack::delayedRemoveNotification(Notification *notification)
-+{
-+    m_notificationsToRemove.append(notification);
-+    if (!m_underMouse) {
-+        m_delayedRemoveTimer->start(1000);
-+    }
-+}
-+
-+void NotificationStack::setCurrentNotification(Notification *notification)
-+{
-+    if (m_notificationWidgets.contains(notification)) {
-+        if (m_currentNotificationWidget) {
-+            m_currentNotificationWidget.data()->setCollapsed(true);
-+        }
-+        m_currentNotificationWidget = m_notificationWidgets.value(notification);
-+        m_currentNotificationWidget.data()->setCollapsed(false);
-+    }
-+}
-+
-+void NotificationStack::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
-+{
-+    Q_UNUSED(event)
-+
-+    m_underMouse = true;
-+    m_delayedRemoveTimer->stop();
-+}
-+
-+void NotificationStack::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
-+{
-+    Q_UNUSED(event)
-+
-+    m_underMouse = false;
-+    m_delayedRemoveTimer->start(1000);
-+}
-+
-+void NotificationStack::mousePressEvent(QGraphicsSceneMouseEvent *event)
-+{
-+    event->accept();
-+}
-+
-+void NotificationStack::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
-+{
-+    Q_UNUSED(event)
-+
-+    if (!m_canDismissTimer->isActive() &&
-+        QPointF(event->buttonDownScenePos(event->button()) - event->scenePos()).manhattanLength() < KGlobalSettings::dndEventDelay()) {
-+        emit hideRequested();
-+    }
-+}
-+
-+NotificationWidget *NotificationStack::currentNotificationWidget() const
-+{
-+    if (m_currentNotificationWidget) {
-+        return m_currentNotificationWidget.data();
-+    } else {
-+        return 0;
-+    }
-+}
-+
-+bool NotificationStack::eventFilter(QObject *watched, QEvent *event)
-+{
-+    NotificationWidget *nw = qobject_cast<NotificationWidget *>(watched);
-+
-+    if (!nw) {
-+        return false;
-+    }
-+
-+    if (event->type() == QEvent::GraphicsSceneHoverEnter) {
-+        if (m_currentNotificationWidget && m_currentNotificationWidget.data() == nw) {
-+            return false;
-+        } else if (m_currentNotificationWidget) {
-+            m_currentNotificationWidget.data()->setCollapsed(true);
-+        }
-+        nw->setCollapsed(false);
-+        m_currentNotificationWidget = nw;
-+        m_canDismissTimer->start(1000);
-+    } else if (event->type() == QEvent::GraphicsSceneMove) {
-+        emit updateRequested();
-+    }
-+
-+
-+    return false;
-+}
-+
-+void NotificationStack::popNotification()
-+{
-+    if (m_notificationsToRemove.isEmpty()) {
-+        return;
-+    }
-+
-+    Notification *notif = m_notificationsToRemove.first();
-+    removeNotification(notif);
-+    m_notificationsToRemove.pop_front();
-+    m_delayedRemoveTimer->start(1000);
-+}
-+
-+
-+#include "notificationstack.moc"
-diff --git a/plasma/generic/applets/notifications/ui/notificationstack.h b/plasma/generic/applets/notifications/ui/notificationstack.h
-new file mode 100644
-index 0000000..783e5ae
---- /dev/null
-+++ b/plasma/generic/applets/notifications/ui/notificationstack.h
-@@ -0,0 +1,81 @@
-+/***************************************************************************
-+ *   notificationscroller.h                                                *
-+ *   Copyright (C) 2010 Marco Martin <notmart@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 NOTIFICATIONSTACK_H
-+#define NOTIFICATIONSTACK_H
-+
-+#include <QGraphicsWidget>
-+
-+class QGraphicsLinearLayout;
-+class QTimer;
-+
-+class NotificationWidget;
-+
-+class Notification;
-+
-+class NotificationStack : public QGraphicsWidget
-+{
-+    Q_OBJECT
-+
-+public:
-+    NotificationStack(QGraphicsItem *parent = 0);
-+    ~NotificationStack();
-+
-+    void addNotification(Notification *notification);
-+
-+    //TODO:accessor
-+    void setCurrentNotification(Notification *notification);
-+
-+    NotificationWidget *currentNotificationWidget() const;
-+
-+protected:
-+    void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
-+    void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
-+    void mousePressEvent(QGraphicsSceneMouseEvent *event);
-+    void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
-+    bool eventFilter(QObject *watched, QEvent *event);
-+
-+public Q_SLOTS:
-+    void removeNotification(Notification *notification);
-+    void delayedRemoveNotification(Notification *notification);
-+
-+private Q_SLOTS:
-+    void popNotification();
-+    void notificationChanged(Notification *notification);
-+
-+Q_SIGNALS:
-+    void stackEmpty();
-+    void updateRequested();
-+    void hideRequested();
-+    void showRequested();
-+
-+private:
-+    QList<Notification *> m_notifications;
-+    QList<Notification *> m_notificationsToRemove;
-+    QHash<Notification *, NotificationWidget *> m_notificationWidgets;
-+    QGraphicsLinearLayout *m_mainLayout;
-+    int m_size;
-+    bool m_underMouse;
-+    QWeakPointer<NotificationWidget> m_currentNotificationWidget;
-+    QTimer *m_delayedRemoveTimer;
-+    QTimer *m_canDismissTimer;
-+};
-+
-+#endif
-diff --git a/plasma/generic/applets/notifications/ui/notificationwidget.cpp b/plasma/generic/applets/notifications/ui/notificationwidget.cpp
-new file mode 100644
-index 0000000..02ed38f
---- /dev/null
-+++ b/plasma/generic/applets/notifications/ui/notificationwidget.cpp
-@@ -0,0 +1,486 @@
-+/***************************************************************************
-+ *   notificationwidget.cpp                                                *
-+ *                                                                         *
-+ *   Copyright (C) 2008 Dmitry Suzdalev <dimsuz@gmail.com>                 *
-+ *   Copyright (C) 2008 Rob Scheepmaker <r.scheepmaker@student.utwente.nl> *
-+ *   Copyright (C) 2008 Jason Stubbs <jasonbstubbs@gmail.com>              *
-+ *   Copyright (C) 2010 Marco Martin <notmart@gmail.com>                   *
-+ *                                                                         *
-+ *   This program 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 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 Library General Public License for more details.                  *
-+ *                                                                         *
-+ *   You should have received a copy of the GNU Library General Public     *
-+ *   License along with this library; if not, write to the                 *
-+ *   Free Software Foundation, Inc.,                                       *
-+ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA .        *
-+ ***************************************************************************/
-+
-+#include "notificationwidget.h"
-+
-+#include <QSignalMapper>
-+
-+#include <QtGui/QGraphicsLinearLayout>
-+#include <QtGui/QGraphicsGridLayout>
-+#include <QtGui/QTextDocument>
-+#include <QtGui/QFontMetrics>
-+#include <QtGui/QGraphicsSceneResizeEvent>
-+#include <QtGui/QPainter>
-+#include <QAction>
-+#include <QLabel>
-+#include <QPropertyAnimation>
-+#include <QParallelAnimationGroup>
-+
-+#include <KColorScheme>
-+#include <KPushButton>
-+#include <KTextBrowser>
-+
-+#include <Plasma/Animation>
-+#include <Plasma/Animator>
-+#include <Plasma/Frame>
-+#include <Plasma/IconWidget>
-+#include <Plasma/Label>
-+#include <Plasma/PushButton>
-+#include <Plasma/TextBrowser>
-+#include <Plasma/Theme>
-+
-+class NotificationWidgetPrivate
-+{
-+public:
-+    NotificationWidgetPrivate(NotificationWidget *q)
-+        : q(q),
-+          destroyOnClose(true),
-+          autoDelete(false),
-+          collapsed(false),
-+          icon(0),
-+          actionsWidget(0),
-+          signalMapper(new QSignalMapper(q))
-+    {
-+    }
-+
-+    void setTextFields(const QString &applicationName, const QString &summary, const QString &message);
-+    void completeDetach();
-+    void updateActions();
-+    void updateNotification();
-+    void buttonClicked();
-+    void hideFinished();
-+    QRectF bigIconRect() const;
-+
-+    NotificationWidget *q;
-+
-+    QWeakPointer<Notification> notification;
-+    bool destroyOnClose;
-+    bool autoDelete;
-+    bool collapsed;
-+
-+    QString message;
-+    Plasma::TextBrowser *messageLabel;
-+    Plasma::Label *title;
-+    Plasma::IconWidget *closeButton;
-+    Plasma::IconWidget *icon;
-+    QGraphicsLinearLayout *titleLayout;
-+    QGraphicsLinearLayout *mainLayout;
-+    QGraphicsGridLayout *bodyLayout;
-+    QGraphicsWidget *body;
-+    QGraphicsWidget *iconPlaceSmall;
-+    QGraphicsWidget *iconPlaceBig;
-+    QGraphicsWidget *actionsWidget;
-+    QHash<QString, QString> actions;
-+    QStringList actionOrder;
-+    QPropertyAnimation *hideAnimation;
-+    QPropertyAnimation *iconAnimation;
-+    QParallelAnimationGroup *animationGroup;
-+
-+    QSignalMapper *signalMapper;
-+};
-+
-+NotificationWidget::NotificationWidget(Notification *notification, QGraphicsWidget *parent)
-+    : QGraphicsWidget(parent),
-+      d(new NotificationWidgetPrivate(this))
-+{
-+    setFlag(QGraphicsItem::ItemHasNoContents, true);
-+    setMinimumWidth(300);
-+
-+    setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
-+
-+
-+    d->iconPlaceSmall = new QGraphicsWidget(this);
-+    d->iconPlaceSmall->setMinimumSize(KIconLoader::SizeSmall, KIconLoader::SizeSmall);
-+    d->iconPlaceSmall->setMaximumSize(KIconLoader::SizeSmall, KIconLoader::SizeSmall);
-+    d->icon = new Plasma::IconWidget(this);
-+    d->icon->setAcceptHoverEvents(false);
-+    d->icon->setAcceptedMouseButtons(Qt::NoButton);
-+
-+    d->title = new Plasma::Label(this);
-+    d->title->setWordWrap(false);
-+    d->title->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
-+    d->title->setAlignment(Qt::AlignCenter);
-+
-+    d->closeButton = new Plasma::IconWidget(this);
-+    d->closeButton->setSvg("widgets/configuration-icons", "close");
-+    d->closeButton->setMaximumSize(d->closeButton->sizeFromIconSize(KIconLoader::SizeSmall));
-+    d->closeButton->setMinimumSize(d->closeButton->maximumSize());
-+    connect(d->closeButton, SIGNAL(clicked()), notification, SLOT(deleteLater()));
-+
-+    d->titleLayout = new QGraphicsLinearLayout(Qt::Horizontal);
-+    d->titleLayout->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
-+    d->titleLayout->addItem(d->iconPlaceSmall);
-+    d->titleLayout->addItem(d->title);
-+    d->titleLayout->addItem(d->closeButton);
-+
-+
-+
-+    d->body = new QGraphicsWidget(this);
-+    d->body->setContentsMargins(0,0,0,0);
-+    d->body->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
-+    d->bodyLayout = new QGraphicsGridLayout(d->body);
-+    d->bodyLayout->setSpacing(0);
-+    d->bodyLayout->setContentsMargins(0,0,0,0);
-+
-+    d->messageLabel = new Plasma::TextBrowser(d->body);
-+    d->messageLabel->setPreferredWidth(0);
-+    d->messageLabel->nativeWidget()->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
-+    d->messageLabel->nativeWidget()->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
-+    d->messageLabel->nativeWidget()->setAlignment(Qt::AlignLeft|Qt::AlignVCenter);
-+    d->messageLabel->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
-+    connect(d->messageLabel->nativeWidget(), SIGNAL(urlClick(QString)),
-+            notification, SLOT(linkActivated(QString)));
-+
-+    d->iconPlaceBig = new QGraphicsWidget(this);
-+    d->iconPlaceBig->setMaximumHeight(KIconLoader::SizeLarge);
-+    d->iconPlaceBig->setMinimumHeight(KIconLoader::SizeLarge);
-+    d->iconPlaceBig->setMaximumWidth(KIconLoader::SizeLarge);
-+    d->iconPlaceBig->setMinimumWidth(KIconLoader::SizeLarge);
-+    d->iconPlaceBig->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
-+    d->bodyLayout->addItem(d->iconPlaceBig, 0, 0, Qt::AlignCenter);
-+    d->bodyLayout->addItem(d->messageLabel, 0, 1, Qt::AlignCenter);
-+
-+    d->mainLayout = new QGraphicsLinearLayout(Qt::Vertical, this);
-+    d->mainLayout->setSpacing(0);
-+    d->mainLayout->addItem(d->titleLayout);
-+    d->mainLayout->addItem(d->body);
-+
-+    d->notification = notification;
-+
-+    connect(d->signalMapper, SIGNAL(mapped(QString)),
-+            notification, SLOT(triggerAction(QString)));
-+    connect(notification, SIGNAL(changed()),
-+            this, SLOT(updateNotification()));
-+    connect(notification, SIGNAL(destroyed()),
-+            this, SLOT(deleteLater()));
-+
-+    d->hideAnimation = new QPropertyAnimation(this, "bodyHeight", this);
-+    d->hideAnimation->setDuration(250);
-+    connect(d->hideAnimation, SIGNAL(finished()), this, SLOT(hideFinished()));
-+
-+    d->iconAnimation = new QPropertyAnimation(d->icon, "geometry", d->icon);
-+    d->iconAnimation->setDuration(250);
-+
-+    d->animationGroup = new QParallelAnimationGroup(this);
-+    d->animationGroup->addAnimation(d->hideAnimation);
-+    d->animationGroup->addAnimation(d->iconAnimation);
-+
-+    d->updateNotification();
-+
-+    d->mainLayout->activate();
-+    updateGeometry();
-+}
-+
-+NotificationWidget::~NotificationWidget()
-+{
-+    delete d;
-+}
-+
-+void NotificationWidget::setCollapsed(bool collapse, bool animate)
-+{
-+    if (collapse == d->collapsed) {
-+        return;
-+    }
-+
-+    setTitleBarVisible(true);
-+
-+    //use this weird way to make easy to animate
-+    if (animate) {
-+        setMinimumHeight(-1);
-+        if (collapse) {
-+            d->hideAnimation->setStartValue(d->body->size().height());
-+            d->hideAnimation->setEndValue(0);
-+
-+            d->iconAnimation->setStartValue(d->icon->geometry());
-+            d->iconAnimation->setEndValue(d->iconPlaceSmall->geometry());
-+            d->animationGroup->start();
-+        } else {
-+            d->body->setVisible(true);
-+            d->hideAnimation->setStartValue(d->body->size().height());
-+            d->body->setMaximumHeight(-1);
-+            d->hideAnimation->setEndValue(d->body->effectiveSizeHint(Qt::PreferredSize).height());
-+
-+            d->iconAnimation->setStartValue(d->icon->geometry());
-+            d->iconAnimation->setEndValue(d->bigIconRect());
-+            d->animationGroup->start();
-+        }
-+    } else {
-+        if (collapse) {
-+            //setMaximumHeight(d->titleLayout->geometry().bottom());
-+            d->body->setMinimumHeight(0);
-+            d->body->setMaximumHeight(0);
-+            d->body->hide();
-+            setMinimumHeight(-1);
-+            d->icon->setGeometry(d->iconPlaceSmall->geometry());
-+        } else {
-+            d->body->show();
-+            d->body->setMaximumHeight(-1);
-+            d->body->setMinimumHeight(-1);
-+            d->body->setMaximumHeight(d->body->effectiveSizeHint(Qt::PreferredSize).height());
-+            d->body->setMinimumHeight(d->body->maximumHeight());
-+            updateGeometry();
-+            d->mainLayout->invalidate();
-+            setMinimumHeight(sizeHint(Qt::PreferredSize, QSizeF()).height());
-+
-+            d->icon->setGeometry(d->bigIconRect());
-+        }
-+    }
-+
-+    if (collapse) {
-+        d->messageLabel->nativeWidget()->setTextInteractionFlags(Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse|Qt::TextSelectableByKeyboard);
-+    } else {
-+        d->messageLabel->nativeWidget()->setTextInteractionFlags(Qt::LinksAccessibleByMouse);
-+    }
-+
-+    d->body->setFlag(QGraphicsItem::ItemClipsChildrenToShape, true);
-+
-+    d->collapsed = collapse;
-+}
-+
-+Notification *NotificationWidget::notification() const
-+{
-+    return d->notification.data();
-+}
-+
-+qreal NotificationWidget::bodyHeight() const
-+{
-+    return d->body->maximumHeight();
-+}
-+
-+void NotificationWidget::setBodyHeight(const qreal height)
-+{
-+    d->body->setMaximumHeight(height);
-+    d->body->setMinimumHeight(height);
-+    updateGeometry();
-+    d->mainLayout->invalidate();
-+    setMinimumHeight(sizeHint(Qt::PreferredSize, QSizeF()).height());
-+}
-+
-+bool NotificationWidget::isCollapsed() const
-+{
-+    return d->collapsed;
-+}
-+
-+void NotificationWidget::setTitleBarVisible(bool visible)
-+{
-+    if (visible) {
-+        d->iconPlaceSmall->show();
-+        d->title->show();
-+        d->closeButton->show();
-+        d->titleLayout->setMaximumHeight(QWIDGETSIZE_MAX);
-+    } else {
-+        d->iconPlaceSmall->hide();
-+        d->title->hide();
-+        d->closeButton->hide();
-+        d->titleLayout->setMaximumHeight(0);
-+    }
-+}
-+
-+bool NotificationWidget::isTitleBarVisible() const
-+{
-+    return d->title->isVisible();
-+}
-+
-+void NotificationWidget::resizeEvent(QGraphicsSceneResizeEvent *event)
-+{
-+    QGraphicsWidget::resizeEvent(event);
-+    if (d->icon && !d->collapsed && d->animationGroup->state() != QAbstractAnimation::Running) {
-+        d->icon->setGeometry(d->bigIconRect());
-+    }
-+}
-+
-+QRectF NotificationWidgetPrivate::bigIconRect() const
-+{
-+    return q->mapFromScene(iconPlaceBig->mapToScene(iconPlaceBig->boundingRect())).boundingRect();
-+}
-+
-+void NotificationWidgetPrivate::setTextFields(const QString &applicationName,
-+                                                const QString &summary, const QString &message)
-+{
-+    if (!summary.isEmpty()) {
-+        title->setText(summary);
-+    } else {
-+        title->setText(i18n("Notification from %1", applicationName));
-+    }
-+
-+
-+    QString processed = message.trimmed();
-+
-+    /*if there is a < that is not closed as a tag, replace it with an entity*/
-+    processed = processed.replace(QRegExp("<(?![^<]*>)"), "&lt;");
-+    processed.replace('\n', "<br>");
-+
-+    QFontMetricsF fm(messageLabel->font());
-+    qreal maxLine = messageLabel->rect().width();
-+
-+    QString parsed;
-+
-+    QString::const_iterator i = processed.begin();
-+    bool inTag = false;
-+    QString word;
-+    QString sentence;
-+
-+    while (i != processed.end()) {
-+        QChar c = *i;
-+
-+        if (c == '<') {
-+            inTag = true;
-+            sentence.append(word);
-+            parsed.append(fm.elidedText(sentence, Qt::ElideRight, maxLine*4.6));
-+            sentence = QString();
-+            word = QString();
-+            word.append(c);
-+        } else if (c == '>') {
-+            word.append(c);
-+            if (!sentence.isEmpty()) {
-+                parsed.append(fm.elidedText(sentence, Qt::ElideRight, maxLine*4.6));
-+                sentence.clear();
-+            }
-+            inTag = false;
-+            parsed.append(word);
-+            word = QString();
-+        } else if (c == ' ') {
-+            word.append(c);
-+            if (inTag) {
-+                parsed.append(word);
-+            } else {
-+                sentence.append(word);
-+            }
-+            word = QString();
-+        } else {
-+            word.append(c);
-+        }
-+
-+        ++i;
-+    }
-+
-+    sentence.append(word);
-+    parsed.append(fm.elidedText(sentence, Qt::ElideRight, maxLine*4.6));
-+
-+    messageLabel->setText(QLatin1String("<html>") + parsed + QLatin1String("</html>"));
-+
-+    if (!collapsed) {
-+        icon->setGeometry(bigIconRect());
-+    }
-+}
-+
-+void NotificationWidgetPrivate::completeDetach()
-+{
-+    actions.clear();
-+    actionOrder.clear();
-+
-+    delete actionsWidget;
-+    actionsWidget = 0;
-+}
-+
-+void NotificationWidgetPrivate::updateActions()
-+{
-+    if (actions.isEmpty() || actionsWidget) {
-+        return;
-+    }
-+
-+    actionsWidget = new QGraphicsWidget(body);
-+    QGraphicsLinearLayout *layout = new QGraphicsLinearLayout(actionsWidget);
-+    layout->setOrientation(Qt::Vertical);
-+    layout->setContentsMargins(0, 0, 0, 0);
-+    layout->addStretch();
-+    actionsWidget->setContentsMargins(0, 0, 0, 0);
-+
-+    foreach (const QString &actionId, actionOrder) {
-+        Plasma::PushButton *button = new Plasma::PushButton(actionsWidget);
-+        QString &action = actions[actionId];
-+        button->setText(action);
-+        button->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
-+        //TODO: we need smaller buttons but I don't like this method of accomplishing it.
-+        button->setPreferredHeight(button->minimumHeight() - 6);
-+
-+        q->connect(button, SIGNAL(clicked()), signalMapper, SLOT(map()));
-+        q->connect(button, SIGNAL(clicked()), q, SLOT(buttonClicked()));
-+        signalMapper->setMapping(button, actionId);
-+
-+        layout->addItem(button);
-+    }
-+    layout->addStretch();
-+    layout->activate();
-+
-+    if (actionsWidget->size().width() > q->size().width() * 0.4) {
-+        layout->setOrientation(Qt::Horizontal);
-+        bodyLayout->addItem(actionsWidget, 1, 0, 1, 2, Qt::AlignCenter);
-+    } else {
-+        bodyLayout->addItem(actionsWidget, 0, 2, Qt::AlignCenter);
-+    }
-+}
-+
-+void NotificationWidgetPrivate::buttonClicked()
-+{
-+    //a decsion has already been taken
-+    if (actionsWidget) {
-+        notification.data()->deleteLater();
-+    }
-+    emit q->actionTriggered(notification.data());
-+}
-+
-+void NotificationWidgetPrivate::updateNotification()
-+{
-+    if (!notification) {
-+        return;
-+    }
-+
-+
-+    //set text fields and icon
-+    setTextFields(notification.data()->applicationName(), notification.data()->summary(), notification.data()->message());
-+    icon->setIcon(notification.data()->applicationIcon());
-+    messageLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
-+
-+    //set the actions provided
-+    actions = notification.data()->actions();
-+    actionOrder = notification.data()->actionOrder();
-+    updateActions();
-+
-+    if (!notification.data()->image().isNull()) {
-+
-+        icon->setIcon(QPixmap::fromImage(notification.data()->image()));
-+
-+        QSize imageSize = notification.data()->image().size();
-+
-+        if (imageSize.width() > KIconLoader::SizeLarge || imageSize.height() > KIconLoader::SizeLarge) {
-+            imageSize.scale(KIconLoader::SizeLarge, KIconLoader::SizeLarge, Qt::KeepAspectRatio);
-+        }
-+
-+        icon->setMaximumIconSize(QSizeF(qMin((int)KIconLoader::SizeLarge, imageSize.width()),
-+                                  qMin((int)KIconLoader::SizeLarge, imageSize.height())));
-+    }
-+
-+
-+    //FIXME: this sounds wrong
-+    q->setPreferredHeight(mainLayout->effectiveSizeHint(Qt::MinimumSize).height());
-+}
-+
-+void NotificationWidgetPrivate::hideFinished()
-+{
-+    body->setVisible(!collapsed);
-+    body->setFlag(QGraphicsItem::ItemClipsChildrenToShape, false);
-+}
-+
-+#include "notificationwidget.moc"
-diff --git a/plasma/generic/applets/notifications/ui/notificationwidget.h b/plasma/generic/applets/notifications/ui/notificationwidget.h
-new file mode 100644
-index 0000000..7c1a436
---- /dev/null
-+++ b/plasma/generic/applets/notifications/ui/notificationwidget.h
-@@ -0,0 +1,72 @@
-+/***************************************************************************
-+ *   notificationwidget.h                                                  *
-+ *                                                                         *
-+ *   Copyright (C) 2008 Dmitry Suzdalev <dimsuz@gmail.com>                 *
-+ *   Copyright (C) 2008 Rob Scheepmaker <r.scheepmaker@student.utwente.nl> *
-+ *   Copyright (C) 2008 Jason Stubbs <jasonbstubbs@gmail.com>              *
-+ *   Copyright (C) 2010 Marco Martin <notmart@gmail.com>                   *
-+ *                                                                         *
-+ *   This program 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 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 Library General Public License for more details.                  *
-+ *                                                                         *
-+ *   You should have received a copy of the GNU Library General Public     *
-+ *   License along with this library; if not, write to the                 *
-+ *   Free Software Foundation, Inc.,                                       *
-+ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA .        *
-+ ***************************************************************************/
-+
-+#ifndef NOTIFICATIONWIDGET_H
-+#define NOTIFICATIONWIDGET_H
-+
-+#include <Plasma/Frame>
-+
-+#include "../core/notification.h"
-+
-+class NotificationWidgetPrivate;
-+
-+/**
-+ *  A graphics item, representing notification message.
-+ */
-+class NotificationWidget : public QGraphicsWidget
-+{
-+    Q_OBJECT
-+    Q_PROPERTY(qreal bodyHeight READ bodyHeight WRITE setBodyHeight)
-+
-+public:
-+    NotificationWidget(Notification *notification, QGraphicsWidget *parent);
-+    ~NotificationWidget();
-+
-+    void setCollapsed(bool collapse, bool animate = true);
-+    bool isCollapsed() const;
-+
-+    void setTitleBarVisible(bool visible);
-+    bool isTitleBarVisible() const;
-+
-+    qreal bodyHeight() const;
-+    void setBodyHeight(const qreal height);
-+
-+    Notification *notification() const;
-+
-+protected:
-+    void resizeEvent(QGraphicsSceneResizeEvent *event);
-+
-+Q_SIGNALS:
-+    void actionTriggered(Notification *);
-+
-+private:
-+    friend class NotificationWidgetPrivate;
-+    NotificationWidgetPrivate* const d;
-+
-+    Q_PRIVATE_SLOT(d, void updateNotification())
-+    Q_PRIVATE_SLOT(d, void buttonClicked())
-+    Q_PRIVATE_SLOT(d, void hideFinished())
-+};
-+
-+#endif // NOTIFICATIONWIDGET_H
-diff --git a/plasma/generic/applets/notifications/ui/stackdialog.cpp b/plasma/generic/applets/notifications/ui/stackdialog.cpp
-new file mode 100644
-index 0000000..9be364e
---- /dev/null
-+++ b/plasma/generic/applets/notifications/ui/stackdialog.cpp
-@@ -0,0 +1,446 @@
-+/***************************************************************************
-+ *   stacdialog.h                                                          *
-+ *   Copyright (C) 2010 Marco Martin <notmart@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 .        *
-+ ***************************************************************************/
-+
-+#include "stackdialog.h"
-+#include "notificationstack.h"
-+#include "notificationwidget.h"
-+
-+#include <QApplication>
-+#include <QDesktopWidget>
-+#include <QGraphicsLayout>
-+#include <QLayout>
-+#include <QPropertyAnimation>
-+#include <QTimer>
-+
-+#include <KWindowSystem>
-+
-+#include <Plasma/Applet>
-+#include <Plasma/Containment>
-+#include <Plasma/Corona>
-+#include <Plasma/FrameSvg>
-+#include <Plasma/WindowEffects>
-+
-+static const uint hideTimeout = 15 * 1000;
-+
-+StackDialog::StackDialog(QWidget *parent, Qt::WindowFlags f)
-+      : Plasma::Dialog(parent, f),
-+        m_applet(0),
-+        m_windowToTile(0),
-+        m_notificationStack(0),
-+        m_view(0),
-+        m_drawLeft(true),
-+        m_drawRight(true),
-+        m_autoHide(true),
-+        m_hasCustomPosition(false)
-+{
-+    m_background = new Plasma::FrameSvg(this);
-+    m_background->setImagePath("widgets/extender-background");
-+    setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
-+    KWindowSystem::setType(winId(), NET::Dock);
-+
-+    m_showTimer = new QTimer(this);
-+    m_showTimer->setSingleShot(true);
-+    m_showTimer->setInterval(0);
-+    connect(m_showTimer, SIGNAL(timeout()), this, SLOT(show()));
-+
-+    m_hideTimer = new QTimer(this);
-+    m_hideTimer->setSingleShot(true);
-+    connect(m_hideTimer, SIGNAL(timeout()), this, SLOT(hideRequested()));
-+}
-+
-+StackDialog::~StackDialog()
-+{
-+}
-+
-+void StackDialog::setNotificationStack(NotificationStack *stack)
-+{
-+    setGraphicsWidget(stack);
-+
-+    if (!m_view && layout()) {
-+        m_view = qobject_cast<QGraphicsView *>(layout()->itemAt(0)->widget());
-+        if (m_view) {
-+            m_view->installEventFilter(this);
-+        }
-+    }
-+
-+    if (m_notificationStack) {
-+        disconnect(m_notificationStack, 0, this, 0);
-+    }
-+
-+    m_notificationStack = stack;
-+
-+    connect(m_notificationStack, SIGNAL(updateRequested()), this, SLOT(update()));
-+    connect(m_notificationStack, SIGNAL(hideRequested()), this, SLOT(hideRequested()));
-+}
-+
-+NotificationStack *StackDialog::notificartionStack() const
-+{
-+    return m_notificationStack;
-+}
-+
-+void StackDialog::setApplet(Plasma::Applet *applet)
-+{
-+    m_applet = applet;
-+    adjustPosition(QPoint(-1, -1));
-+}
-+
-+Plasma::Applet *StackDialog::applet() const
-+{
-+    return m_applet;
-+}
-+
-+void StackDialog::setWindowToTile(QWidget *widget)
-+{
-+    if (m_windowToTile) {
-+        m_windowToTile->removeEventFilter(this);
-+        delete m_windowToTileAnimation;
-+    }
-+
-+    m_windowToTile = widget;
-+    m_windowToTile->installEventFilter(this);
-+    m_windowToTileAnimation = new QPropertyAnimation(m_windowToTile, "pos", this);
-+    m_windowToTileAnimation->setDuration(250);
-+    m_windowToTileAnimation->setEasingCurve(QEasingCurve::InOutQuad);
-+}
-+
-+QWidget *StackDialog::windowToTile() const
-+{
-+    return m_windowToTile;
-+}
-+
-+void StackDialog::setAutoHide(const bool autoHide)
-+{
-+    m_autoHide = autoHide;
-+}
-+
-+bool StackDialog::autoHide() const
-+{
-+    return m_autoHide;
-+}
-+
-+void StackDialog::adjustWindowToTilePos()
-+{
-+    if (m_applet && m_windowToTile && m_hasCustomPosition) {
-+        m_windowToTileAnimation->setStartValue(m_windowToTile->pos());
-+
-+        if (isVisible()) {
-+            const QRect realScreenRect = qApp->desktop()->screenGeometry(m_applet->containment()->screen());
-+            if (m_applet->location() == Plasma::TopEdge || (pos().y() - realScreenRect.top()) < m_windowToTile->size().height()) {
-+                m_windowToTileAnimation->setEndValue(QPoint(m_windowToTile->pos().x(), geometry().bottom()));
-+            } else {
-+                m_windowToTileAnimation->setEndValue(QPoint(m_windowToTile->pos().x(), pos().y() - m_windowToTile->size().height()));
-+            }
-+        } else if (m_applet && m_applet->containment() && m_applet->containment()->corona()) {
-+            m_windowToTileAnimation->setEndValue(QPoint(m_applet->containment()->corona()->popupPosition(m_applet, m_windowToTile->size())));
-+        }
-+        m_windowToTileAnimation->start();
-+    }
-+}
-+
-+void StackDialog::paintEvent(QPaintEvent *e)
-+{
-+    Plasma::Dialog::paintEvent(e);
-+
-+    QPainter painter(this);
-+    if (m_notificationStack) {
-+        //FIXME: assumption++
-+        QGraphicsLayout *mainLayout = static_cast<QGraphicsLayout *>(m_notificationStack->layout());
-+
-+        if (!m_notificationStack->currentNotificationWidget() || mainLayout->count() < 2) {
-+            return;
-+        }
-+
-+        for (int i = 0; i < mainLayout->count(); ++i) {
-+            //assumption++ all items are NotificationWidget
-+            NotificationWidget *nw = static_cast<NotificationWidget *>(mainLayout->itemAt(i));
-+
-+            //first element
-+            if (i == 0 && m_notificationStack->currentNotificationWidget() != nw) {
-+                continue;
-+            } else if (i == 0) {
-+                m_background->setEnabledBorders((Plasma::FrameSvg::EnabledBorders)(Plasma::FrameSvg::AllBorders&~Plasma::FrameSvg::TopBorder));
-+            //last element
-+            } else if (i == mainLayout->count()-1 && m_notificationStack->currentNotificationWidget() != nw) {
-+                continue;
-+            } else if (i == mainLayout->count()-1) {
-+                m_background->setEnabledBorders((Plasma::FrameSvg::EnabledBorders)Plasma::FrameSvg::AllBorders&~Plasma::FrameSvg::BottomBorder);
-+            //element under the active one
-+            } else if (m_notificationStack->currentNotificationWidget()->pos().y() < nw->pos().y()) {
-+                m_background->setEnabledBorders((Plasma::FrameSvg::EnabledBorders)Plasma::FrameSvg::AllBorders&~Plasma::FrameSvg::TopBorder);
-+            //element over the active one
-+            } else if (m_notificationStack->currentNotificationWidget()->pos().y() > nw->pos().y()) {
-+                m_background->setEnabledBorders((Plasma::FrameSvg::EnabledBorders)Plasma::FrameSvg::AllBorders&~Plasma::FrameSvg::BottomBorder);
-+            //active element
-+            } else {
-+                m_background->setEnabledBorders(Plasma::FrameSvg::AllBorders);
-+            }
-+
-+            qreal left, top, right, bottom;
-+            m_background->getMargins(left, top, right, bottom);
-+            m_background->resizeFrame(QSizeF(size().width(), nw->size().height() + top + bottom));
-+
-+            Plasma::FrameSvg::EnabledBorders borders = m_background->enabledBorders();
-+
-+            if (!m_drawLeft) {
-+                borders &= ~Plasma::FrameSvg::LeftBorder;
-+            }
-+
-+            if (!m_drawRight) {
-+                borders &= ~Plasma::FrameSvg::RightBorder;
-+            }
-+
-+            m_background->setEnabledBorders(borders);
-+
-+            const int topMargin = contentsRect().top();
-+            m_background->paintFrame(&painter, QPointF(0, nw->pos().y() - top + topMargin));
-+        }
-+    }
-+}
-+
-+void StackDialog::perhapsShow()
-+{
-+    if (m_applet && m_applet->view()) {
-+        // we use a timer here because when the stack is going to be shown, the applet is likely
-+        // to also be in movement (e.g. from hidden away to now shown to the user) and that will
-+        // likely result in an odd geometry for the applet when popupPosition is called on this
-+        // dialog. so instead we wait a bit after the show request to allow the applet to find
-+        // it's proper place
-+        m_showTimer->start();
-+    }
-+}
-+
-+void StackDialog::showEvent(QShowEvent *event)
-+{
-+    Q_UNUSED(event)
-+
-+    adjustPosition(adjustedSavedPos());
-+    adjustWindowToTilePos();
-+
-+    if (m_autoHide) {
-+        m_hideTimer->start(hideTimeout);
-+    }
-+
-+    Plasma::Dialog::showEvent(event);
-+}
-+
-+void StackDialog::hideRequested()
-+{
-+    // we have this method because hide() may not always cause a hideEvent, e.g. when
-+    // the StackDialog has not been shown yet .. however, we always want to ensure the
-+    // show timer is stopped. we also stop it in the hideEvent for completeness and to
-+    // catch any direct calls to hide() that may happen
-+    m_showTimer->stop();
-+    hide();
-+}
-+
-+void StackDialog::hideEvent(QHideEvent *event)
-+{
-+    Q_UNUSED(event)
-+
-+    m_showTimer->stop();
-+    m_hideTimer->stop();
-+
-+    adjustWindowToTilePos();
-+
-+    m_notificationStack->adjustSize();
-+    Plasma::Dialog::hideEvent(event);
-+}
-+
-+void StackDialog::resizeEvent(QResizeEvent *event)
-+{
-+    Q_UNUSED(event)
-+    adjustWindowToTilePos();
-+    Plasma::Dialog::resizeEvent(event);
-+    if (m_hasCustomPosition) {
-+        adjustPosition(pos());
-+    } else if (m_applet && m_applet->containment() && m_applet->containment()->corona()) {
-+        move(m_applet->containment()->corona()->popupPosition(m_applet, size()));
-+    }
-+}
-+
-+void StackDialog::moveEvent(QMoveEvent *event)
-+{
-+    Q_UNUSED(event)
-+
-+    adjustWindowToTilePos();
-+    Plasma::Dialog::moveEvent(event);
-+}
-+
-+void StackDialog::enterEvent(QEvent *event)
-+{
-+    Q_UNUSED(event)
-+
-+    m_hideTimer->stop();
-+}
-+
-+void StackDialog::leaveEvent(QEvent *event)
-+{
-+    Q_UNUSED(event)
-+
-+    if (m_autoHide) {
-+        m_hideTimer->start(hideTimeout);
-+    }
-+    Plasma::Dialog::leaveEvent(event);
-+}
-+
-+void StackDialog::adjustPosition(const QPoint &pos)
-+{
-+    if (!m_applet) {
-+        return;
-+    }
-+
-+    if (pos == QPoint(-1, -1)) {
-+        const QPoint popupPosition = m_applet->containment()->corona()->popupPosition(m_applet, size());
-+        move(popupPosition);
-+        Plasma::WindowEffects::slideWindow(this, m_applet->location());
-+        m_hasCustomPosition = false;
-+    } else {
-+        QPoint customPosition = pos;
-+
-+        if (m_applet->containment() &&
-+            m_applet->containment()->corona() &&
-+            m_notificationStack) {
-+            QRect screenRect = m_applet->containment()->corona()->availableScreenRegion(m_applet->containment()->screen()).boundingRect();
-+
-+            customPosition.rx() = qMax(customPosition.x(), screenRect.left());
-+            customPosition.ry() = qMax(customPosition.y(), screenRect.top());
-+            customPosition.rx() = qMin(customPosition.x() + size().width(), screenRect.right()) - size().width();
-+            customPosition.ry() = qMin(customPosition.y() + size().height(), screenRect.bottom()) - size().height();
-+
-+            bool closerToBottom = (customPosition.ry() > (screenRect.height() / 2));
-+            if (!m_lastSize.isNull() && closerToBottom
-+                && (m_lastSize.height() > size().height())) {
-+                customPosition.ry() += m_lastSize.height() - size().height();
-+            }
-+            m_lastSize = size();
-+        }
-+
-+        move(customPosition);
-+        Plasma::WindowEffects::slideWindow(this, Plasma::Desktop);
-+        m_hasCustomPosition = true;
-+    }
-+}
-+
-+void StackDialog::savePosition(const QPoint& pos)
-+{
-+    if (!m_applet || !m_applet->containment()) {
-+        return;
-+    }
-+
-+    QByteArray horizSide, vertSide;
-+    QPoint pixelsToSave;
-+    const QRect realScreenRect = qApp->desktop()->screenGeometry(m_applet->containment()->screen());
-+
-+    int screenRelativeX = pos.x() - realScreenRect.x();
-+    int diffWithRight = realScreenRect.width() - (screenRelativeX + size().width());
-+    if (screenRelativeX < diffWithRight) {
-+        horizSide = "l";
-+        pixelsToSave.rx() = screenRelativeX;
-+    } else {
-+        horizSide = "r";
-+        pixelsToSave.rx() = diffWithRight;
-+    }
-+
-+    int screenRelativeY = pos.y() - realScreenRect.y();
-+    int diffWithBottom = realScreenRect.height() - (screenRelativeY + size().height());
-+    if (screenRelativeY < diffWithBottom) {
-+        vertSide = "t";
-+        pixelsToSave.ry() = screenRelativeY;
-+    } else {
-+        vertSide = "b";
-+        pixelsToSave.ry() = diffWithBottom;
-+    }
-+
-+    kDebug() << "Affinity-v" << vertSide;
-+    kDebug() << "Affinity-h" << horizSide;
-+    kDebug() << "Y: " << pixelsToSave.ry();
-+    kDebug() << "X: " << pixelsToSave.rx();
-+
-+    m_applet->config().writeEntry("customPosition", pixelsToSave);
-+    m_applet->config().writeEntry("customPositionAffinityHoriz", horizSide);
-+    m_applet->config().writeEntry("customPositionAffinityVert", vertSide);
-+}
-+
-+QPoint StackDialog::adjustedSavedPos() const
-+{
-+    if (!m_applet) {
-+        return QPoint(-1, -1);
-+    }
-+
-+    QPoint pos = m_applet->config().readEntry("customPosition", QPoint(-1, -1));
-+
-+    if (pos != QPoint(-1, -1)) {
-+        const QRect realScreenRect = qApp->desktop()->screenGeometry(m_applet->containment()->screen());
-+        QByteArray horizSide = m_applet->config().readEntry("customPositionAffinityHoriz").toLatin1();
-+        QByteArray vertSide = m_applet->config().readEntry("customPositionAffinityVert").toLatin1();
-+
-+        if (horizSide == "l") {
-+            pos.rx() += realScreenRect.x();
-+        } else {
-+            pos.rx() = realScreenRect.x() + (realScreenRect.width() - pos.rx() - size().width());
-+        }
-+
-+        if (vertSide == "t") {
-+            pos.ry() += realScreenRect.y();
-+        } else {
-+            pos.ry() = realScreenRect.y() + (realScreenRect.height() - pos.ry() - size().height());
-+        }
-+    }
-+
-+    return pos;
-+}
-+
-+bool StackDialog::event(QEvent *event)
-+{
-+    bool ret = Dialog::event(event);
-+
-+    if (event->type() == QEvent::ContentsRectChange) {
-+        int left, top, right, bottom;
-+        getContentsMargins(&left, &top, &right, &bottom);
-+
-+        m_drawLeft = (left != 0);
-+        m_drawRight = (right != 0);
-+        update();
-+    }
-+
-+    return ret;
-+}
-+
-+bool StackDialog::eventFilter(QObject *watched, QEvent *event)
-+{
-+    if (m_windowToTile && watched == m_windowToTile &&
-+        event->type() == QEvent::Show && isVisible()) {
-+        adjustWindowToTilePos();
-+    } else if (watched == m_notificationStack && event->type() == QEvent::GraphicsSceneMousePress) {
-+        QGraphicsSceneMouseEvent *me = static_cast<QGraphicsSceneMouseEvent *>(event);
-+        m_dragPos = me->pos().toPoint();
-+    } else if (watched == m_notificationStack && event->type() == QEvent::GraphicsSceneMouseMove) {
-+        QGraphicsSceneMouseEvent *me = static_cast<QGraphicsSceneMouseEvent *>(event);
-+        adjustPosition(me->screenPos() - m_dragPos);
-+    } else if (watched == m_notificationStack && event->type() == QEvent::GraphicsSceneMouseRelease) {
-+        QGraphicsSceneMouseEvent *me = static_cast<QGraphicsSceneMouseEvent *>(event);
-+        adjustPosition(me->screenPos() - m_dragPos);
-+        savePosition(me->screenPos() - m_dragPos);
-+    }
-+
-+    return Plasma::Dialog::eventFilter(watched, event);
-+}
-+
-+#include "stackdialog.moc"
-diff --git a/plasma/generic/applets/notifications/ui/stackdialog.h b/plasma/generic/applets/notifications/ui/stackdialog.h
-new file mode 100644
-index 0000000..4360c4a
---- /dev/null
-+++ b/plasma/generic/applets/notifications/ui/stackdialog.h
-@@ -0,0 +1,99 @@
-+/***************************************************************************
-+ *   stacdialog.h                                                          *
-+ *   Copyright (C) 2010 Marco Martin <notmart@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 STACKDIALOG_H
-+#define STACKDIALOG_H
-+
-+#include <Plasma/Dialog>
-+
-+#include <QPoint>
-+
-+class QPropertyAnimation;
-+class QTimer;
-+
-+namespace Plasma
-+{
-+    class Applet;
-+    class FrameSvg;
-+}
-+
-+class NotificationStack;
-+
-+
-+class StackDialog : public Plasma::Dialog
-+{
-+    Q_OBJECT
-+public:
-+    StackDialog(QWidget *parent = 0, Qt::WindowFlags f = Qt::Window);
-+    ~StackDialog();
-+
-+    void setNotificationStack(NotificationStack *stack);
-+    NotificationStack *notificartionStack() const;
-+
-+    void setApplet(Plasma::Applet *applet);
-+    Plasma::Applet *applet() const;
-+
-+    void setWindowToTile(QWidget *widget);
-+    QWidget *windowToTile() const;
-+
-+    void setAutoHide(const bool autoHide);
-+    bool autoHide() const;
-+
-+public Q_SLOTS:
-+    void perhapsShow();
-+
-+protected:
-+    void adjustWindowToTilePos();
-+
-+    void paintEvent(QPaintEvent *e);
-+    void showEvent(QShowEvent *event);
-+    void hideEvent(QHideEvent *event);
-+    void enterEvent(QEvent *event);
-+    void leaveEvent(QEvent *event);
-+    void resizeEvent(QResizeEvent *event);
-+    void moveEvent(QMoveEvent *event);
-+    bool event(QEvent *event);
-+    bool eventFilter(QObject *watched, QEvent *event);
-+    void adjustPosition(const QPoint &pos = QPoint(-1, -1));
-+    void savePosition(const QPoint &pos);
-+    QPoint adjustedSavedPos() const;
-+
-+private Q_SLOTS:
-+    void hideRequested();
-+
-+private:
-+    Plasma::Applet *m_applet;
-+    QWidget *m_windowToTile;
-+    QPropertyAnimation *m_windowToTileAnimation;
-+    QPoint m_dragPos;
-+    QSize m_lastSize;
-+
-+    Plasma::FrameSvg *m_background;
-+    NotificationStack *m_notificationStack;
-+    QTimer *m_showTimer;
-+    QTimer *m_hideTimer;
-+    QGraphicsView *m_view;
-+    bool m_drawLeft;
-+    bool m_drawRight;
-+    bool m_autoHide;
-+    bool m_hasCustomPosition;
-+};
-+
-+#endif

diff --git a/kde-base/plasma-workspace/files/plasma-workspace-4.10.1-noplasmalock.patch b/kde-base/plasma-workspace/files/plasma-workspace-4.10.1-noplasmalock.patch
deleted file mode 100644
index 2380d20..0000000
--- a/kde-base/plasma-workspace/files/plasma-workspace-4.10.1-noplasmalock.patch
+++ /dev/null
@@ -1,11 +0,0 @@
-diff --git a/plasma/screensaver/CMakeLists.txt b/plasma/screensaver/CMakeLists.txt
-index 514c856..9dcb5f4 100644
---- a/plasma/screensaver/CMakeLists.txt
-+++ b/plasma/screensaver/CMakeLists.txt
-@@ -1,6 +1,3 @@
- add_subdirectory(containments)
--if(NOT WIN32)
--add_subdirectory(shell)
--endif(NOT WIN32)
- 
- 

diff --git a/kde-base/plasma-workspace/metadata.xml b/kde-base/plasma-workspace/metadata.xml
deleted file mode 100644
index 3b3fc4f..0000000
--- a/kde-base/plasma-workspace/metadata.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd">
-<pkgmetadata>
-<herd>kde</herd>
-<use>
-	<flag name="json">Enable JSON support via <pkg>dev-libs/qjson</pkg></flag>
-	<flag name="qalculate">Enable Qalculate runner using <pkg>sci-libs/libqalculate</pkg></flag>
-</use>
-</pkgmetadata>

diff --git a/kde-base/plasma-workspace/plasma-workspace-4.11.2-r2.ebuild b/kde-base/plasma-workspace/plasma-workspace-4.11.2-r2.ebuild
deleted file mode 100644
index 4ed968e..0000000
--- a/kde-base/plasma-workspace/plasma-workspace-4.11.2-r2.ebuild
+++ /dev/null
@@ -1,125 +0,0 @@
-# Copyright 1999-2013 Gentoo Foundation
-# Distributed under the terms of the GNU General Public License v2
-# $Header: $
-
-EAPI=5
-
-DECLARATIVE_REQUIRED="always"
-KDE_HANDBOOK="optional"
-KMNAME="kde-workspace"
-KMMODULE="plasma"
-PYTHON_COMPAT=( python2_{6,7} )
-OPENGL_REQUIRED="always"
-inherit python-single-r1 kde4-meta
-
-DESCRIPTION="Plasma: KDE desktop framework"
-KEYWORDS="~amd64 ~arm ~ppc ~ppc64 ~x86 ~amd64-linux ~x86-linux"
-IUSE="debug gps json python qalculate semantic-desktop"
-
-REQUIRED_USE="python? ( ${PYTHON_REQUIRED_USE} )"
-
-COMMONDEPEND="
-	dev-libs/libdbusmenu-qt
-	>=dev-qt/qtcore-4.8.4-r3:4
-	!kde-misc/ktouchpadenabler
-	$(add_kdebase_dep kactivities)
-	$(add_kdebase_dep kdelibs 'semantic-desktop?')
-	$(add_kdebase_dep kdepimlibs)
-	$(add_kdebase_dep kephal)
-	$(add_kdebase_dep ksysguard)
-	$(add_kdebase_dep libkworkspace)
-	$(add_kdebase_dep libplasmaclock)
-	$(add_kdebase_dep libplasmagenericshell)
-	$(add_kdebase_dep libtaskmanager)
-	x11-libs/libX11
-	x11-libs/libXcomposite
-	x11-libs/libXdamage
-	x11-libs/libXext
-	x11-libs/libXfixes
-	x11-libs/libXi
-	x11-libs/libXrender
-	gps? ( >=sci-geosciences/gpsd-2.37 )
-	json? ( dev-libs/qjson )
-	python? (
-		${PYTHON_DEPS}
-		>=dev-python/PyQt4-4.4.0[X,${PYTHON_USEDEP}]
-		$(add_kdebase_dep pykde4 "${PYTHON_USEDEP}")
-	)
-	qalculate? ( sci-libs/libqalculate )
-	semantic-desktop? (
-		dev-libs/soprano
-		$(add_kdebase_dep nepomuk-core)
-	)
-"
-DEPEND="${COMMONDEPEND}
-	dev-libs/boost
-	x11-proto/compositeproto
-	x11-proto/damageproto
-	x11-proto/fixesproto
-	x11-proto/renderproto
-"
-RDEPEND="${COMMONDEPEND}
-	$(add_kdebase_dep plasma-runtime)
-"
-
-KMEXTRA="
-	appmenu/
-	ktouchpadenabler/
-	statusnotifierwatcher/
-"
-KMEXTRACTONLY="
-	kcheckpass/
-	krunner/dbus/org.freedesktop.ScreenSaver.xml
-	krunner/dbus/org.kde.krunner.App.xml
-	ksmserver/org.kde.KSMServerInterface.xml
-	ksmserver/screenlocker/
-	libs/kephal/
-	libs/kworkspace/
-	libs/taskmanager/
-	libs/plasmagenericshell/
-	libs/ksysguard/
-	libs/kdm/kgreeterplugin.h
-	ksysguard/
-"
-
-KMLOADLIBS="libkworkspace libplasmaclock libplasmagenericshell libtaskmanager"
-
-PATCHES=( "${FILESDIR}/${PN}-4.10.1-noplasmalock.patch" "${FILESDIR}/oldnotify.patch" )
-
-pkg_setup() {
-	if use python ; then
-		python-single-r1_pkg_setup
-	fi
-	kde4-meta_pkg_setup
-}
-
-src_unpack() {
-	if use handbook; then
-		KMEXTRA+=" doc/plasma-desktop"
-	fi
-
-	kde4-meta_src_unpack
-}
-
-src_configure() {
-	mycmakeargs=(
-		$(cmake-utils_use_with gps libgps)
-		$(cmake-utils_use_with json QJSON)
-		$(cmake-utils_use_with python PythonLibrary)
-		$(cmake-utils_use_with qalculate)
-		$(cmake-utils_use_with semantic-desktop Akonadi)
-		$(cmake-utils_use_with semantic-desktop NepomukCore)
-		$(cmake-utils_use_with semantic-desktop Soprano)
-		-DWITH_Xmms=OFF
-	)
-
-	kde4-meta_src_configure
-}
-
-src_install() {
-	kde4-meta_src_install
-
-	if use python; then
-		python_optimize "${ED}"
-	fi
-}


^ permalink raw reply related	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2014-04-29 22:47 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-10-09 12:02 [gentoo-commits] dev/dilfridge:master commit in: kde-base/plasma-workspace/files/, kde-base/plasma-workspace/ Andreas Hüttel
  -- strict thread matches above, loose matches on Subject: below --
2014-04-29 22:47 Andreas Hüttel

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox