plasma: semi-working notifications applet reimplementation

the application notifications works and is nearly complete, the jobs
notification is yet to be done. so far it looks like this:
https://ibb.co/GTGMKtQ

Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
This commit is contained in:
Ivailo Monev 2023-09-16 15:06:34 +03:00
parent 5ce20a5331
commit f4d40c28e9
46 changed files with 656 additions and 3961 deletions

View file

@ -1,6 +1,5 @@
project(batterymonitor)
set(batterymonitor_SRCS
batterymonitor.cpp
)

View file

@ -1,2 +1,23 @@
installPackage(. org.kde.notifications)
project(plasma-applet-notifications)
set(notifications_SRCS
notifications.cpp
jobswidget.cpp
applicationswidget.cpp
)
kde4_add_plugin(plasma_applet_notifications ${notifications_SRCS})
target_link_libraries(plasma_applet_notifications
KDE4::plasma
KDE4::kio
)
install(
TARGETS plasma_applet_notifications
DESTINATION ${KDE4_PLUGIN_INSTALL_DIR}
)
install(
FILES plasma-applet-notifications.desktop
DESTINATION ${KDE4_SERVICES_INSTALL_DIR}
)

View file

@ -1,5 +1,4 @@
#!/bin/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
$XGETTEXT `find . -name \*.js -o -name \*.qml -o -name \*.cpp` -o $podir/plasma_applet_notifications.pot
rm -f rc.cpp

View file

