You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

350 lines
10 KiB

/***************************************************************************
* *
* Copyright 2013 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 General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . *
***************************************************************************/
#include "host.h"
#include "task.h"
#include "debug.h"
#include "protocol.h"
#include <klocalizedstring.h>
#include <Plasma/Package>
#include <Plasma/PluginLoader>
#include <QLoggingCategory>
#include <QQuickItem>
#include <QTimer>
#include <QVariant>
#include <zlib.h>
#include "protocols/plasmoid/plasmoidprotocol.h"
#include "protocols/dbussystemtray/dbussystemtrayprotocol.h"
#define TIMEOUT 100
namespace SystemTray
{
static QHash<Task::Category, int> s_taskWeights;
bool taskLessThan(const Task *lhs, const Task *rhs)
{
/* Sorting of systemtray icons
*
* We sort (and thus group) in the following order, from high to low priority
* - Notifications always comes first
* - Category
* - Name
*/
const QString _not = QStringLiteral("org.kde.plasma.notifications");
if (lhs->taskId() == _not) {
return true;
}
if (rhs->taskId() == _not) {
return false;
}
if (lhs->category() != rhs->category()) {
if (s_taskWeights.isEmpty()) {
s_taskWeights.insert(Task::Communications, 0);
s_taskWeights.insert(Task::SystemServices, 1);
s_taskWeights.insert(Task::Hardware, 2);
s_taskWeights.insert(Task::ApplicationStatus, 3);
s_taskWeights.insert(Task::UnknownCategory, 4);
}
return s_taskWeights.value(lhs->category()) < s_taskWeights.value(rhs->category());
}
return lhs->name() < rhs->name();
}
class HostPrivate {
public:
HostPrivate(Host *host)
: q(host),
rootItem(0)
{
}
void setupProtocol(Protocol *protocol);
bool showTask(Task *task);
Host *q;
QList<Task *> tasks;
QQuickItem* rootItem;
// Keep references to the list to avoid full refreshes
//QList<SystemTray::Task*> tasks;
QList<SystemTray::Task*> shownTasks;
QList<SystemTray::Task*> hiddenTasks;
//all tasks that are in hidden categories
QList<SystemTray::Task*> discardedTasks;
QSet<Task::Category> shownCategories;
QQmlListProperty<SystemTray::Task> shownTasksDeclarative;
QQmlListProperty<SystemTray::Task> hiddenTasksDeclarative;
//QQmlListProperty<SystemTray::Task> tasksDeclarative;
QStringList categories;
QTimer compressionTimer;
};
Host::Host(QObject* parent) :
QObject(parent),
d(new HostPrivate(this))
{
// connect(m_manager, &Manager::tasksChanged, this, &Host::tasksChanged);
QTimer::singleShot(2000, this, SLOT(init())); // FIXME: remove timer
//init();
connect(&d->compressionTimer, &QTimer::timeout, this, &Host::compressionTimeout);
}
Host::~Host()
{
delete d;
}
void Host::init()
{
initTasks();
d->setupProtocol(new SystemTray::DBusSystemTrayProtocol(this));
d->setupProtocol(new SystemTray::PlasmoidProtocol(this));
emit categoriesChanged();
}
void Host::compressionTimeout()
{
qCDebug(SYSTEMTRAY) << "ST2 tasksChanged";
emit tasksChanged();
d->compressionTimer.stop();
}
void Host::initTasks()
{
QList<SystemTray::Task*> allTasks = tasks();
foreach (SystemTray::Task *task, allTasks) {
if (d->showTask(task)) {
d->shownTasks.append(task);
} else {
d->hiddenTasks.append(task);
}
}
qSort(d->shownTasks.begin(), d->shownTasks.end(), taskLessThan);
qSort(d->hiddenTasks.begin(), d->hiddenTasks.end(), taskLessThan);
QQmlListProperty<SystemTray::Task> _shown(this, d->shownTasks);
d->shownTasksDeclarative = _shown;
QQmlListProperty<SystemTray::Task> _hidden(this, d->hiddenTasks);
d->hiddenTasksDeclarative = _hidden;
qCDebug(SYSTEMTRAY) << "ST2 init starting timer" << TIMEOUT;
d->compressionTimer.start(TIMEOUT);
}
QQuickItem* Host::rootItem()
{
return d->rootItem;
}
void Host::setRootItem(QQuickItem* item)
{
if (d->rootItem == item) {
return;
}
d->rootItem = item;
emit rootItemChanged();
}
bool Host::isCategoryShown(int cat) const
{
return d->shownCategories.contains((Task::Category)cat);
}
void Host::setCategoryShown(int cat, bool shown)
{
if (shown) {
if (!d->shownCategories.contains((Task::Category)cat)) {
d->shownCategories.insert((Task::Category)cat);
foreach (Task *task, d->discardedTasks) {
if (d->shownCategories.contains(task->category())) {
addTask(task);
}
}
}
} else {
if (d->shownCategories.contains((Task::Category)cat)) {
d->shownCategories.remove((Task::Category)cat);
foreach (Task *task, d->tasks) {
if (!d->shownCategories.contains(task->category())) {
removeTask(task);
d->discardedTasks.append(task);
}
}
}
}
}
QList<Task*> Host::tasks() const
{
return d->tasks;
}
void Host::addTask(Task *task)
{
if (!d->shownCategories.contains(task->category())) {
d->discardedTasks.append(task);
return;
} else {
d->discardedTasks.removeAll(task);
}
connect(task, SIGNAL(destroyed(SystemTray::Task*)), this, SLOT(removeTask(SystemTray::Task*)));
connect(task, SIGNAL(changedStatus()), this, SLOT(slotTaskStatusChanged()));
qCDebug(SYSTEMTRAY) << "ST2" << task->name() << "(" << task->taskId() << ")";
d->tasks.append(task);
if (d->showTask(task)) {
d->shownTasks.append(task);
qSort(d->shownTasks.begin(), d->shownTasks.end(), taskLessThan);
} else {
d->hiddenTasks.append(task);
qSort(d->hiddenTasks.begin(), d->hiddenTasks.end(), taskLessThan);
}
d->compressionTimer.start(TIMEOUT);
emit tasksChanged();
}
void Host::removeTask(Task *task)
{
d->tasks.removeAll(task);
disconnect(task, 0, this, 0);
if (d->showTask(task)) {
d->shownTasks.removeAll(task);
} else {
d->hiddenTasks.removeAll(task);
}
// No compression here, as we delete the pointer to the task
// object behind the list's back otherwise
emit tasksChanged();
}
void Host::slotTaskStatusChanged()
{
Task* task = qobject_cast<Task*>(sender());
if (task) {
qCDebug(SYSTEMTRAY) << "ST2 emit taskStatusChanged(task);";
taskStatusChanged(task);
} else {
qCDebug(SYSTEMTRAY) << "ST2 changed, but invalid cast";
}
}
QQmlListProperty<SystemTray::Task> Host::hiddenTasks()
{
return d->hiddenTasksDeclarative;
}
QQmlListProperty< Task > Host::shownTasks()
{
return d->shownTasksDeclarative;
}
bool HostPrivate::showTask(Task *task) {
return task->shown() && task->status() != SystemTray::Task::Passive;
}
void HostPrivate::setupProtocol(Protocol *protocol)
{
QObject::connect(protocol, SIGNAL(taskCreated(SystemTray::Task*)), q, SLOT(addTask(SystemTray::Task*)));
protocol->init();
}
void Host::taskStatusChanged(SystemTray::Task *task)
{
if (task) {
if (d->shownTasks.contains(task)) {
if (!d->showTask(task)) {
qCDebug(SYSTEMTRAY) << "ST2 Migrating shown -> hidden" << task->name();
d->shownTasks.removeAll(task);
d->hiddenTasks.append(task);
qSort(d->hiddenTasks.begin(), d->hiddenTasks.end(), taskLessThan);
d->compressionTimer.start(TIMEOUT);
}
} else if (d->hiddenTasks.contains(task)) {
if (d->showTask(task)) {
qCDebug(SYSTEMTRAY) << "ST2 Migrating hidden -> shown" << task->name();
d->hiddenTasks.removeAll(task);
d->shownTasks.append(task);
qSort(d->shownTasks.begin(), d->shownTasks.end(), taskLessThan);
d->compressionTimer.start(TIMEOUT);
}
}
}
}
QStringList Host::categories() const
{
QList<SystemTray::Task*> allTasks = tasks();
QStringList cats;
QList<SystemTray::Task::Category> cnt;
foreach (SystemTray::Task *task, allTasks) {
const SystemTray::Task::Category c = task->category();
if (cnt.contains(c)) {
continue;
}
cnt.append(c);
if (c == SystemTray::Task::UnknownCategory) {
cats.append(i18n("Unknown Category"));
} else if (c == SystemTray::Task::ApplicationStatus) {
cats.append(i18n("Application Status"));
} else if (c == SystemTray::Task::Communications) {
cats.append(i18n("Communications"));
} else if (c == SystemTray::Task::SystemServices) {
cats.append(i18n("System Services"));
} else if (c == SystemTray::Task::Hardware) {
cats.append(i18n("Hardware"));
}
}
qCDebug(SYSTEMTRAY) << "ST2 " << cats;
return cats;
}
} // namespace
#include "host.moc"