diff --git a/app/settings/data/CMakeLists.txt b/app/settings/data/CMakeLists.txt index 8e10846ba..e56ba15ee 100644 --- a/app/settings/data/CMakeLists.txt +++ b/app/settings/data/CMakeLists.txt @@ -1,5 +1,6 @@ set(lattedock-app_SRCS - ${lattedock-app_SRCS} + ${lattedock-app_SRCS} + ${CMAKE_CURRENT_SOURCE_DIR}/activitydata.cpp ${CMAKE_CURRENT_SOURCE_DIR}/layoutdata.cpp ${CMAKE_CURRENT_SOURCE_DIR}/layoutstable.cpp PARENT_SCOPE diff --git a/app/settings/data/activitydata.cpp b/app/settings/data/activitydata.cpp new file mode 100644 index 000000000..d00eba84a --- /dev/null +++ b/app/settings/data/activitydata.cpp @@ -0,0 +1,83 @@ +/* + * Copyright 2020 Michail Vourlakos + * + * This file is part of Latte-Dock + * + * Latte-Dock 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. + * + * Latte-Dock 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, see . + * + */ + +#include "activitydata.h" + +namespace Latte { +namespace Settings { +namespace Data { + +Activity::Activity() +{ +} + +Activity::Activity(Activity &&o) + : id(o.id), + name(o.name), + icon(o.icon), + isCurrent(o.isCurrent), + state(o.state) +{ +} + +Activity::Activity(const Activity &o) + : id(o.id), + name(o.name), + icon(o.icon), + isCurrent(o.isCurrent), + state(o.state) +{ +} + +Activity &Activity::operator=(const Activity &rhs) +{ + id = rhs.id; + name = rhs.name; + icon = rhs.icon; + isCurrent = rhs.isCurrent; + state = rhs.state; + + return (*this); +} + +Activity &Activity::operator=(Activity &&rhs) +{ + id = rhs.id; + name = rhs.name; + icon = rhs.icon; + isCurrent = rhs.isCurrent; + state = rhs.state; + + return (*this); +} + +bool Activity::isValid() const +{ + return (state != KActivities::Info::Invalid); +} + +bool Activity::isRunning() const +{ + return ((state == KActivities::Info::Running) || (state == KActivities::Info::Starting)); +} + +} +} +} diff --git a/app/settings/data/activitydata.h b/app/settings/data/activitydata.h new file mode 100644 index 000000000..603507460 --- /dev/null +++ b/app/settings/data/activitydata.h @@ -0,0 +1,69 @@ +/* + * Copyright 2020 Michail Vourlakos + * + * This file is part of Latte-Dock + * + * Latte-Dock 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. + * + * Latte-Dock 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, see . + * + */ + +#ifndef SETTINGSDATAACTIVITY_H +#define SETTINGSDATAACTIVITY_H + +//! Qt +#include +#include +#include + +//! KActivities +#include + +namespace Latte { +namespace Settings { +namespace Data { + +class Activity +{ +public: + Activity(); + Activity(Activity &&o); + Activity(const Activity &o); + + //! Layout data + QString id; + QString name; + QString icon; + bool isCurrent; + KActivities::Info::State state; + + bool isValid() const; + bool isRunning() const; + + //! Operators + Activity &operator=(const Activity &rhs); + Activity &operator=(Activity &&rhs); +}; + +//! This is an Activities map in the following structure: +//! #activityId -> activite_information +typedef QHash ActivitiesMap; + +} +} +} + +Q_DECLARE_METATYPE(Latte::Settings::Data::Activity) +Q_DECLARE_METATYPE(Latte::Settings::Data::ActivitiesMap) + +#endif diff --git a/app/settings/delegates/activitiesdelegate.cpp b/app/settings/delegates/activitiesdelegate.cpp index 19bb7893f..824c7264e 100644 --- a/app/settings/delegates/activitiesdelegate.cpp +++ b/app/settings/delegates/activitiesdelegate.cpp @@ -21,6 +21,7 @@ // local #include "persistentmenu.h" +#include "../data/activitydata.h" #include "../data/layoutdata.h" #include "../models/layoutsmodel.h" #include "../tools/settingstools.h" @@ -36,9 +37,6 @@ #include #include -// KDE -#include -#include namespace Latte { namespace Settings { @@ -50,16 +48,6 @@ Activities::Activities(QObject *parent) { } -QString Activities::freeActivities_text() const -{ - return QString("[ " + i18n("All Free Activities...") + " ]"); -} - -QString Activities::freeActivities_icon() const -{ - return "favorites"; -} - QWidget *Activities::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const { QPushButton *button = new QPushButton(parent); @@ -69,31 +57,39 @@ QWidget *Activities::createEditor(QWidget *parent, const QStyleOptionViewItem &o menu->setMinimumWidth(option.rect.width()); bool isLayoutActive = index.data(Model::Layouts::LAYOUTISACTIVEROLE).toBool(); - QStringList allActivities = index.data(Model::Layouts::ALLACTIVITIESROLE).toStringList(); + + QStringList allActivities = index.data(Model::Layouts::ALLACTIVITIESSORTEDROLE).toStringList(); + Data::ActivitiesMap allActivitiesData = index.data(Model::Layouts::ALLACTIVITIESDATAROLE).value(); + QStringList assignedActivities = index.data(Qt::UserRole).toStringList(); for (int i = 0; i < allActivities.count(); ++i) { - if (allActivities[i] == Data::Layout::FREEACTIVITIESID) { - bool isFreeActivitiesChecked = assignedActivities.contains(Data::Layout::FREEACTIVITIESID); + Data::Activity activitydata = allActivitiesData[allActivities[i]]; + + if (!activitydata.isValid()) { + continue; + } - QAction *action = new QAction(freeActivities_text()); - action->setData(Data::Layout::FREEACTIVITIESID); - action->setIcon(QIcon::fromTheme(freeActivities_icon())); - action->setCheckable(true); - action->setChecked(isFreeActivitiesChecked); + bool ischecked = assignedActivities.contains(activitydata.id); + QAction *action = new QAction(activitydata.name); + action->setData(activitydata.id); + action->setIcon(QIcon::fromTheme(activitydata.icon)); + action->setCheckable(true); + action->setChecked(ischecked); + + if (activitydata.id == Data::Layout::FREEACTIVITIESID) { if (isLayoutActive) { QFont font = action->font(); font.setBold(true); action->setFont(font); } - menu->addAction(action); - if (isFreeActivitiesChecked) { + if (ischecked) { menu->setMasterIndex(i); } - connect(action, &QAction::toggled, this, [this, menu, button, action, i]() { + connect(action, &QAction::toggled, this, [this, menu, button, action, i, allActivitiesData]() { if (action->isChecked()) { menu->setMasterIndex(i); } else { @@ -102,38 +98,28 @@ QWidget *Activities::createEditor(QWidget *parent, const QStyleOptionViewItem &o } } - updateButton(button); + updateButton(button, allActivitiesData); }); } else { - KActivities::Info info(allActivities[i]); - - if (info.state() != KActivities::Info::Invalid) { - QAction *action = new QAction(info.name()); - action->setData(allActivities[i]); - action->setIcon(QIcon::fromTheme(info.icon())); - action->setCheckable(true); - action->setChecked(assignedActivities.contains(allActivities[i])); - - if ((info.state() == KActivities::Info::Running) || (info.state() == KActivities::Info::Starting)) { - QFont font = action->font(); - font.setBold(true); - action->setFont(font); - } - - menu->addAction(action); + if (activitydata.isRunning()) { + QFont font = action->font(); + font.setBold(true); + action->setFont(font); + } - connect(action, &QAction::toggled, this, [this, menu, button, action, i]() { - if (action->isChecked()) { - menu->setMasterIndex(-1); - } + connect(action, &QAction::toggled, this, [this, menu, button, action, i, allActivitiesData]() { + if (action->isChecked()) { + menu->setMasterIndex(-1); + } - updateButton(button); - }); - } + updateButton(button, allActivitiesData); + }); } + + menu->addAction(action); } - connect(menu, &PersistentMenu::masterIndexChanged, this, [this, menu, button]() { + connect(menu, &PersistentMenu::masterIndexChanged, this, [this, menu, button, allActivitiesData]() { int masterRow = menu->masterIndex(); if (masterRow>=0) { auto actions = button->menu()->actions(); @@ -152,7 +138,7 @@ QWidget *Activities::createEditor(QWidget *parent, const QStyleOptionViewItem &o } } - updateButton(button); + updateButton(button, allActivitiesData); }); return button; @@ -160,7 +146,9 @@ QWidget *Activities::createEditor(QWidget *parent, const QStyleOptionViewItem &o void Activities::setEditorData(QWidget *editor, const QModelIndex &index) const { - updateButton(editor); + Data::ActivitiesMap allActivitiesData = index.data(Model::Layouts::ALLACTIVITIESDATAROLE).value(); + + updateButton(editor, allActivitiesData); } void Activities::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const @@ -183,7 +171,7 @@ void Activities::updateEditorGeometry(QWidget *editor, const QStyleOptionViewIte } bool Activities::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, - const QModelIndex &index) + const QModelIndex &index) { Q_ASSERT(event); Q_ASSERT(model); @@ -209,7 +197,14 @@ void Activities::paint(QPainter *painter, const QStyleOptionViewItem &option, co if (!isSharedCapable) { painter->save(); - QStringList assignedActivities = index.model()->data(index, Qt::UserRole).toStringList(); + QList assignedActivities; + QStringList assignedIds = index.model()->data(index, Qt::UserRole).toStringList(); + + Data::ActivitiesMap allActivitiesData = index.data(Model::Layouts::ALLACTIVITIESDATAROLE).value(); + + for (int i=0; i 0) { myOptions.text = joinedActivities(assignedActivities, isLayoutActive); @@ -299,42 +294,33 @@ void Activities::paint(QPainter *painter, const QStyleOptionViewItem &option, co } } -QString Activities::joinedActivities(const QStringList &activities, bool isActive, bool formatText) const +QString Activities::joinedActivities(const QList &activities, bool isActive, bool formatText) const { QString finalText; int i = 0; - for (const auto &activityId : activities) { - QString name; + for (int i=0; i 0) { - finalText += ", "; - } - i++; - - if (formatText && ((info.state() == KActivities::Info::Running) || (info.state() == KActivities::Info::Starting))) { - bold = true; - } - - name = info.name(); + if (formatText && activities[i].isRunning()) { + bold = true; } } - QString styledText = name; + if (i > 0) { + finalText += ", "; + } + + + QString styledText = activities[i].name; if (bold && formatText) { styledText = "" + styledText + ""; @@ -350,17 +336,18 @@ QString Activities::joinedActivities(const QStringList &activities, bool isActiv return finalText; } -void Activities::updateButton(QWidget *editor) const +void Activities::updateButton(QWidget *editor, const Data::ActivitiesMap &allActivitiesData) const { if (!editor) { return; } + QPushButton *button = static_cast(editor); - QStringList assignedActivities; + QList assignedActivities; foreach (QAction *action, button->menu()->actions()) { if (action->isChecked()) { - assignedActivities << action->data().toString(); + assignedActivities << allActivitiesData[action->data().toString()]; } } diff --git a/app/settings/delegates/activitiesdelegate.h b/app/settings/delegates/activitiesdelegate.h index 16a3b891b..fc8d9717c 100644 --- a/app/settings/delegates/activitiesdelegate.h +++ b/app/settings/delegates/activitiesdelegate.h @@ -20,6 +20,9 @@ #ifndef ACTIVITIESDELEGATE_H #define ACTIVITIESDELEGATE_H +// local +#include "../data/activitydata.h" + // Qt #include @@ -46,12 +49,9 @@ public: virtual bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) override; private: - void updateButton(QWidget *editor) const; - - QString freeActivities_text() const; - QString freeActivities_icon() const; + void updateButton(QWidget *editor, const Data::ActivitiesMap &allActivitiesData) const; - QString joinedActivities(const QStringList &activities, bool isActive = false, bool formatText = true) const; + QString joinedActivities(const QList &activities, bool isActive = false, bool formatText = true) const; }; } diff --git a/app/settings/models/layoutsmodel.cpp b/app/settings/models/layoutsmodel.cpp index c9145c32b..18dbe6fad 100644 --- a/app/settings/models/layoutsmodel.cpp +++ b/app/settings/models/layoutsmodel.cpp @@ -33,6 +33,10 @@ // KDE #include +// KActivities +#include +#include + const QChar CheckMark{0x2714}; namespace Latte { @@ -43,6 +47,8 @@ Layouts::Layouts(QObject *parent, Latte::Corona *corona) : QAbstractTableModel(parent), m_corona(corona) { + initActivities(); + connect(this, &Layouts::inMultipleModeChanged, this, [&]() { QVector roles; roles << Qt::DisplayRole; @@ -57,6 +63,11 @@ Layouts::Layouts(QObject *parent, Latte::Corona *corona) connect(m_corona->layoutsManager(), &Latte::Layouts::Manager::centralLayoutsChanged, this, &Layouts::updateActiveStates); } +Layouts::~Layouts() +{ + qDeleteAll(m_activitiesInfo); +} + bool Layouts::containsCurrentName(const QString &name) const { return m_layoutsTable.containsCurrentName(name); @@ -324,11 +335,15 @@ QVariant Layouts::data(const QModelIndex &index, int role) const return inMultipleMode(); } else if (role == LAYOUTNAMEWASEDITEDROLE) { return m_layoutsTable[row].nameWasEdited(); - } else if (role == ALLACTIVITIESROLE) { + } else if (role == ALLACTIVITIESSORTEDROLE) { QStringList activities; activities << QString(Data::Layout::FREEACTIVITIESID); activities << m_corona->layoutsManager()->synchronizer()->activities(); return activities; + } else if (role == ALLACTIVITIESDATAROLE) { + QVariant activitiesData; + activitiesData.setValue(m_activitiesMap); + return activitiesData; } else if (role == ALLLAYOUTSROLE) { QVariant layouts; layouts.setValue(m_layoutsTable); @@ -681,6 +696,107 @@ void Layouts::setCurrentData(Data::LayoutsTable &data) emit rowsInserted(); } + +//! Activities code +void Layouts::initActivities() +{ + Data::Activity freeActivities; + freeActivities.id = Data::Layout::FREEACTIVITIESID; + freeActivities.name = QString("[ " + i18n("All Free Activities...") + " ]"); + freeActivities.icon = "favorites"; + freeActivities.state = KActivities::Info::Stopped; + m_activitiesMap[Data::Layout::FREEACTIVITIESID] = freeActivities; + + QStringList activities = m_corona->layoutsManager()->synchronizer()->activities();; + + for(const auto &id: activities) { + KActivities::Info info(id); + + if (info.state() != KActivities::Info::Invalid) { + on_activityAdded(id); + } + } + + connect(m_corona->activitiesConsumer(), &KActivities::Consumer::activityAdded, this, &Layouts::on_activityAdded); + connect(m_corona->activitiesConsumer(), &KActivities::Consumer::activityRemoved, this, &Layouts::on_activityRemoved); + connect(m_corona->activitiesConsumer(), &KActivities::Consumer::runningActivitiesChanged, this, &Layouts::on_runningActivitiesChanged); + + activitiesStatesChanged(); +} + +void Layouts::activitiesStatesChanged() +{ + QVector roles; + roles << Qt::DisplayRole; + roles << Qt::UserRole; + roles << ALLACTIVITIESDATAROLE; + roles << ALLACTIVITIESSORTEDROLE; + + emit dataChanged(index(0, BACKGROUNDCOLUMN), index(rowCount()-1, BACKGROUNDCOLUMN), roles); + emit dataChanged(index(0, ACTIVITYCOLUMN), index(rowCount()-1, ACTIVITYCOLUMN), roles); +} + +void Layouts::on_activityAdded(const QString &id) +{ + m_activitiesInfo[id] = new KActivities::Info(id, this); + + Data::Activity activity; + activity.id = m_activitiesInfo[id]->id(); + activity.name = m_activitiesInfo[id]->name(); + activity.icon = m_activitiesInfo[id]->icon(); + activity.state = m_activitiesInfo[id]->state(); + + m_activitiesMap[id] = activity; + + connect(m_activitiesInfo[id], &KActivities::Info::nameChanged, [this, id]() { + on_activityChanged(id); + }); + + connect(m_activitiesInfo[id], &KActivities::Info::iconChanged, [this, id]() { + on_activityChanged(id); + }); +} + +void Layouts::on_activityRemoved(const QString &id) +{ + if (m_activitiesMap.contains(id)) { + m_activitiesMap.remove(id); + } + + if (m_activitiesInfo.contains(id)) { + KActivities::Info *info = m_activitiesInfo.take(id); + info->deleteLater(); + } + + activitiesStatesChanged(); +} + +void Layouts::on_activityChanged(const QString &id) +{ + if (m_activitiesMap.contains(id) && m_activitiesInfo.contains(id)) { + m_activitiesMap[id].name = m_activitiesInfo[id]->name(); + m_activitiesMap[id].icon = m_activitiesInfo[id]->icon(); + m_activitiesMap[id].state = m_activitiesInfo[id]->state(); + + activitiesStatesChanged(); + } +} + +void Layouts::on_runningActivitiesChanged(const QStringList &runningIds) +{ + Data::ActivitiesMap::iterator i; + + for (i = m_activitiesMap.begin(); i != m_activitiesMap.end(); ++i){ + if (runningIds.contains(i.key())) { + m_activitiesMap[i.key()].state = KActivities::Info::Running; + } else { + m_activitiesMap[i.key()].state = KActivities::Info::Stopped; + } + } + + activitiesStatesChanged(); +} + } } } diff --git a/app/settings/models/layoutsmodel.h b/app/settings/models/layoutsmodel.h index 28ea49278..e7f9ac5c3 100644 --- a/app/settings/models/layoutsmodel.h +++ b/app/settings/models/layoutsmodel.h @@ -22,6 +22,7 @@ #define SETTINGSLAYOUTSMODEL_H // local +#include "../data/activitydata.h" #include "../data/layoutdata.h" #include "../data/layoutstable.h" #include "../../lattecorona.h" @@ -59,12 +60,13 @@ public: LAYOUTISSHAREDROLE, LAYOUTNAMEWASEDITEDROLE, INMULTIPLELAYOUTSROLE, - ALLACTIVITIESROLE, - RUNNINGACTIVITIESROLE, + ALLACTIVITIESSORTEDROLE, + ALLACTIVITIESDATAROLE, ALLLAYOUTSROLE }; explicit Layouts(QObject *parent, Latte::Corona *corona); + ~Layouts(); bool containsCurrentName(const QString &name) const; @@ -110,7 +112,15 @@ signals: private slots: void updateActiveStates(); + void activitiesStatesChanged(); + void on_activityAdded(const QString &id); + void on_activityRemoved(const QString &id); + void on_activityChanged(const QString &id); + void on_runningActivitiesChanged(const QStringList &runningIds); + private: + void initActivities(); + void autoAssignFreeActivitiesLayout(); void setActivities(const int &row, const QStringList &activities); void setId(const int &row, const QString &newId); @@ -122,6 +132,9 @@ private: bool m_inMultipleMode{false}; Data::LayoutsTable m_layoutsTable; + Data::ActivitiesMap m_activitiesMap; + QHash m_activitiesInfo; + Latte::Corona *m_corona{nullptr}; };