@ -0,0 +1,278 @@
/* This file is part of the KDE project
Copyright (C) 2023 Ivailo Monev <xakepa10@gmail.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License version 2, as published by the Free Software Foundation.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "applicationswidget.h"
#include <QGraphicsGridLayout>
#include <Plasma/DataEngineManager>
#include <Plasma/IconWidget>
#include <Plasma/ToolButton>
#include <KIcon>
#include <KNotificationConfigWidget>
#include <KDebug>
Q_DECLARE_METATYPE(Plasma::IconWidget*)
Q_DECLARE_METATYPE(Plasma::Label*)
ApplicationsWidget::ApplicationsWidget(QGraphicsItem *parent, NotificationsWidget *notificationswidget)
: QGraphicsWidget(parent),
m_notificationswidget(notificationswidget),
m_layout(nullptr),
m_label(nullptr),
m_dataengine(nullptr)
{
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
m_layout = new QGraphicsLinearLayout(Qt::Vertical, this);
m_layout->setContentsMargins(0, 0, 0, 0);
m_label = new Plasma::Label(this);
m_label->setText(i18n("No application notifications"));
m_label->setAlignment(Qt::AlignCenter);
m_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
m_layout->addItem(m_label);
m_layout->addStretch();
setLayout(m_layout);
m_dataengine = Plasma::DataEngineManager::self()->loadEngine("notifications");
if (!m_dataengine) {
kWarning() << "Could not load notifications data engine";
return;
}
connect(
m_dataengine, SIGNAL(sourceAdded(QString)),
this, SLOT(sourceAdded(QString))
);
}
ApplicationsWidget::~ApplicationsWidget()
{
if (m_dataengine) {
Plasma::DataEngineManager::self()->unloadEngine("notifications");
}
}
int ApplicationsWidget::count() const
{
return m_frames.size();
}
void ApplicationsWidget::sourceAdded(const QString &name)
{
// qDebug() << Q_FUNC_INFO << name;
QMutexLocker locker(&m_mutex);
Plasma::Frame* frame = new Plasma::Frame(this);
frame->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
frame->setProperty("_k_name", name);
QGraphicsGridLayout* framelayout = new QGraphicsGridLayout(frame);
Plasma::IconWidget* iconwidget = new Plasma::IconWidget(frame);
iconwidget->setAcceptHoverEvents(false);
iconwidget->setAcceptedMouseButtons(Qt::NoButton);
iconwidget->setIcon(KIcon("dialog-information"));
const int desktopiconsize = KIconLoader::global()->currentSize(KIconLoader::Desktop);
const QSizeF desktopiconsizef = QSizeF(desktopiconsize, desktopiconsize);
iconwidget->setPreferredIconSize(desktopiconsizef);
iconwidget->setMinimumSize(desktopiconsizef);
iconwidget->setMaximumSize(desktopiconsizef);
iconwidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
framelayout->addItem(iconwidget, 0, 0, 2, 1);
frame->setProperty("_k_iconwidget", QVariant::fromValue(iconwidget));
Plasma::Label* bodylabel = new Plasma::Label(frame);
bodylabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
bodylabel->setAlignment(Qt::AlignTop | Qt::AlignHCenter);
framelayout->addItem(bodylabel, 0, 1, 3, 1);
frame->setProperty("_k_bodylabel", QVariant::fromValue(bodylabel));
const int smalliconsize = KIconLoader::global()->currentSize(KIconLoader::Small);
Plasma::IconWidget* removewidget = new Plasma::IconWidget(frame);
removewidget->setMaximumIconSize(QSize(smalliconsize, smalliconsize));
removewidget->setIcon(KIcon("dialog-close"));
removewidget->setToolTip(i18n("Click to remove this notification."));
removewidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
connect(
removewidget, SIGNAL(activated()),
this, SLOT(slotRemoveActivated())
);
framelayout->addItem(removewidget, 0, 2, 1, 1);
frame->setProperty("_k_removewidget", QVariant::fromValue(removewidget));
Plasma::IconWidget* configurewidget = new Plasma::IconWidget(frame);
configurewidget->setMaximumIconSize(QSize(smalliconsize, smalliconsize));
configurewidget->setIcon(KIcon("configure"));
configurewidget->setToolTip(i18n("Click to configure this notification."));
configurewidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
configurewidget->setVisible(false);
connect(
configurewidget, SIGNAL(activated()),
this, SLOT(slotConfigureActivated())
);
framelayout->addItem(configurewidget, 1, 2, 1, 1);
frame->setProperty("_k_configurewidget", QVariant::fromValue(configurewidget));
frame->setLayout(framelayout);
m_frames.append(frame);
m_label->setVisible(false);
m_layout->insertItem(0, frame);
adjustSize();
emit countChanged();
locker.unlock();
m_dataengine->connectSource(name, this);
}
void ApplicationsWidget::dataUpdated(const QString &name, const Plasma::DataEngine::Data &data)
{
// qDebug() << Q_FUNC_INFO << name << data;
#if 0
// sample data
"notification 1" QHash(
("appName", QVariant(QString, "Изтегляне на файлове (KGet)") )
( "body" , QVariant(QString, "<p>Изтеглянето на следният файл завърши:</p><p style="font-size: small;">index.html</p>") )
( "appIcon" , QVariant(QString, "kget") )
( "appRealName" , QVariant(QString, "kget") )
( "image" , QVariant(QImage, ) )
( "actions" , QVariant(QStringList, () ) )
( "summary" , QVariant(QString, "Изтеглянето завърши") )
( "expireTimeout" , QVariant(int, 6240) )
( "id" , QVariant(QString, "1") )
( "configurable" , QVariant(bool, true) )
)
#endif
QMutexLocker locker(&m_mutex);
foreach (Plasma::Frame* frame, m_frames) {
const QString framename = frame->property("_k_name").toString();
if (framename == name) {
Plasma::IconWidget* iconwidget = qvariant_cast<Plasma::IconWidget*>(frame->property("_k_iconwidget"));
const QString appicon = data.value("appIcon").toString();
if (!appicon.isEmpty()) {
iconwidget->setIcon(appicon);
}
const QStringList actions = data.value("actions").toStringList();
// qDebug() << Q_FUNC_INFO << actions;
QGraphicsGridLayout* framelayout = static_cast<QGraphicsGridLayout*>(frame->layout());
Q_ASSERT(framelayout != nullptr);
QGraphicsLinearLayout* buttonslayout = nullptr;
// row insertation starts at 0, count is +1
if (framelayout->rowCount() >= 4) {
buttonslayout = static_cast<QGraphicsLinearLayout*>(framelayout->itemAt(3, 0));
}
if (buttonslayout) {
// remove buttons in case of notification update
QList<Plasma::ToolButton*> actionbuttons;
for (int i = 0; i < buttonslayout->count(); i++) {
Plasma::ToolButton* actionbutton = static_cast<Plasma::ToolButton*>(buttonslayout->itemAt(i));
actionbuttons.append(actionbutton);
buttonslayout->removeAt(i);
}
qDeleteAll(actionbuttons);
actionbuttons.clear();
}
for (int i = 0; i < actions.size(); i++) {
const QString actionid = actions[i];
i++;
const QString actionname = actions[i];
if (actionid.isEmpty() || actionname.isEmpty()) {
kWarning() << "Empty action ID or name" << actionid << actionname;
continue;
}
Plasma::ToolButton* actionbutton = new Plasma::ToolButton(frame);
actionbutton->setProperty("_k_name", framename);
actionbutton->setProperty("_k_actionid", actionid);
actionbutton->setText(actionname);
connect(
actionbutton, SIGNAL(clicked()),
this, SLOT(slotActionClicked())
);
if (!buttonslayout) {
buttonslayout = new QGraphicsLinearLayout(Qt::Horizontal, framelayout);
}
buttonslayout->addItem(actionbutton);
}
if (buttonslayout) {
framelayout->addItem(buttonslayout, 3, 0, 1, 3);
framelayout->setAlignment(buttonslayout, Qt::AlignCenter);
}
Plasma::Label* label = qvariant_cast<Plasma::Label*>(frame->property("_k_bodylabel"));
label->setText(data.value("body").toString());
Plasma::IconWidget* configurewidget = qvariant_cast<Plasma::IconWidget*>(frame->property("_k_configurewidget"));
const bool configurable = data.value("configurable").toBool();
configurewidget->setVisible(configurable);
if (configurable) {
configurewidget->setProperty("_k_apprealname", data.value("appRealName"));
}
frame->adjustSize();
break;
}
}
}
void ApplicationsWidget::slotRemoveActivated()
{
QMutexLocker locker(&m_mutex);
const Plasma::IconWidget* removewidget = qobject_cast<Plasma::IconWidget*>(sender());
Plasma::Frame* removeframe = qobject_cast<Plasma::Frame*>(removewidget->parentObject());
Q_ASSERT(removeframe != nullptr);
QMutableListIterator<Plasma::Frame*> iter(m_frames);
while (iter.hasNext()) {
Plasma::Frame* frame = iter.next();
if (frame == removeframe) {
const QString framename = removeframe->property("_k_name").toString();
Plasma::Service* plasmaservice = m_dataengine->serviceForSource(framename);
if (!plasmaservice) {
kWarning() << "Could not get service for" << framename;
} else {
const QVariantMap plasmaserviceargs = plasmaservice->operationParameters("userClosed");
(void)plasmaservice->startOperationCall("userClosed", plasmaserviceargs);
}
m_layout->removeItem(frame);
frame->deleteLater();
iter.remove();
break;
}
}
m_label->setVisible(m_frames.size() <= 0);
adjustSize();
emit countChanged();
}
void ApplicationsWidget::slotConfigureActivated()
{
const Plasma::IconWidget* configurewidget = qobject_cast<Plasma::IconWidget*>(sender());
const QString frameapprealname = configurewidget->property("_k_apprealname").toString();
KNotificationConfigWidget::configure(frameapprealname, nullptr);
}
void ApplicationsWidget::slotActionClicked()
{
const Plasma::ToolButton* actionbutton = qobject_cast<Plasma::ToolButton*>(sender());
const QString framename = actionbutton->property("_k_name").toString();
const QString actionid = actionbutton->property("_k_actionid").toString();
Plasma::Service* plasmaservice = m_dataengine->serviceForSource(framename);
if (!plasmaservice) {
kWarning() << "Could not get service for" << framename;
} else {
QVariantMap plasmaserviceargs = plasmaservice->operationParameters("invokeAction");
plasmaserviceargs["actionId"] = actionid;
(void)plasmaservice->startOperationCall("invokeAction", plasmaserviceargs);
}
// TODO: remove notification too
}
#include "moc_applicationswidget.cpp"

View file

@ -0,0 +1,60 @@
/* This file is part of the KDE project
Copyright (C) 2023 Ivailo Monev <xakepa10@gmail.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License version 2, as published by the Free Software Foundation.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef APPLICATIONSWIDGET_H
#define APPLICATIONSWIDGET_H
#include <QMutex>
#include <QGraphicsWidget>
#include <QGraphicsLinearLayout>
#include <Plasma/Label>
#include <Plasma/Frame>
#include <Plasma/DataEngine>
#include <KIconLoader>
class NotificationsWidget;
class ApplicationsWidget : public QGraphicsWidget
{
Q_OBJECT
public:
ApplicationsWidget(QGraphicsItem *parent, NotificationsWidget *notificationswidget);
~ApplicationsWidget();
int count() const;
Q_SIGNALS:
int countChanged();
private Q_SLOTS:
void sourceAdded(const QString &name);
void dataUpdated(const QString &name, const Plasma::DataEngine::Data &data);
void slotRemoveActivated();
void slotConfigureActivated();
void slotActionClicked();
private:
QMutex m_mutex;
NotificationsWidget *m_notificationswidget;
QGraphicsLinearLayout* m_layout;
Plasma::Label* m_label;
QList<Plasma::Frame*> m_frames;
Plasma::DataEngine *m_dataengine;
};
#endif // APPLICATIONSWIDGET_H

View file

@ -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>

View file

@ -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.operationParameters(operationName)
service.startOperationCall(operationName, 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.operationParameters("stop")
service.startOperationCall("stop", 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.formatDuration(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}
}
}
]
}
}
}

View file

@ -1,104 +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.addJobNotification(
source,
runningJobs[source]["appIconName"],
runningJobs[source]["appName"],
i18n("%1 [Finished]", runningJobs[source]["infoMessage"]),
message,
0,
0,
runningJobs[source]["destUrl"] ? [{"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
}
}
}

View file

@ -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
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
fillMode: Image.PreserveAspectFit
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
}
}
]
}
}

View file

@ -1,251 +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: {
if (!notificationsModel.inserting)
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.family: theme.defaultFont.family
font.italic: theme.defaultFont.italic
font.pointSize: theme.defaultFont.pointSize
font.strikeout: theme.defaultFont.strikeout
font.underline: theme.defaultFont.underline
font.weight: theme.defaultFont.weight
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
}
}
}
}
}
}
}
}

View file

@ -1 +0,0 @@
NotificationDelegate 0.1 NotificationDelegate.qml

View file

@ -1,187 +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
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
}
}
]
}
}

View file

@ -1,236 +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 "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.inserting = true;
notificationsModel.insert(0, notification);
notificationsModel.inserting = false;
if (plasmoid.popupShowing) {
return
}
if (!lastNotificationPopup) {
lastNotificationPopup = lastNotificationPopupComponent.createObject(notificationsRoot)
}
lastNotificationPopup.popup(notification)
}
function addJobNotification(source, appIcon, appName, summary, body, expireTimeout, urgency, actions) {
addNotification(source, appIcon, new QImage, appName, summary, body, expireTimeout, urgency, appName, false, actions)
}
function executeAction(source, id) {
//try to use the service
if (source.indexOf("notification") !== -1) {
var service = notificationsSource.serviceForSource(source)
var op = service.operationParameters("invokeAction")
op["actionId"] = id
service.startOperationCall("invokeAction", 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.operationParameters("configureNotification")
op["appRealName"] = appRealName;
service.startOperationCall("configureNotification", op)
}
function closeNotification(source) {
var service = notificationsSource.serviceForSource(source)
var op = service.operationParameters("userClosed")
service.startOperationCall("userClosed", op)
}
property QtObject lastNotificationPopup
Component {
id: lastNotificationPopupComponent
LastNotificationPopup {
}
}
ListModel {
id: notificationsModel
property bool inserting: false;
}
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
}
}
}

View file

@ -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
}
}
}

View file

@ -1,68 +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>
<connections/>
</ui>

View file

@ -1,170 +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.locale 0.1 as KLocale
import "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
PlasmaComponents.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
}
}
}
}
}
}

View file

@ -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

View file

@ -0,0 +1,75 @@
/* This file is part of the KDE project
Copyright (C) 2023 Ivailo Monev <xakepa10@gmail.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License version 2, as published by the Free Software Foundation.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "jobswidget.h"
#include <Plasma/DataEngineManager>
#include <KDebug>
JobsWidget::JobsWidget(QGraphicsItem *parent, NotificationsWidget *notificationswidget)
: QGraphicsWidget(parent),
m_notificationswidget(notificationswidget),
m_layout(nullptr),
m_label(nullptr),
m_dataengine(nullptr)
{
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
m_layout = new QGraphicsLinearLayout(Qt::Vertical, this);
m_layout->setContentsMargins(0, 0, 0, 0);
m_label = new Plasma::Label(this);
m_label->setText(i18n("No job notifications"));
m_label->setAlignment(Qt::AlignCenter);
m_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
m_layout->addItem(m_label);
setLayout(m_layout);
m_dataengine = Plasma::DataEngineManager::self()->loadEngine("applicationjobs");
if (!m_dataengine) {
kWarning() << "Could not load applicationjobs data engine";
return;
}
connect(
m_dataengine, SIGNAL(sourceAdded(QString)),
this, SLOT(sourceAdded(QString))
);
}
JobsWidget::~JobsWidget()
{
if (m_dataengine) {
Plasma::DataEngineManager::self()->unloadEngine("applicationjobs");
}
}
int JobsWidget::count() const
{
return 0;
}
void JobsWidget::sourceAdded(const QString &name)
{
qDebug() << Q_FUNC_INFO << name;
m_dataengine->connectSource(name, this);
}
void JobsWidget::dataUpdated(const QString &name, const Plasma::DataEngine::Data &data)
{
// qDebug() << Q_FUNC_INFO << name << data;
}
#include "moc_jobswidget.cpp"

View file

@ -0,0 +1,53 @@
/* This file is part of the KDE project
Copyright (C) 2023 Ivailo Monev <xakepa10@gmail.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License version 2, as published by the Free Software Foundation.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef JOBSWIDGET_H
#define JOBSWIDGET_H
#include <QGraphicsWidget>
#include <QGraphicsLinearLayout>
#include <Plasma/Label>
#include <Plasma/DataEngine>
class NotificationsWidget;
class JobsWidget : public QGraphicsWidget
{
Q_OBJECT
public:
JobsWidget(QGraphicsItem *parent, NotificationsWidget *notificationswidget);
~JobsWidget();
int count() const;
Q_SIGNALS:
int countChanged();
private Q_SLOTS:
void sourceAdded(const QString &name);
void dataUpdated(const QString &name, const Plasma::DataEngine::Data &data);
private:
NotificationsWidget *m_notificationswidget;
QGraphicsLinearLayout* m_layout;
Plasma::Label* m_label;
Plasma::DataEngine *m_dataengine;
};
#endif // JOBSWIDGET_H

View file

@ -0,0 +1,119 @@
/* This file is part of the KDE project
Copyright (C) 2023 Ivailo Monev <xakepa10@gmail.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License version 2, as published by the Free Software Foundation.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "notifications.h"
#include "jobswidget.h"
#include "applicationswidget.h"
#include <Plasma/TabBar>
#include <Plasma/ScrollWidget>
#include <KIcon>
#include <KDebug>
static const QSizeF s_minimumsize = QSizeF(290, 140);
class NotificationsWidget : public Plasma::TabBar
{
Q_OBJECT
public:
NotificationsWidget(NotificationsApplet* notifications);
~NotificationsWidget();
private Q_SLOTS:
void slotCountChanged();
private:
NotificationsApplet* m_notifications;
Plasma::ScrollWidget* m_jobsscrollwidget;
JobsWidget* m_jobswidget;
Plasma::ScrollWidget* m_applicationsscrollwidget;
ApplicationsWidget* m_applicationswidget;
Plasma::Label* m_notificationslabel;
};
NotificationsWidget::NotificationsWidget(NotificationsApplet* notifications)
: Plasma::TabBar(notifications),
m_notifications(notifications),
m_jobswidget(nullptr),
m_applicationswidget(nullptr)
{
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
setMinimumSize(s_minimumsize);
m_jobsscrollwidget = new Plasma::ScrollWidget(this);
m_jobsscrollwidget->setMinimumSize(s_minimumsize);
m_jobswidget = new JobsWidget(m_jobsscrollwidget, this);
connect(
m_jobswidget, SIGNAL(countChanged()),
this, SLOT(slotCountChanged())
);
m_jobsscrollwidget->setWidget(m_jobswidget);
addTab(KIcon("services"), i18n("Jobs"), m_jobsscrollwidget);
m_applicationsscrollwidget = new Plasma::ScrollWidget(this);
m_applicationsscrollwidget->setMinimumSize(s_minimumsize);
m_applicationswidget = new ApplicationsWidget(m_applicationsscrollwidget, this);
connect(
m_applicationswidget, SIGNAL(countChanged()),
this, SLOT(slotCountChanged())
);
m_applicationsscrollwidget->setWidget(m_applicationswidget);
addTab(KIcon("dialog-information"), i18n("Notifications"), m_applicationsscrollwidget);
m_notifications->setStatus(Plasma::ItemStatus::PassiveStatus);
}
NotificationsWidget::~NotificationsWidget()
{
}
void NotificationsWidget::slotCountChanged()
{
const int totalcount = (m_jobswidget->count() + m_applicationswidget->count());
if (totalcount > 0) {
m_notifications->setStatus(Plasma::ItemStatus::ActiveStatus);
} else {
m_notifications->setStatus(Plasma::ItemStatus::PassiveStatus);
}
}
NotificationsApplet::NotificationsApplet(QObject *parent, const QVariantList &args)
: Plasma::PopupApplet(parent, args),
m_notificationswidget(nullptr)
{
KGlobal::locale()->insertCatalog("plasma_applet_notifications");
setAspectRatioMode(Plasma::AspectRatioMode::IgnoreAspectRatio);
m_notificationswidget = new NotificationsWidget(this);
setPopupIcon("preferences-desktop-notification");
}
NotificationsApplet::~NotificationsApplet()
{
delete m_notificationswidget;
}
QGraphicsWidget* NotificationsApplet::graphicsWidget()
{
return m_notificationswidget;
}
K_EXPORT_PLASMA_APPLET(notifications, NotificationsApplet)
#include "moc_notifications.cpp"
#include "notifications.moc"

View file

@ -0,0 +1,41 @@
/* This file is part of the KDE project
Copyright (C) 2023 Ivailo Monev <xakepa10@gmail.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License version 2, as published by the Free Software Foundation.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef NOTIFICATIONS_H
#define NOTIFICATIONS_H
#include <Plasma/PopupApplet>
class NotificationsWidget;
class NotificationsApplet : public Plasma::PopupApplet
{
Q_OBJECT
public:
NotificationsApplet(QObject *parent, const QVariantList &args);
~NotificationsApplet();
// Plasma::PopupApplet reimplementation
QGraphicsWidget* graphicsWidget() final;
private:
friend NotificationsWidget;
NotificationsWidget *m_notificationswidget;
};
#endif // NOTIFICATIONS_H

View file

@ -153,12 +153,11 @@ 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-Name=notifications
X-KDE-PluginInfo-Version=1.0
X-KDE-PluginInfo-Website=
X-KDE-ServiceTypes=Plasma/PopupApplet,Plasma/Applet
X-Plasma-API=declarativeappletscript
X-KDE-Library=plasma_applet_notifications
X-Plasma-DefaultSize=100,100
X-Plasma-MainScript=ui/main.qml
X-Plasma-RequiredExtensions=LaunchApp
X-Plasma-NotificationArea=true

View file

@ -28,7 +28,7 @@ var ICONS_SIZE = 24 // Size of icons, icons are square i.e. width == height
var MINIMUM_SIZE = 8 // minimum size of widget
var ARROW_MARGINS = 5 // margins for an arrow
var BLINK_INTERVAL = 750 // time interval of blinking
var TASK_NOTIFICATIONS_TYPEID = "org.kde.notifications"
var TASK_NOTIFICATIONS_TYPEID = "notifications"
var USE_GRID_IN_POPUP = false // true if in popup icons should be placed like a grid without names

View file

@ -683,8 +683,8 @@ void Applet::checkDefaultApplets()
s_manager->addApplet("devicenotifier", this);
}
if (!applets.contains("org.kde.notifications")) {
s_manager->addApplet("org.kde.notifications", this);
if (!applets.contains("notifications")) {
s_manager->addApplet("notifications", this);
}
if (!applets.contains("keyboard")) {

View file

@ -3,7 +3,6 @@ add_subdirectory(apps)
add_subdirectory(dict)
add_subdirectory(geolocation)
add_subdirectory(notifications)
add_subdirectory(powermanagement)
add_subdirectory(soliddevice)
add_subdirectory(time)
add_subdirectory(weather)

View file

@ -1,27 +0,0 @@
set(powermanagement_engine_SRCS
powermanagementengine.cpp
powermanagementjob.cpp
powermanagementservice.cpp
)
set(krunner_xml ${CMAKE_SOURCE_DIR}/krunner/dbus/org.kde.krunner.App.xml)
QT4_ADD_DBUS_INTERFACE(powermanagement_engine_SRCS ${krunner_xml} krunner_interface)
kde4_add_plugin(plasma_engine_powermanagement ${powermanagement_engine_SRCS})
target_link_libraries(plasma_engine_powermanagement
KDE4::kdecore
KDE4::solid
KDE4::plasma
KDE4::kidletime
kworkspace
)
install(
TARGETS plasma_engine_powermanagement
DESTINATION ${KDE4_PLUGIN_INSTALL_DIR}
)
install(
FILES plasma-dataengine-powermanagement.desktop
DESTINATION ${KDE4_SERVICES_INSTALL_DIR}
)

View file

@ -1,147 +0,0 @@
[Desktop Entry]
# ctxt: plasma data engine
Name=Power Management
Name[ar]=إدارة الطاقة
Name[ast]=Xestión d'enerxía
Name[bg]=Управление на захранването
Name[bn]=ি
Name[bs]=upravljanje napajanjem
Name[ca]=Gestió d'energia
Name[ca@valencia]=Gestió d'energia
Name[cs]=Správa napájení
Name[csb]=Sprôwianié mòcą
Name[da]=Strømstyring
Name[de]=Energieverwaltung
Name[el]=Διαχείριση ενέργειας
Name[en_GB]=Power Management
Name[eo]=Energia administrado
Name[es]=Gestión de energía
Name[et]=Toitehaldus
Name[eu]=Energia-kudeaketa
Name[fi]=Virranhallinta
Name[fr]=Gestion de l'énergie
Name[fy]=Enerzjybehear
Name[ga]=Bainisteoireacht Cumhachta
Name[gl]=Xestión da enerxía
Name[gu]=
Name[he]=ניהול צריכת חשמל
Name[hi]=ि
Name[hr]=Upravljanje potrošnjom energije
Name[hu]=Energiakezelő
Name[ia]=Gestion de energia
Name[id]=Manajemen Daya
Name[is]=Orkustýring
Name[it]=Gestione energetica
Name[ja]=
Name[kk]=Қуаттандыруды басқару
Name[km]=
Name[kn]=ಿಿ ಿ
Name[ko]=
Name[lt]=Energijos valdymas
Name[lv]=Energokontrole
Name[mk]=Менаџмент на енергија
Name[ml]=ി ി
Name[mr]=
Name[nb]=Strømstyring
Name[nds]=Stroomkuntrull
Name[nl]=Energiebeheer
Name[nn]=Straumstyring
Name[pa]= ਿ
Name[pl]=Zarządzanie energią
Name[pt]=Gestão de Energia
Name[pt_BR]=Gerenciamento de energia
Name[ro]=Gestiunea alimentării
Name[ru]=Управление питанием
Name[si]=
Name[sk]=Správa napájania
Name[sl]=Upravljanje z energijo
Name[sr]=управљање напајањем
Name[sr@ijekavian]=управљање напајањем
Name[sr@ijekavianlatin]=upravljanje napajanjem
Name[sr@latin]=upravljanje napajanjem
Name[sv]=Strömsparhantering
Name[tg]=Идоракунии барқ
Name[th]=
Name[tr]=Güç Yönetimi
Name[ug]=توك مەنبەسىنى باشقۇرۇش
Name[uk]=Керування живленням
Name[wa]=Manaedjmint di l' enerdjeye
Name[x-test]=xxPower Managementxx
Name[zh_CN]=
Name[zh_TW]=
Comment=Battery, AC, sleep and PowerDevil information.
Comment[ar]=معلومات البطارية والتيار المتناوب والنوم وعفريت الطاقة.
Comment[ast]=Información de batería, CA, hibernación y PowerDevil.
Comment[bg]=Данни за батерия, AC, приспиване и PowerDevil
Comment[bs]=Podaci iz Strujnog đavola o bateriji, ACu, i spavanju.
Comment[ca]=Informació de la bateria, AC, suspensió i del PowerDevil.
Comment[ca@valencia]=Informació de la bateria, AC, suspensió i del PowerDevil.
Comment[cs]=Informace o baterii, AC a uspání.
Comment[da]=Information om batteri, strømforsyning, dvale og PowerDevil.
Comment[de]=Informationen zu Akku, Netzanschluss, Ruhezustand und PowerDevil.
Comment[el]=Πληροφορίες μπαταρίας, AC, αδράνειας και PowerDevil
Comment[en_GB]=Battery, AC, sleep and PowerDevil information.
Comment[es]=Información de batería, CA, hibernación y PowerDevil.
Comment[et]=Aku, voolutoite, puhkeseisundi ja PowerDevili teave.
Comment[eu]=Bateria, korronte alternoa, loa eta PowerDevil-i buruzko informazioa.
Comment[fi]=Akku, vaihtovirta, nukkumis- ja PowerDevil-tiedot.
Comment[fr]=Batterie, chargeur, veille et informations sur PowerDevil
Comment[fy]=Batterij, AC, sliepe en PowerDevil ynformaasje
Comment[ga]=Faisnéis a bhaineann leis an gcadhnra, ceangal SA, codladh agus PowerDevil.
Comment[gl]=Información da batería, corrente, hibernación e PowerDevil.
Comment[he]=מידע אודות סוללה, צריכת חשמל, מצב שינה ו־PowerDevil.
Comment[hr]=Informacije o bateriji, adapteru, spavanju i PowerDevilu.
Comment[hu]=A telepek, a tápellátás és a PowerDevil energiakezelő jellemzői.
Comment[ia]=Batteria, AC, reposo e information de PowerDevil.
Comment[id]=Informasi Baterai, AC, tidur dan PowerDevil.
Comment[is]=Upplýsingar um raflöður, AC-straum, svæfingu og PowerDevil orkustýringarpúkann.
Comment[it]=Informazioni su batteria, alimentazione, sospensione e PowerDevil
Comment[ja]=PowerDevil
Comment[kk]=Батарея, тоқ, ұйықтау күйі және PowerDevil мәліметі.
Comment[km]= AC PowerDevil 
Comment[kn]=ಿ, AC, PowerDevil ಿಿ.
Comment[ko]=, AC, PowerDevil .
Comment[lt]=Akumuliatoriaus, AC, miego ir PowerDevil informacija.
Comment[lv]=Baterija, barošana, gulēšanas un PowerDevil informācija.
Comment[ml]=ി, ി, ി ി ി ി.
Comment[mr]=, AC, ि ि.
Comment[nb]=Informasjon om batteri, nettstrøm, hvilemodus og PowerDevil.
Comment[nds]=Batterie-, Stroom-, Utsett- un Stroomdüvel-Infos
Comment[nl]=Accu-, stroomvoorziening-, slaapstand- en PowerDevil-informatie.
Comment[nn]=Informasjon om batteristatus, lading og liknande.
Comment[pa]=, , ਿ
Comment[pl]=Bateria, zasilacz, usypianie i informacje PowerDevil.
Comment[pt]=Informação sobre a bateria, corrente eléctrica e o PowerDevil.
Comment[pt_BR]=Bateria, adaptador de energia, dormir e informação do PowerDevil.
Comment[ro]=Informații despre acumulator, priză, adormire și PowerDevil.
Comment[ru]=Информация о батарее, электрической сети и PowerDevil.
Comment[si]=, AC, PowerDevil
Comment[sk]=Informácie o batérii, AC a uspaní.
Comment[sl]=Podatki o baterijah, omrežnem napajanju, pripravljenosti in PowerDevilu.
Comment[sr]=Подаци из Струјног ђавола о батерији, АЦу, и спавању.
Comment[sr@ijekavian]=Подаци из Струјног ђавола о батерији, АЦу, и спавању.
Comment[sr@ijekavianlatin]=Podaci iz Strujnog đavola o bateriji, ACu, i spavanju.
Comment[sr@latin]=Podaci iz Strujnog đavola o bateriji, ACu, i spavanju.
Comment[sv]=Information om batteri, nätspänning, viloläge och Powerdevil.
Comment[tg]=Батарея, AC, захираи барқ ва иттилооти PowerDevil.
Comment[th]=, , PowerDevil
Comment[tr]=Pil, Adaptör, uyku kipi ve PowerDevil bilgileri.
Comment[ug]=توكدان، ئۆزگىرىشچان توك مەنبەسى، سىستېما ئۇخلات ۋە PowerDevil ئۇچۇرىنى تەمىنلەيدۇ.
Comment[uk]=Акумулятор, мережеве живлення, відомості щодо присипляння і PowerDevil.
Comment[vi]=Thông tin pin, AC, chế đ ng và PowerDevil
Comment[wa]=Pondants et djondants sol batreye, l' AC, l' edoirmaedje eyet l' Diâle d' Enerdjeye.
Comment[x-test]=xxBattery, AC, sleep and PowerDevil information.xx
Comment[zh_CN]= PowerDevil
Comment[zh_TW]= PowerDevil
X-KDE-ServiceTypes=Plasma/DataEngine
Type=Service
Icon=preferences-system-power-management
X-KDE-Library=plasma_engine_powermanagement
X-KDE-PluginInfo-Author=
X-KDE-PluginInfo-Email=
X-KDE-PluginInfo-Name=powermanagement
X-KDE-PluginInfo-Version=
X-KDE-PluginInfo-Website=
X-KDE-PluginInfo-Category=
X-KDE-PluginInfo-Depends=

View file

@ -1,109 +0,0 @@
/*
* Copyright 2007 Aaron Seigo <aseigo@kde.org>
* Copyright 2007-2008 Sebastian Kuegler <sebas@kde.org>
* CopyRight 2007 Maor Vanmak <mvanmak1@gmail.com>
* Copyright 2008 Dario Freddi <drf54321@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 version 2 as
* published by the Free Software Foundation
*
* 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 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.
*/
#include "powermanagementengine.h"
#include "powermanagementservice.h"
#include <QDBusConnectionInterface>
#include <QDBusConnection>
#include <QDBusMetaType>
#include <KDebug>
#include <KLocale>
#include <KStandardDirs>
#include <KIdleTime>
#include <Solid/PowerManagement>
#include <Plasma/DataContainer>
typedef QMap< QString, QString > StringStringMap;
Q_DECLARE_METATYPE(StringStringMap)
PowermanagementEngine::PowermanagementEngine(QObject* parent, const QVariantList& args)
: Plasma::DataEngine(parent, args)
{
qDBusRegisterMetaType<StringStringMap>();
m_sources << "Sleep States" << "PowerDevil";
}
void PowermanagementEngine::init()
{
if (QDBusConnection::sessionBus().interface()->isServiceRegistered("org.freedesktop.PowerManagement")) {
sourceRequestEvent("PowerDevil");
}
}
QStringList PowermanagementEngine::sources() const
{
return m_sources;
}
bool PowermanagementEngine::sourceRequestEvent(const QString &name)
{
if (name == "Sleep States") {
const QSet<Solid::PowerManagement::SleepState> sleepstates = Solid::PowerManagement::supportedSleepStates();
// We first set all possible sleepstates to false, then enable the ones that are available
setData("Sleep States", "Suspend", false);
setData("Sleep States", "Hibernate", false);
setData("Sleep States", "Hybrid Suspend", false);
foreach (const Solid::PowerManagement::SleepState &sleepstate, sleepstates) {
if (sleepstate == Solid::PowerManagement::SuspendState) {
setData("Sleep States", "Suspend", true);
} else if (sleepstate == Solid::PowerManagement::HibernateState) {
setData("Sleep States", "Hibernate", true);
} else if (sleepstate == Solid::PowerManagement::HybridSuspendState) {
setData("Sleep States", "Hybrid Suspend", true);
}
//kDebug() << "Sleepstate \"" << sleepstate << "\" supported.";
}
} else if (name == "PowerDevil") {
;
//any info concerning lock screen/screensaver goes here
} else if (name == "UserActivity") {
setData("UserActivity", "IdleTime", KIdleTime::instance()->idleTime());
} else {
kDebug() << "Data for '" << name << "' not found";
return false;
}
return true;
}
bool PowermanagementEngine::updateSourceEvent(const QString &source)
{
if (source == "UserActivity") {
setData("UserActivity", "IdleTime", KIdleTime::instance()->idleTime());
return true;
}
return Plasma::DataEngine::updateSourceEvent(source);
}
Plasma::Service* PowermanagementEngine::serviceForSource(const QString &source)
{
if (source == "PowerDevil") {
return new PowerManagementService(this);
}
return nullptr;
}
K_EXPORT_PLASMA_DATAENGINE(powermanagement, PowermanagementEngine)
#include "moc_powermanagementengine.cpp"

View file

@ -1,48 +0,0 @@
/*
* Copyright 2007 Aaron Seigo <aseigo@kde.org>
* Copyright 2007-2008 Sebastian Kuegler <sebas@kde.org>
* Copyright 2008 Dario Freddi <drf54321@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 version 2 as
* published by the Free Software Foundation
*
* 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 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.
*/
#ifndef POWERMANAGEMENTENGINE_H
#define POWERMANAGEMENTENGINE_H
#include <Plasma/DataEngine>
/**
* This class provides power management in Plasma applets.
*/
class PowermanagementEngine : public Plasma::DataEngine
{
Q_OBJECT
public:
PowermanagementEngine(QObject *parent, const QVariantList &args);
QStringList sources() const;
Plasma::Service* serviceForSource(const QString &source);
protected:
bool sourceRequestEvent(const QString &name);
bool updateSourceEvent(const QString &source);
void init();
private:
QStringList m_sources;
};
#endif // POWERMANAGEMENTENGINE_H

View file

@ -1,115 +0,0 @@
/*
* Copyright 2011 Sebastian Kügler <sebas@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 version 2 as
* published by the Free Software Foundation
*
* 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 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.
*/
#include <QDBusConnection>
#include <QDBusInterface>
#include <QDBusMessage>
#include <QDBusPendingReply>
// kde-workspace/libs
#include <kworkspace/kworkspace.h>
#include <krunner_interface.h>
#include "powermanagementjob.h"
#include <kdebug.h>
#include <Solid/PowerManagement>
PowerManagementJob::PowerManagementJob(const QString &operation, const QMap<QString, QVariant> &parameters, QObject *parent) :
ServiceJob(parent->objectName(), operation, parameters, parent)
{
}
PowerManagementJob::~PowerManagementJob()
{
}
void PowerManagementJob::start()
{
const QString operation = operationName();
//kDebug() << "starting operation ... " << operation;
if (operation == "lockScreen") {
static const QString interface("org.freedesktop.ScreenSaver");
QDBusInterface screensaver(interface, "/ScreenSaver");
QDBusPendingReply<void> reply = screensaver.asyncCall("Lock");
if (reply.isError()) {
setResult(false);
return;
}
setResult(true);
return;
} else if (operation == "suspendToRam") {
if (!Solid::PowerManagement::supportedSleepStates().contains(Solid::PowerManagement::SuspendState)) {
setResult(false);
return;
}
Solid::PowerManagement::requestSleep(Solid::PowerManagement::SuspendState);
setResult(true);
return;
} else if (operation == "suspendToDisk") {
if (!Solid::PowerManagement::supportedSleepStates().contains(Solid::PowerManagement::HibernateState)) {
setResult(false);
return;
}
Solid::PowerManagement::requestSleep(Solid::PowerManagement::HibernateState);
setResult(true);
return;
} else if (operation == "suspendHybrid") {
if (!Solid::PowerManagement::supportedSleepStates().contains(Solid::PowerManagement::HybridSuspendState)) {
setResult(false);
return;
}
Solid::PowerManagement::requestSleep(Solid::PowerManagement::HybridSuspendState);
setResult(true);
return;
} else if (operation == "requestShutDown") {
if (!KWorkSpace::canShutDown()) {
setResult(false);
return;
}
KWorkSpace::requestShutDown();
setResult(true);
return;
} else if (operation == "switchUser") {
// Taken from kickoff/core/itemhandlers.cpp
org::kde::krunner::App krunner("org.kde.krunner", "/App", QDBusConnection::sessionBus());
krunner.switchUser();
setResult(true);
return;
} else if (operation == "beginSuppressingSleep") {
setResult(Solid::PowerManagement::beginSuppressingSleep(parameters().value("reason").toString()));
return;
} else if (operation == "stopSuppressingSleep") {
setResult(Solid::PowerManagement::stopSuppressingSleep(parameters().value("cookie").toUInt()));
return;
} else if (operation == "beginSuppressingScreenPowerManagement") {
setResult(Solid::PowerManagement::beginSuppressingScreenPowerManagement(parameters().value("reason").toString()));
return;
} else if (operation == "stopSuppressingScreenPowerManagement") {
setResult(Solid::PowerManagement::stopSuppressingScreenPowerManagement(parameters().value("cookie").toUInt()));
return;
}
kDebug() << "don't know what to do with " << operation;
setResult(false);
}
#include "moc_powermanagementjob.cpp"

View file

@ -1,39 +0,0 @@
/*
* Copyright 2011 Sebastian Kügler <sebas@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 version 2 as
* published by the Free Software Foundation
*
* 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 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.
*/
#ifndef POWERMANAGEMENTJOB_H
#define POWERMANAGEMENTJOB_H
// plasma
#include <Plasma/ServiceJob>
class PowerManagementJob : public Plasma::ServiceJob
{
Q_OBJECT
public:
PowerManagementJob(const QString &operation, const QMap<QString, QVariant> &parameters,
QObject *parent = 0);
~PowerManagementJob();
protected:
void start();
};
#endif // POWERMANAGEMENTJOB_H

View file

@ -1,48 +0,0 @@
/*
* Copyright 2011 Sebastian Kügler <sebas@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 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 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.
*/
#include "powermanagementservice.h"
#include "powermanagementjob.h"
PowerManagementService::PowerManagementService(QObject *parent)
: Plasma::Service(parent)
{
setName("powermanagementservice");
setOperationNames(
QStringList()
<< "lockScreen"
<< "suspendToRam"
<< "suspendToDisk"
<< "suspendHybrid"
<< "requestShutDown"
<< "switchUser"
<< "beginSuppressingSleep"
<< "stopSuppressingSleep"
<< "beginSuppressingScreenPowerManagement"
<< "stopSuppressingScreenPowerManagement"
);
}
ServiceJob *PowerManagementService::createJob(const QString &operation,
const QMap<QString, QVariant> &parameters)
{
return new PowerManagementJob(operation, parameters, this);
}
#include "moc_powermanagementservice.cpp"

View file

@ -1,39 +0,0 @@
/*
* Copyright 2011 Sebastian Kügler <sebas@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 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 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.
*/
#ifndef POWERMANAGEMENTSERVICE_H
#define POWERMANAGEMENTSERVICE_H
#include <Plasma/Service>
#include <Plasma/ServiceJob>
using namespace Plasma;
class PowerManagementService : public Plasma::Service
{
Q_OBJECT
public:
PowerManagementService(QObject *parent = 0);
ServiceJob *createJob(const QString &operation, const QMap<QString, QVariant> &parameters);
};
#endif // POWERMANAGEMENTSERVICE_H

View file

@ -1,53 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2011 Marco Martin <mart@kde.org>
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Components project.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
** the names of its contributors may be used to endorse or promote
** products derived from this software without specific prior written
** permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
** $QT_END_LICENSE$
**
****************************************************************************/
import QtQuick 1.1
import org.kde.plasma.components 0.1
/**
* Provides a component with list of options that the user can choose from.
*
* All elements of this component are defined in Menu, its base component.
*/
Menu {
id: root
}

View file

@ -1,135 +0,0 @@
/*
* Copyright 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, 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 "private/Config.js" as Config
/**
* An item delegate for the primitive ListView component.
*
* It's intended to make all listviews look coherent.
*/
Item {
id: listItem
default property alias content: paddingItem.data
/**
* type:bool Holds if the item emits signals related to mouse interaction.
*
* The default value is false.
*/
property alias enabled: itemMouse.enabled
//item has been clicked or pressed+hold
/**
* This signal is emitted when there is a click.
*
* This is disabled by default, set enabled to true to use it.
* @see enabled
*/
signal clicked
/**
* The user pressed the item with the mouse and didn't release it for a
* certain amount of time.
*
* This is disabled by default, set enabled to true to use it.
* @see enabled
*/
signal pressAndHold
/**
* If true makes the list item look as checked or pressed. It has to be set
* from the code, it won't change by itself.
*/
//plasma extension
//always look pressed?
property bool checked: false
/**
* If true the item will be a delegate for a section, so will look like a
* "title" for the otems under it.
*/
//is this to be used as section delegate?
property bool sectionDelegate: false
width: parent ? parent.width : childrenRect.width
height: paddingItem.childrenRect.height + background.margins.top + background.margins.bottom
property int implicitHeight: paddingItem.childrenRect.height + background.margins.top + background.margins.bottom
Connections {
target: listItem
onCheckedChanged: background.prefix = (listItem.checked ? "pressed" : "normal")
onSectionDelegateChanged: background.prefix = (listItem.sectionDelegate ? "section" : "normal")
}
PlasmaCore.FrameSvgItem {
id : background
imagePath: "widgets/listitem"
prefix: "normal"
anchors.fill: parent
visible: listItem.ListView.view ? listItem.ListView.view.highlight === null : true
opacity: itemMouse.containsMouse && !itemMouse.pressed ? 0.5 : 1
Component.onCompleted: {
prefix = (listItem.sectionDelegate ? "section" : (listItem.checked ? "pressed" : "normal"))
}
Behavior on opacity { NumberAnimation { duration: 200 } }
}
PlasmaCore.SvgItem {
svg: PlasmaCore.Svg {imagePath: "widgets/listitem"}
elementId: "separator"
anchors {
left: parent.left
right: parent.right
top: parent.top
}
height: naturalSize.height
visible: listItem.sectionDelegate || (typeof(index) != "undefined" && index > 0 && !listItem.checked && !itemMouse.pressed)
}
MouseArea {
id: itemMouse
property bool changeBackgroundOnPress: !listItem.checked && !listItem.sectionDelegate
anchors.fill: background
enabled: false
hoverEnabled: Config.mouseOverEnabled
onClicked: listItem.clicked()
onPressAndHold: listItem.pressAndHold()
onPressed: if (changeBackgroundOnPress) background.prefix = "pressed"
onReleased: if (changeBackgroundOnPress) background.prefix = "normal"
onCanceled: if (changeBackgroundOnPress) background.prefix = "normal"
}
Item {
id: paddingItem
anchors {
fill: background
leftMargin: background.margins.left
topMargin: background.margins.top
rightMargin: background.margins.right
bottomMargin: background.margins.bottom
}
}
}

View file

@ -1,175 +0,0 @@
/*
* Copyright (C) 2011 by Daker Fernandes Pinheiro <dakerfp@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 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.qtextracomponents 0.1
/**
* Simple progressBar using the plasma theme.
*
* Some operations take a period of time to be performed and the user needs a
* confirmation that the operation is still ongoing. If the user does not get
* any confirmation, they might suspect that they did something wrong or that
* the device has broken. A progress bar is one of the available mechanisms for
* providing this reassurance to the user.
*/
Item {
id: progressBar
// Common API
/** type:real Minimum value for the progressBar */
property alias minimumValue: range.minimumValue
/** type:real Maximum value for the progressBar */
property alias maximumValue: range.maximumValue
/** type:real Current value of the progressBar */
property alias value: range.value
/**
* type:bool
* Indicates whether the operation's duration is known or not. The property
* can have the following values:
*
* - true: the operation's duration is unknown, so the progress bar is
* animated. The value, minimum, and maximum properties are ignored.
* - false: the operation's duration is known, so the progress bar is drawn
* to indicate progress between the minimum and maximum values.
*
* The default value is false.
*/
property alias indeterminate: indeterminateAnimation.running
// Plasma API
/**
* Orientation of the progressBar: Qt.Horizontal or Qt.Vertical
*/
property int orientation: Qt.Horizontal
width: 100
height: 20
opacity: enabled ? 1.0 : 0.5
RangeModel {
id: range
// default values
minimumValue: 0.0
maximumValue: 1.0
value: 0
positionAtMinimum: 0
positionAtMaximum: backgroundPixmapItem.width
}
Item {
id: contents
property bool _isVertical: orientation == Qt.Vertical
property int _tileWidth: width
width: _isVertical ? progressBar.height : progressBar.width
height: _isVertical ? progressBar.width : progressBar.height
rotation: _isVertical ? 90 : 0
anchors.centerIn: parent
Timer {
id: resizeTimer
repeat: false
interval: 0
running: false
onTriggered: {
contents._tileWidth = Math.floor(contents.width/(Math.floor(contents.width/(contents.height/1.6))))
if (barFrameSvg.hasElement("hint-bar-stretch")) {
barFrameSvg.resizeFrame(Qt.size(barPixmapItem.width, barPixmapItem.height))
} else {
barFrameSvg.resizeFrame(Qt.size(contents._tileWidth, contents.height))
}
barPixmapItem.pixmap = barFrameSvg.framePixmap()
if (backgroundFrameSvg.hasElement("hint-bar-stretch")) {
backgroundFrameSvg.resizeFrame(Qt.size(backgroundPixmapItem.width, backgroundPixmapItem.height))
} else {
backgroundFrameSvg.resizeFrame(Qt.size(contents._tileWidth, contents.height))
}
backgroundPixmapItem.pixmap = backgroundFrameSvg.framePixmap()
}
}
PlasmaCore.FrameSvg {
id: barFrameSvg
Component.onCompleted: {
barFrameSvg.setImagePath("widgets/bar_meter_horizontal")
barFrameSvg.setElementPrefix("bar-active")
resizeTimer.restart()
}
}
PlasmaCore.FrameSvg {
id: backgroundFrameSvg
Component.onCompleted: {
backgroundFrameSvg.setImagePath("widgets/bar_meter_horizontal")
backgroundFrameSvg.setElementPrefix("bar-inactive")
resizeTimer.restart()
}
}
QPixmapItem {
id: backgroundPixmapItem
anchors.fill: parent
fillMode: QPixmapItem.TileHorizontally
onWidthChanged: resizeTimer.restart()
onHeightChanged: resizeTimer.restart()
}
QPixmapItem {
id: barPixmapItem
fillMode: QPixmapItem.TileHorizontally
width: indeterminate ? contents._tileWidth*2 : range.position
height: contents.height
visible: indeterminate || value > 0
onWidthChanged: resizeTimer.restart()
onHeightChanged: resizeTimer.restart()
SequentialAnimation {
id: indeterminateAnimation
loops: Animation.Infinite
onRunningChanged: {
if (!running) {
barPixmapItem.x = 0
}
}
PropertyAnimation {
target: barPixmapItem
property: "x"
duration: 800
to: 0
}
PropertyAnimation {
target: barPixmapItem
property: "x"
duration: 800
to: backgroundPixmapItem.width - barPixmapItem.width
}
}
}
}
}

View file

@ -1,258 +0,0 @@
/*
* Copyright 2012 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, 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
/**
* This item takes a Flickable and automatically puts scrollbars in adjusting
* the layout if needed. The scrollbars will be interactive or not, depending
* on the platform. If flickableItem is a categorized ListView the vertical
* scrollbar will be a SectionScroller.
*/
Item {
id: root
/**
* The Flickable of this area: it can be either a Flickable or a subclass,
* ListView or GridView
*/
property Flickable flickableItem
//FIXME: this alias seems necessary for it to correctly parse
default property alias flickableItemDefault: root.flickableItem
Connections {
target: root
onFlickableItemChanged: {
root.flickableItem.parent = root
root.flickableItem.anchors.fill = root
root.flickableItem.clip = true
internal.checkVerticalScrollBar()
internal.checkHorizontalScrollBar()
}
}
Component.onCompleted: {
root.flickableItem.parent = root
root.flickableItem.anchors.fill = root
root.flickableItem.clip = true
internal.checkVerticalScrollBar()
internal.checkHorizontalScrollBar()
}
Connections {
target: flickableItem
onContentHeightChanged: internal.checkVerticalScrollBar()
onHeightChanged: internal.checkVerticalScrollBar()
onContentWidthChanged: internal.checkHorizontalScrollBar()
onWidthChanged: internal.checkHorizontalScrollBar()
}
QtObject {
id: internal
property Item verticalScrollBar
property Item horizontalScrollBar
function checkVerticalScrollBar() {
if (!flickableItem) {
return
}
if (flickableItem.contentHeight > flickableItem.height) {
//Do we have to change the type?
//from section to normal
if ((!flickableItem.model || flickableItem.model.get === undefined || !flickableItem.section || !flickableItem.section.property) &&
(!verticalScrollBar || verticalScrollBar.orientation === undefined)) {
if (verticalScrollBar) verticalScrollBar.destroy()
verticalScrollBar = verticalScrollBarComponent.createObject(root)
//from normal to section
} else if (flickableItem.section && flickableItem.section.property &&
flickableItem.model.get !== undefined &&
(!verticalScrollBar || verticalScrollBar.orientation !== undefined)) {
if (verticalScrollBar) verticalScrollBar.destroy()
verticalScrollBar = sectionScrollerComponent.createObject(root)
}
}
checkVerticalScrollBarMargins()
}
function checkVerticalScrollBarMargins() {
//undefined in case of SectionScroller
if ((flickableItem.contentHeight > flickableItem.height) && verticalScrollBar &&
((verticalScrollBar.interactive && verticalScrollBar.visible) || (verticalScrollBar.orientation === undefined &&
//FIXME: heuristic on width to distinguish the touch sectionscroller
verticalScrollBar.width < 30))) {
flickableItem.anchors.rightMargin = verticalScrollBar.width
} else {
flickableItem.anchors.rightMargin = 0
}
}
function checkHorizontalScrollBar() {
if (!flickableItem || horizontalScrollBar) {
return
}
if (flickableItem.contentWidth > flickableItem.width) {
if (!horizontalScrollBar) {
horizontalScrollBar = horizontalScrollBarComponent.createObject(root)
}
}
checkHorizontalScrollBarMargins()
}
function checkHorizontalScrollBarMargins() {
if ((flickableItem.contentWidth > flickableItem.width) &&
horizontalScrollBar && horizontalScrollBar.interactive && horizontalScrollBar.visible) {
flickableItem.anchors.bottomMargin = horizontalScrollBar.height
} else {
flickableItem.anchors.bottomMargin = 0
}
}
}
Component {
id: verticalScrollBarComponent
ScrollBar {
flickableItem: root.flickableItem
orientation: Qt.Vertical
property bool isScrollBar: true
z: root.flickableItem.z + 1
anchors {
left: undefined
top: root.top
right: root.right
bottom: root.bottom
bottomMargin: root.height - root.flickableItem.height
}
onVisibleChanged: internal.checkVerticalScrollBarMargins()
}
}
Component {
id: horizontalScrollBarComponent
ScrollBar {
flickableItem: root.flickableItem
orientation: Qt.Horizontal
z: root.flickableItem.z + 1
anchors {
left: root.left
top: undefined
right: root.right
bottom: root.bottom
rightMargin: root.width - root.flickableItem.width
}
onVisibleChanged: internal.checkHorizontalScrollBarMargins()
}
}
Component {
id: sectionScrollerComponent
SectionScroller {
listView: root.flickableItem
property bool isScrollBar: false
z: root.flickableItem.z + 1
anchors {
left: undefined
top: root.top
right: root.right
bottom: root.bottom
bottomMargin: root.height - root.flickableItem.height
}
onVisibleChanged: internal.checkVerticalScrollBarMargins()
}
}
//FIXME: create all this stuff only on demand, like scrollbars?
PlasmaCore.Svg {
id: borderSvg
imagePath: "widgets/scrollwidget"
}
PlasmaCore.SvgItem {
svg: borderSvg
z: 1000
elementId: "border-top"
width: 100
height: naturalSize.height
opacity: flickableItem.atYBeginning ? 0 : 1
Behavior on opacity {
NumberAnimation {
duration: 250
easing.type: Easing.InOutQuad
}
}
anchors {
left: parent.left
top: parent.top
right: parent.right
topMargin: flickableItem.anchors.topMargin
}
}
PlasmaCore.SvgItem {
svg: borderSvg
z: 1000
elementId: "border-bottom"
width: 100
height: naturalSize.height
opacity: flickableItem.atYEnd ? 0 : 1
Behavior on opacity {
NumberAnimation {
duration: 250
easing.type: Easing.InOutQuad
}
}
anchors {
left: parent.left
bottom: parent.bottom
right: parent.right
bottomMargin: flickableItem.anchors.bottomMargin
}
}
PlasmaCore.SvgItem {
svg: borderSvg
z: 1000
elementId: "border-left"
width: naturalSize.width
opacity: flickableItem.atXBeginning ? 0 : 1
Behavior on opacity {
NumberAnimation {
duration: 250
easing.type: Easing.InOutQuad
}
}
anchors {
left: parent.left
top: parent.top
bottom: parent.bottom
leftMargin: flickableItem.anchors.leftMargin
}
}
PlasmaCore.SvgItem {
svg: borderSvg
z: 1000
elementId: "border-right"
width: naturalSize.width
opacity: flickableItem.atXEnd ? 0 : 1
Behavior on opacity {
NumberAnimation {
duration: 250
easing.type: Easing.InOutQuad
}
}
anchors {
top: parent.top
bottom: parent.bottom
right: parent.right
rightMargin: flickableItem.anchors.rightMargin
}
}
}

View file

@ -1,218 +0,0 @@
/*
* Copyright (C) 2011 by Daker Fernandes Pinheiro <dakerfp@gmail.com>
* Copyright (C) 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, 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 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 "private" as Private
/**
* A simple Scroll Bar using the plasma theme.
*
* This component does not belong to the QtComponents API specification but it
* was based on the ScrollDecorator component. You should not use it for touch
* interfaces, use a flickable and a ScrollDecorator instead.
*
* By default, this component looks and behaves like a scroll decorator
* on touchscreens.
*/
// TODO: add support mouse wheel events
Item {
id: scrollbar
// Common API
/**
* The Flickable component which the ScrollBar will interact with.
*/
property Flickable flickableItem: null
/**
* The orientation where the ScrollBar will scroll.
* The orientation * can be either Qt.Horizontal or Qt.Vertical.
*
* The default value is Qt.Vertical.
*/
property int orientation: Qt.Vertical
/**
* Whether the ScrollBar is interactive.
*
* The default value is true.
*/
property bool interactive: true
// Plasma API
/**
* Whether the ScrollBar will increase the Flickable content in the normal
* direction (Left to Right or Top to Bottom) or if this will be inverted.
*
* The default value is false.
*/
property bool inverted: false
/**
* type:real
* How many steps exist while moving the handler. If you want the
* ScrollBar buttons to appear you must set this property to a value
* bigger than 0.
*
* The default value is 0.
*/
property alias stepSize: range.stepSize
/**
* Indicates if the ScrollBar is pressed.
*/
property bool pressed: internalLoader.item.mouseArea?internalLoader.item.mouseArea.pressed:false
/**
* The interval time used by the ScrollBar button to increase or decrease
* steps.
*/
property real scrollButtonInterval: 50
implicitWidth: internalLoader.isVertical ? (internalLoader.item ? internalLoader.item.implicitWidth : 12) : 200
implicitHeight: internalLoader.isVertical ? 200 : (internalLoader.item ? internalLoader.item.implicitHeight : 12)
// TODO: needs to define if there will be specific graphics for
// disabled scroll bars
opacity: enabled ? 1.0 : 0.5
visible: flickableItem && internalLoader.handleEnabled
anchors {
right: internalLoader.anchorableWithFlickable ? flickableItem.right : undefined
left: (orientation == Qt.Vertical) ? undefined : (internalLoader.anchorableWithFlickable ? flickableItem.left : undefined)
top: (orientation == Qt.Vertical) ? (internalLoader.anchorableWithFlickable ? flickableItem.top : undefined) : undefined
bottom: internalLoader.anchorableWithFlickable ? flickableItem.bottom : undefined
}
Loader {
id: internalLoader
anchors.fill: parent
//property bool handleEnabled: internalLoader.isVertical ? item.handle.height < item.contents.height : item.handle.width < item.contents.width
property bool handleEnabled: internalLoader.isVertical ? flickableItem.contentHeight > flickableItem.height : flickableItem.contentWidth > flickableItem.width
property bool isVertical: orientation == Qt.Vertical
property bool anchorableWithFlickable: scrollbar.parent == flickableItem || scrollbar.parent == flickableItem.parent
function incrementValue(increment)
{
if (!flickableItem) {
return;
}
if (internalLoader.isVertical) {
flickableItem.contentY = Math.max(0, Math.min(flickableItem.contentHeight - flickableItem.height,
flickableItem.contentY + increment));
} else {
flickableItem.contentX = Math.max(0, Math.min(flickableItem.contentWidth - flickableItem.width,
flickableItem.contentX + increment));
}
}
Connections {
target: flickableItem
onContentHeightChanged: {
range.value = flickableItem.contentY;
}
onContentYChanged: {
if (internalLoader.isVertical) {
range.value = flickableItem.contentY;
}
}
onContentXChanged: {
if (!internalLoader.isVertical) {
range.value = flickableItem.contentX;
}
}
}
Connections {
target: internalLoader.item.handle
onYChanged: updateFromHandleTimer.running = true
onXChanged: updateFromHandleTimer.running = true
}
RangeModel {
id: range
minimumValue: 0
maximumValue: {
var diff;
if (internalLoader.isVertical) {
diff = flickableItem.contentHeight - flickableItem.height;
} else {
diff = flickableItem.contentWidth - flickableItem.width;
}
return Math.max(0, diff);
}
stepSize: 10
inverted: scrollbar.inverted
positionAtMinimum: 0
positionAtMaximum: {
if (internalLoader.isVertical) {
internalLoader.item.contents.height - internalLoader.item.handle.height;
} else {
internalLoader.item.contents.width - internalLoader.item.handle.width;
}
}
onValueChanged: {
if (flickableItem.moving) {
return;
}
if (internalLoader.isVertical) {
flickableItem.contentY = value;
} else {
flickableItem.contentX = value;
}
}
onPositionChanged: {
if (internalLoader.item.mouseArea && internalLoader.item.mouseArea.pressed) {
return;
}
if (internalLoader.isVertical) {
internalLoader.item.handle.y = position;
} else {
internalLoader.item.handle.x = position; }
}
}
Timer {
id: updateFromHandleTimer
interval: 10
onTriggered: {
if (!enabled || !interactive) {
return;
}
if (internalLoader.isVertical) {
range.position = internalLoader.item.handle.y;
} else {
range.position = internalLoader.item.handle.x;
}
}
}
source: interactive ? "private/ScrollBarDelegate.qml" : "private/ScrollDecoratorDelegate.qml"
}
}

View file

@ -1,176 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Components project.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
** the names of its contributors may be used to endorse or promote
** products derived from this software without specific prior written
** permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
** $QT_END_LICENSE$
**
****************************************************************************/
import QtQuick 1.1
import "private/SectionScroller.js" as Sections
import org.kde.plasma.core 0.1 as PlasmaCore
/**
* Similar to a ScrollBar or a ScrollDecorator.
*
* It's interactive and works on ListViews that have section.property set, so
* its contents are categorized.
*
* An indicator will say to what category the user scrolled to. Useful for
* things like address books or things sorted by date. Don't use with models
* too big (thousands of items) because it implies loading all the items to
* memory, as well loses precision.
*/
Item {
id: root
/**
* The listview the sectionScroller will operate on. This component doesn't
* work with Flickable or GridView.
*/
property ListView listView
onListViewChanged: {
if (listView && listView.model)
internal.initDirtyObserver();
}
Connections {
target: listView
onModelChanged: {
if (listView && listView.model) {
internal.initDirtyObserver()
}
}
}
implicitWidth: scrollBar.implicitWidth
Behavior on opacity {
NumberAnimation {
duration: 250
}
}
anchors {
right: listView.right
top: listView.top
bottom: listView.bottom
}
RangeModel {
id: range
minimumValue: 0
maximumValue: Math.max(0, listView.contentHeight - listView.height)
stepSize: 0
//inverted: true
positionAtMinimum: root.width*2
positionAtMaximum: root.height - root.width*2
value: listView.contentY
onPositionChanged: sectionLabel.text = Sections.closestSection(position/listView.height)
}
ScrollBar {
id: scrollBar
flickableItem: listView
anchors.fill: parent
interactive: true
}
PlasmaCore.FrameSvgItem {
id: tooltip
imagePath: "widgets/tooltip"
width: sectionLabel.width + margins.left + margins.right
height: sectionLabel.height + margins.top + margins.bottom
Label {
id: sectionLabel
x: parent.margins.left
y: parent.margins.top
}
y: Math.min(root.height-height-scrollBar.width, Math.max(scrollBar.width, range.position - height/2))
anchors {
//verticalCenter: handle.verticalCenter
right: parent.left
}
opacity: sectionLabel.text && scrollBar.pressed ? 1 : 0
Behavior on opacity {
NumberAnimation {
duration: 250
}
}
}
Timer {
id: dirtyTimer
interval: 250
onTriggered: {
Sections.initSectionData(listView);
internal.modelDirty = false;
tooltip.visible = Sections._sections.length > 1
}
}
QtObject {
id: internal
property bool modelDirty: false
function initDirtyObserver() {
Sections.initSectionData(listView);
tooltip.visible = Sections._sections.length > 1
function dirtyObserver() {
if (!internal.modelDirty) {
internal.modelDirty = true;
dirtyTimer.running = true;
}
}
if (listView.model.countChanged)
listView.model.countChanged.connect(dirtyObserver);
if (listView.model.itemsChanged)
listView.model.itemsChanged.connect(dirtyObserver);
if (listView.model.itemsInserted)
listView.model.itemsInserted.connect(dirtyObserver);
if (listView.model.itemsMoved)
listView.model.itemsMoved.connect(dirtyObserver);
if (listView.model.itemsRemoved)
listView.model.itemsRemoved.connect(dirtyObserver);
}
}
}

View file

@ -1,44 +0,0 @@
/*
* Copyright 2012 by Sebastian Kügler <sebas@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, 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
/**
* This is a title label which uses the plasma theme. The characteristics of
* the text will be automatically set according to the plasma theme. Use this
* components for titles in your UI, for example page or section titles.
*
* Example usage:
* @code
* import org.kde.plasma.components 0.1 as PlasmaComponents
* [...]
* Column {
* PlasmaComponents.Title { text: "Fruit sweetness on the rise" }
* [...]
* }
* @endcode
*
* See PlasmaComponents Label and primitive QML Text element API for additional
* properties, methods and signals.
*/
Label {
id: root
font.pointSize: theme.defaultFont.pointSize*2
}

View file

@ -1,20 +0,0 @@
/*
* Copyright (C) 2012 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, 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 mouseOverEnabled = true

View file

@ -1,267 +0,0 @@
/*
* Copyright (C) 2011 by Daker Fernandes Pinheiro <dakerfp@gmail.com>
* Copyright (C) 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, 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 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
PlasmaCore.FrameSvgItem {
id: background
anchors.fill: parent
imagePath:"widgets/scrollbar"
prefix: internalLoader.isVertical ? "background-vertical" : "background-horizontal"
property int implicitWidth: scrollbarSvg.hasElement("hint-scrollbar-size") ? scrollbarSvg.elementSize("hint-scrollbar-size").width : scrollbarSvg.elementSize("arrow-up").width
property int implicitHeight: scrollbarSvg.hasElement("hint-scrollbar-size") ? scrollbarSvg.elementSize("hint-scrollbar-size").height : scrollbarSvg.elementSize("arrow-left").height
Keys.onUpPressed: {
if (!enabled || !internalLoader.isVertical)
return;
if (inverted)
internalLoader.incrementValue(stepSize);
else
internalLoader.incrementValue(-stepSize);
}
Keys.onDownPressed: {
if (!enabled || !internalLoader.isVertical)
return;
if (inverted)
internalLoader.incrementValue(-stepSize);
else
internalLoader.incrementValue(stepSize);
}
Keys.onLeftPressed: {
if (!enabled || internalLoader.isVertical)
return;
if (inverted)
internalLoader.incrementValue(stepSize);
else
internalLoader.incrementValue(-stepSize);
}
Keys.onRightPressed: {
if (!enabled || internalLoader.isVertical)
return;
if (inverted)
internalLoader.incrementValue(-stepSize);
else
internalLoader.incrementValue(stepSize);
}
property Item handle: handle
property Item contents: contents
Item {
id: contents
anchors {
fill: parent
leftMargin: (!internalLoader.isVertical && leftButton.visible) ? leftButton.width : 0
rightMargin: (!internalLoader.isVertical && rightButton.visible) ? rightButton.width : 0
topMargin: (internalLoader.isVertical && leftButton.visible) ? leftButton.height : 0
bottomMargin: (internalLoader.isVertical && rightButton.visible) ? rightButton.height : 0
}
PlasmaCore.FrameSvgItem {
id: handle
imagePath:"widgets/scrollbar"
prefix: {
if (mouseArea.pressed) {
return "sunken-slider"
}
if (scrollbar.activeFocus || mouseArea.containsMouse) {
return "mouseover-slider"
} else {
return "slider"
}
}
property int length: internalLoader.isVertical? flickableItem.visibleArea.heightRatio * parent.height : flickableItem.visibleArea.widthRatio * parent.width
width: internalLoader.isVertical ? parent.width : length
height: internalLoader.isVertical ? length : parent.height
}
}
PlasmaCore.Svg {
id: scrollbarSvg
imagePath: "widgets/scrollbar"
property bool arrowPresent: scrollbarSvg.hasElement("arrow-up")
//new theme may be different
onRepaintNeeded: arrowPresent = scrollbarSvg.hasElement("arrow-up")
}
PlasmaCore.SvgItem {
id: leftButton
visible: stepSize > 0 && scrollbarSvg.arrowPresent
anchors {
left: internalLoader.isVertical ? undefined : parent.left
verticalCenter: internalLoader.isVertical ? undefined : parent.verticalCenter
top: internalLoader.isVertical ? parent.top : undefined
horizontalCenter: internalLoader.isVertical ? parent.horizontalCenter : undefined
}
width: 18
height: 18
svg: scrollbarSvg
elementId: {
if (leftMouseArea.pressed) {
return internalLoader.isVertical ? "sunken-arrow-up" : "sunken-arrow-left"
}
if (scrollbar.activeFocus || leftMouseArea.containsMouse) {
return internalLoader.isVertical ? "mouseover-arrow-up" : "mouseover-arrow-left"
} else {
return internalLoader.isVertical ? "arrow-up" : "arrow-left"
}
}
MouseArea {
id: leftMouseArea
anchors.fill: parent
enabled: scrollbar.enabled
hoverEnabled: true
Timer {
id: leftTimer
interval: scrollbar.scrollButtonInterval;
running: parent.pressed
repeat: true
triggeredOnStart: true
onTriggered: {
background.forceActiveFocus()
if (inverted) {
internalLoader.incrementValue(stepSize);
} else {
internalLoader.incrementValue(-stepSize);
}
}
}
}
}
PlasmaCore.SvgItem {
id: rightButton
visible: leftButton.visible
anchors {
right: internalLoader.isVertical ? undefined : parent.right
verticalCenter: internalLoader.isVertical ? undefined : parent.verticalCenter
bottom: internalLoader.isVertical ? parent.bottom : undefined
horizontalCenter: internalLoader.isVertical ? parent.horizontalCenter : undefined
}
width: 18
height: 18
svg: scrollbarSvg
elementId: {
if (rightMouseArea.pressed) {
return internalLoader.isVertical ? "sunken-arrow-down" : "sunken-arrow-right"
}
if (scrollbar.activeFocus || rightMouseArea.containsMouse) {
return internalLoader.isVertical ? "mouseover-arrow-down" : "mouseover-arrow-right"
} else {
return internalLoader.isVertical ? "arrow-down" : "arrow-right"
}
}
MouseArea {
id: rightMouseArea
anchors.fill: parent
enabled: scrollbar.enabled
hoverEnabled: true
Timer {
id: rightTimer
interval: scrollbar.scrollButtonInterval;
running: parent.pressed;
repeat: true
triggeredOnStart: true
onTriggered: {
background.forceActiveFocus();
if (inverted)
internalLoader.incrementValue(-stepSize);
else
internalLoader.incrementValue(stepSize);
}
}
}
}
property MouseArea mouseArea: mouseArea
MouseArea {
id: mouseArea
anchors.fill: contents
enabled: scrollbar.enabled
hoverEnabled: true
drag {
target: handle
axis: internalLoader.isVertical ? Drag.YAxis : Drag.XAxis
minimumX: range.positionAtMinimum
maximumX: range.positionAtMaximum
minimumY: range.positionAtMinimum
maximumY: range.positionAtMaximum
}
onPressed: {
if (internalLoader.isVertical) {
// Clamp the value
var newY = Math.max(mouse.y, drag.minimumY);
newY = Math.min(newY, drag.maximumY);
// Debounce the press: a press event inside the handler will not
// change its position, the user needs to drag it.
if (newY > handle.y + handle.height) {
handle.y = mouse.y - handle.height
} else if (newY < handle.y) {
handle.y = mouse.y
}
} else {
// Clamp the value
var newX = Math.max(mouse.x, drag.minimumX);
newX = Math.min(newX, drag.maximumX);
// Debounce the press: a press event inside the handler will not
// change its position, the user needs to drag it.
if (newX > handle.x + handle.width) {
handle.x = mouse.x - handle.width
} else if (newX < handle.x) {
handle.x = mouse.x
}
}
background.forceActiveFocus();
}
Component.onCompleted: {
acceptedButtons |= Qt.MiddleButton
}
}
}

View file

@ -1,122 +0,0 @@
/*
* Copyright (C) 2011 by Daker Fernandes Pinheiro <dakerfp@gmail.com>
* Copyright (C) 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, 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 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
PlasmaCore.FrameSvgItem {
id: background
anchors.fill: parent
imagePath:"widgets/scrollbar"
prefix: internalLoader.isVertical ? "background-vertical" : "background-horizontal"
property int implicitWidth: scrollbarSvg.hasElement("hint-scrollbar-size") ? scrollbarSvg.elementSize("hint-scrollbar-size").width : 12
property int implicitHeight: scrollbarSvg.hasElement("hint-scrollbar-size") ? scrollbarSvg.elementSize("hint-scrollbar-size").height : 12
opacity: 0
Behavior on opacity {
NumberAnimation {
duration: 250
easing.type: Easing.OutQuad
}
}
PlasmaCore.Svg {
id: scrollbarSvg
imagePath: "widgets/scrollbar"
}
property Item handle: handle
property Item contents: contents
Item {
id: contents
anchors.fill: parent
PlasmaCore.FrameSvgItem {
id: handle
imagePath:"widgets/scrollbar"
prefix: "slider"
function length()
{
var nh, ny;
if (internalLoader.isVertical) {
nh = flickableItem.visibleArea.heightRatio * internalLoader.height
} else {
nh = flickableItem.visibleArea.widthRatio * internalLoader.width
}
if (internalLoader.isVertical) {
ny = flickableItem.visibleArea.yPosition * internalLoader.height
} else {
ny = flickableItem.visibleArea.xPosition * internalLoader.width
}
if (ny > 3) {
var t
if (internalLoader.isVertical) {
t = Math.ceil(internalLoader.height - 3 - ny)
} else {
t = Math.ceil(internalLoader.width - 3 - ny)
}
if (nh > t) {
return t
} else {
return nh
}
} else {
return nh + ny
}
}
width: internalLoader.isVertical ? parent.width : length()
height: internalLoader.isVertical ? length() : parent.height
}
}
property MouseArea mouseArea: null
Connections {
target: flickableItem
onMovingChanged: {
if (flickableItem.moving) {
opacityTimer.running = false
background.opacity = 1
} else {
opacityTimer.restart()
}
}
}
Timer {
id: opacityTimer
interval: 500
repeat: false
running: false
onTriggered: {
background.opacity = 0
}
}
}

View file

@ -1,71 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Components project.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
** the names of its contributors may be used to endorse or promote
** products derived from this software without specific prior written
** permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
** $QT_END_LICENSE$
**
****************************************************************************/
var _sectionData = [];
var _sections = [];
function initSectionData(list) {
if (!list || !list.model) return;
_sectionData = [];
_sections = [];
var current = "";
var prop = list.section.property;
for (var i = 0, count = list.model.count; i < count; i++) {
var item = list.model.get(i);
if (item[prop] !== current) {
current = item[prop];
_sections.push(current);
_sectionData.push({ index: i, header: current });
}
}
}
function closestSection(pos) {
var tmp = (_sections.length) * pos;
var val = Math.ceil(tmp) // TODO: better algorithm
val = val < 2 ? 1 : val;
return _sections[val-1];
}
function indexOf(sectionName) {
var val = _sectionData[_sections.indexOf(sectionName)].index;
return val === 0 || val > 0 ? val : -1;
}

View file

@ -3,16 +3,9 @@ plugin plasmacomponentsplugin
BusyIndicator 0.1 BusyIndicator.qml
Button 0.1 Button.qml
ButtonGroup 0.1 ButtonGroup.js
ContextMenu 0.1 ContextMenu.qml
Highlight 0.1 Highlight.qml
Label 0.1 Label.qml
ListItem 0.1 ListItem.qml
ProgressBar 0.1 ProgressBar.qml
ScrollBar 0.1 ScrollBar.qml
SectionScroller 0.1 SectionScroller.qml
TabBar 0.1 TabBar.qml
TabButton 0.1 TabButton.qml
TabGroup 0.1 TabGroup.qml
ToolButton 0.1 ToolButton.qml
ScrollArea 0.1 ScrollArea.qml
Title 0.1 Title.qml

View file

@ -79,7 +79,7 @@ DialogWidth=302
[Containments][1][Applets][5][Configuration][Applets][9]
geometry=0,0,24,24
immutability=1
plugin=org.kde.notifications
plugin=notifications
zvalue=0
[Containments][1][Applets][5][Configuration][Applets][9][PopupApplet]