File indexing completed on 2024-04-21 05:30:58

0001 /*
0002     SPDX-FileCopyrightText: 2020 Michail Vourlakos <mvourlakos@gmail.com>
0003     SPDX-License-Identifier: GPL-2.0-or-later
0004 */
0005 
0006 #include "layoutsmodel.h"
0007 
0008 // local
0009 #include "../../data/layoutdata.h"
0010 #include "../../layouts/manager.h"
0011 #include "../../layouts/synchronizer.h"
0012 #include "../../settings/universalsettings.h"
0013 
0014 // Qt
0015 #include <QDebug>
0016 #include <QFileInfo>
0017 #include <QFont>
0018 #include <QIcon>
0019 
0020 // KDE
0021 #include <KLocalizedString>
0022 
0023 // KActivities
0024 #include <KActivities/Consumer>
0025 #include <KActivities/Info>
0026 
0027 namespace Latte {
0028 namespace Settings {
0029 namespace Model {
0030 
0031 Layouts::Layouts(QObject *parent, Latte::Corona *corona)
0032     : QAbstractTableModel(parent),
0033       m_corona(corona)
0034 {
0035     initActivities();
0036 
0037     connect(this, &Layouts::inMultipleModeChanged, this, [&]() {
0038         QVector<int> roles;
0039         roles << Qt::DisplayRole;
0040         roles << Qt::UserRole;
0041         roles << INMULTIPLELAYOUTSROLE;
0042 
0043         emit dataChanged(index(0, NAMECOLUMN), index(rowCount()-1, ACTIVITYCOLUMN), roles);
0044     });
0045 
0046     connect(this, &Layouts::activitiesStatesChanged, this, &Layouts::onActivitiesStatesChanged);
0047 
0048     connect(m_corona->universalSettings(), &Latte::UniversalSettings::singleModeLayoutNameChanged, this, &Layouts::updateActiveStates); //! sort properly when switching single layouts
0049     connect(m_corona->layoutsManager()->synchronizer(), &Latte::Layouts::Synchronizer::centralLayoutsChanged, this, &Layouts::updateActiveStates);
0050 
0051     connect(this, &Layouts::activitiesStatesChanged, this, &Layouts::updateConsideredActiveStates);
0052     connect(this, &Layouts::inMultipleModeChanged, this, &Layouts::updateConsideredActiveStates);
0053     connect(m_corona->layoutsManager()->synchronizer(), &Latte::Layouts::Synchronizer::centralLayoutsChanged, this, &Layouts::updateConsideredActiveStates);
0054     connect(m_corona->universalSettings(), &Latte::UniversalSettings::singleModeLayoutNameChanged, this, &Layouts::updateConsideredActiveStates);
0055 }
0056 
0057 Layouts::~Layouts()
0058 {
0059     qDeleteAll(m_activitiesInfo);
0060 }
0061 
0062 bool Layouts::containsCurrentName(const QString &name) const
0063 {
0064     return m_layoutsTable.containsName(name);
0065 }
0066 
0067 bool Layouts::hasChangedData() const
0068 {
0069     return modeIsChanged() || layoutsAreChanged();
0070 }
0071 
0072 bool Layouts::modeIsChanged() const
0073 {
0074     return o_inMultipleMode != m_inMultipleMode;
0075 }
0076 
0077 bool Layouts::layoutsAreChanged() const
0078 {
0079     return o_layoutsTable != m_layoutsTable;
0080 }
0081 
0082 bool Layouts::inMultipleMode() const
0083 {
0084     return m_inMultipleMode;
0085 }
0086 
0087 void Layouts::setInMultipleMode(bool inMultiple)
0088 {
0089     if (m_inMultipleMode == inMultiple) {
0090         return;
0091     }
0092 
0093     m_inMultipleMode = inMultiple;
0094     emit inMultipleModeChanged();
0095 }
0096 
0097 bool Layouts::hasEnabledLayout() const
0098 {
0099     for (int i=0; i<m_layoutsTable.rowCount(); ++i) {
0100         if (m_layoutsTable[i].activities.count() > 0) {
0101             return true;
0102         }
0103     }
0104 
0105     return false;
0106 }
0107 
0108 bool Layouts::hasEnabledLayoutInAllActitivities() const
0109 {
0110     for (int i=0; i<m_layoutsTable.rowCount(); ++i) {
0111         if (m_layoutsTable[i].activities.contains(Data::Layout::ALLACTIVITIESID)) {
0112             return true;
0113         }
0114     }
0115 
0116     return false;
0117 }
0118 
0119 bool Layouts::hasEnabledLayoutInFreeActivities() const
0120 {
0121     for (int i=0; i<m_layoutsTable.rowCount(); ++i) {
0122         if (m_layoutsTable[i].activities.contains(Data::Layout::FREEACTIVITIESID)) {
0123             return true;
0124         }
0125     }
0126 
0127     return false;
0128 }
0129 
0130 bool Layouts::hasEnabledLayoutInCurrentActivity() const
0131 {
0132     QString curActivityId = currentActivityId();
0133 
0134     for (int i=0; i<m_layoutsTable.rowCount(); ++i) {
0135         if (m_layoutsTable[i].activities.contains(curActivityId)) {
0136             return true;
0137         }
0138     }
0139 
0140     return false;
0141 }
0142 
0143 int Layouts::rowCount() const
0144 {
0145     return m_layoutsTable.rowCount();
0146 }
0147 
0148 int Layouts::rowCount(const QModelIndex &parent) const
0149 {
0150     Q_UNUSED(parent);
0151 
0152     return m_layoutsTable.rowCount();
0153 }
0154 
0155 int Layouts::columnCount(const QModelIndex &parent) const
0156 {
0157     Q_UNUSED(parent);
0158 
0159     return ACTIVITYCOLUMN+1;
0160 }
0161 
0162 QString Layouts::currentActivityId() const
0163 {
0164     return m_corona->activitiesConsumer()->currentActivity();
0165 }
0166 
0167 void Layouts::clear()
0168 {
0169     if (m_layoutsTable.rowCount() > 0) {
0170         beginRemoveRows(QModelIndex(), 0, m_layoutsTable.rowCount() - 1);
0171         m_layoutsTable.clear();
0172         endRemoveRows();
0173     }
0174 }
0175 
0176 void Layouts::appendLayout(const Latte::Data::Layout &layout)
0177 {
0178     int newRow = m_layoutsTable.sortedPosForName(layout.name);
0179 
0180     beginInsertRows(QModelIndex(), newRow, newRow);
0181     m_layoutsTable.insert(newRow, layout);
0182     endInsertRows();
0183 
0184     emit rowsInserted();
0185 }
0186 
0187 void Layouts::appendOriginalLayout(const Latte::Data::Layout &layout)
0188 {
0189     int newRow = o_layoutsTable.sortedPosForName(layout.name);
0190     o_layoutsTable.insert(newRow, layout);
0191 
0192     appendLayout(layout);
0193 }
0194 
0195 void Layouts::applyData()
0196 {   
0197     QVector<int> roles;
0198     roles << Qt::DisplayRole;
0199     roles << Qt::UserRole;
0200 
0201     o_inMultipleMode = m_inMultipleMode;
0202     o_layoutsTable = m_layoutsTable;
0203 
0204     emit dataChanged(index(0, BACKGROUNDCOLUMN), index(rowCount()-1, ACTIVITYCOLUMN), roles);
0205 }
0206 
0207 void Layouts::resetData()
0208 {
0209     clear();
0210     setOriginalInMultipleMode(o_inMultipleMode);
0211     setOriginalData(o_layoutsTable);
0212 }
0213 
0214 void Layouts::removeLayout(const QString &id)
0215 {
0216     int index = m_layoutsTable.indexOf(id);
0217 
0218     if (index >= 0) {
0219         removeRows(index,1);
0220     }
0221 }
0222 
0223 void Layouts::setLayoutProperties(const Latte::Data::Layout &layout)
0224 {
0225     if (m_layoutsTable.containsId(layout.id)) {
0226         m_layoutsTable[layout.id] = layout;
0227         int dataRow = m_layoutsTable.indexOf(layout.id);
0228 
0229         QVector<int> roles;
0230         roles << Qt::DisplayRole;
0231         roles << Qt::UserRole;
0232         roles << ERRORSROLE;
0233         roles << WARNINGSROLE;
0234         emit dataChanged(index(dataRow, IDCOLUMN), index(dataRow, ACTIVITYCOLUMN), roles);
0235     }
0236 }
0237 
0238 bool Layouts::removeRows(int row, int count, const QModelIndex &parent)
0239 {
0240     Q_UNUSED(parent)
0241 
0242     int firstRow = row;
0243     int lastRow = row+count-1;
0244 
0245     if (count > 0 && m_layoutsTable.rowExists(firstRow) && (m_layoutsTable.rowExists(lastRow))) {
0246         bool freeActivitiesLayoutIsRemoved{false};
0247 
0248         for(int i=firstRow; i<=lastRow; ++i) {
0249             if (m_layoutsTable[i].activities.contains(Latte::Data::Layout::FREEACTIVITIESID)) {
0250                 //! we need to reassign it properly
0251                 freeActivitiesLayoutIsRemoved = true;
0252                 break;
0253             }
0254         }
0255 
0256         beginRemoveRows(QModelIndex(), firstRow, lastRow);
0257         for(int i=0; i<count; ++i) {
0258             m_layoutsTable.remove(firstRow);
0259         }
0260         endRemoveRows();
0261 
0262         return true;
0263     }
0264 
0265     return false;
0266 }
0267 
0268 QString Layouts::layoutNameForFreeActivities() const
0269 {
0270     for(int i=0; i<rowCount(); ++i) {
0271         if (m_layoutsTable[i].activities.contains(Latte::Data::Layout::FREEACTIVITIESID)) {
0272             return m_layoutsTable[i].name;
0273         }
0274     }
0275 
0276     return QString();
0277 }
0278 
0279 void Layouts::setCurrentLayoutForFreeActivities(const QString &id)
0280 {
0281     if (m_layoutsTable.containsId(id)) {
0282         m_layoutsTable.setLayoutForFreeActivities(id);
0283 
0284         QVector<int> roles;
0285         roles << Qt::DisplayRole;
0286         roles << Qt::UserRole;
0287         emit dataChanged(index(0, ACTIVITYCOLUMN), index(rowCount()-1, ACTIVITYCOLUMN), roles);
0288     }
0289 }
0290 
0291 void Layouts::setOriginalLayoutForFreeActivities(const QString &id)
0292 {
0293     if (o_layoutsTable.containsId(id)) {
0294         o_layoutsTable.setLayoutForFreeActivities(id);
0295         m_layoutsTable.setLayoutForFreeActivities(id);
0296 
0297         QVector<int> roles;
0298         roles << Qt::DisplayRole;
0299         roles << Qt::UserRole;
0300         emit dataChanged(index(0, ACTIVITYCOLUMN), index(rowCount()-1, ACTIVITYCOLUMN), roles);
0301     }
0302 }
0303 
0304 QVariant Layouts::headerData(int section, Qt::Orientation orientation, int role) const
0305 {
0306     if (orientation != Qt::Horizontal) {
0307         return QAbstractTableModel::headerData(section, orientation, role);
0308     }
0309 
0310     if (role == Qt::FontRole) {
0311         QFont font = qvariant_cast<QFont>(QAbstractTableModel::headerData(section, orientation, role));
0312         font.setBold(true);
0313         return font;
0314     }
0315 
0316     switch(section) {
0317     case IDCOLUMN:
0318         if (role == Qt::DisplayRole) {
0319             return QString("#path");
0320         }
0321         break;
0322     case HIDDENTEXTCOLUMN:
0323         if (role == Qt::DisplayRole) {
0324             return QString("");
0325         }
0326         break;
0327     case BACKGROUNDCOLUMN:
0328         if (role == Qt::DisplayRole) {
0329             return QString("");
0330         } else if (role == Qt::DecorationRole) {
0331             return QIcon::fromTheme("games-config-background");
0332         } else if (role == Qt::TextAlignmentRole ){
0333             return QVariant::fromValue(Qt::AlignHCenter | Qt::AlignVCenter);
0334         }
0335         break;
0336     case NAMECOLUMN:
0337         if (role == Qt::DisplayRole) {
0338             return QString(i18nc("column for layout name", "Name"));
0339         }/* else if (role == Qt::TextAlignmentRole) {
0340             return QVariant::fromValue(Qt::AlignLeft | Qt::AlignVCenter);
0341         }*/
0342         break;
0343     case MENUCOLUMN:
0344         if (role == Qt::DisplayRole) {
0345             return QString(i18nc("column for layout to show in menu", "In Menu"));
0346         }/* else if (role == Qt::TextAlignmentRole ){
0347             return QVariant::fromValue(Qt::AlignHCenter | Qt::AlignVCenter);
0348         }*/
0349         break;
0350     case BORDERSCOLUMN:
0351         if (role == Qt::DisplayRole) {
0352             return QString(i18nc("column for layout to hide borders for maximized windows", "Borderless"));
0353         }/* else if (role == Qt::TextAlignmentRole ){
0354             return QVariant::fromValue(Qt::AlignHCenter | Qt::AlignVCenter);
0355         }*/
0356         break;
0357     case ACTIVITYCOLUMN:
0358         if (role == Qt::DisplayRole) {
0359             return QString(i18nc("column for layout to show which activities is assigned to", "Activities"));
0360         } else if (role == Qt::DecorationRole) {
0361             return QIcon::fromTheme("activities");
0362         }/* else if (role == Qt::TextAlignmentRole ){
0363             return QVariant::fromValue(Qt::AlignLeft | Qt::AlignVCenter);
0364         }*/
0365         break;
0366     default:
0367         break;
0368     };
0369 
0370     return QAbstractTableModel::headerData(section, orientation, role);
0371 }
0372 
0373 Qt::ItemFlags Layouts::flags(const QModelIndex &index) const
0374 {
0375     const int column = index.column();
0376     const int row = index.row();
0377 
0378     auto flags = QAbstractTableModel::flags(index);
0379 
0380     if (column == MENUCOLUMN || column == BORDERSCOLUMN) {
0381         flags |= Qt::ItemIsUserCheckable;
0382     }
0383 
0384     if (column == ACTIVITYCOLUMN
0385             || column == NAMECOLUMN) {
0386         flags |= Qt::ItemIsEditable;
0387     }
0388 
0389     return flags;
0390 }
0391 
0392 Latte::Data::LayoutIcon Layouts::icon(const int &row) const
0393 {
0394     return m_corona->layoutsManager()->iconForLayout(m_layoutsTable[row]);
0395 }
0396 
0397 const Latte::Data::LayoutIcon Layouts::currentLayoutIcon(const QString &id) const
0398 {
0399     int row = rowForId(id);
0400 
0401     if (row >= 0) {
0402         return icon(row);
0403     }
0404 
0405     return Latte::Data::LayoutIcon();
0406 }
0407 
0408 QString Layouts::sortableText(const int &priority, const int &row) const
0409 {
0410     QString numberPart;
0411 
0412     if (priority < 10) {
0413         numberPart = "00000" + QString::number(priority);
0414     } else if (priority < 100) {
0415         numberPart = "0000" + QString::number(priority);
0416     } else if (priority < 1000) {
0417         numberPart = "000" + QString::number(priority);
0418     } else if (priority < 10000) {
0419         numberPart = "00" + QString::number(priority);
0420     } else if (priority < 100000) {
0421         numberPart = "0" + QString::number(priority);
0422     }
0423 
0424     return (numberPart + m_layoutsTable[row].name);
0425 }
0426 
0427 
0428 QString Layouts::sortingPriority(const SortingPriority &priority, const int &row) const
0429 {
0430     int iPriority = (int)priority;
0431 
0432     iPriority = (m_layoutsTable[row].isActive && inMultipleMode() ? iPriority - 1000 : iPriority);
0433 
0434     return sortableText(iPriority, row);
0435 }
0436 
0437 QVariant Layouts::data(const QModelIndex &index, int role) const
0438 {
0439     const int row = index.row();
0440     int column = index.column();
0441     bool isNewLayout = !o_layoutsTable.containsId(m_layoutsTable[row].id);
0442 
0443     if (!m_layoutsTable.rowExists(row)) {
0444         return QVariant{};
0445     }
0446 
0447     //! original data
0448     Latte::Data::Layout original;
0449 
0450     if (!isNewLayout) {
0451         original = o_layoutsTable[m_layoutsTable[row].id];
0452     }
0453 
0454     if (role == IDROLE) {
0455         return m_layoutsTable[row].id;
0456     } else if (role == ISACTIVEROLE) {
0457         return m_layoutsTable[row].isActive;
0458     } else if (role == ISCONSIDEREDACTIVEROLE) {
0459         return m_layoutsTable[row].isConsideredActive;
0460     } else if (role == ISLOCKEDROLE) {
0461         return m_layoutsTable[row].isLocked;
0462     } else if (role == INMULTIPLELAYOUTSROLE) {
0463         return inMultipleMode();
0464     } else if (role == ASSIGNEDACTIVITIESROLE) {
0465         return m_layoutsTable[row].activities;
0466     } else if (role == ALLACTIVITIESSORTEDROLE) {
0467         QStringList activities;
0468         activities << QString(Latte::Data::Layout::ALLACTIVITIESID);
0469         activities << QString(Latte::Data::Layout::FREEACTIVITIESID);
0470         activities << QString(Latte::Data::Layout::CURRENTACTIVITYID);
0471         activities << m_corona->layoutsManager()->synchronizer()->activities();
0472         return activities;
0473     } else if (role == ALLACTIVITIESDATAROLE) {
0474         QVariant activitiesData;
0475         activitiesData.setValue(m_activitiesTable);
0476         return activitiesData;
0477     } else if (role == ALLLAYOUTSROLE) {
0478         QVariant layouts;
0479         layouts.setValue(m_layoutsTable);
0480         return layouts;
0481     } else if (role == ISNEWLAYOUTROLE) {
0482         return isNewLayout;
0483     } else if (role == LAYOUTHASCHANGESROLE) {
0484         return isNewLayout ? true : (original != m_layoutsTable[row]);
0485     } else if (role == BACKGROUNDUSERROLE) {
0486         Latte::Data::LayoutIcon _icon = icon(row);
0487         QVariant iconVariant;
0488         iconVariant.setValue<Latte::Data::LayoutIcon>(_icon);
0489         return iconVariant;
0490     } else if (role == ERRORSROLE) {
0491         return m_layoutsTable[row].errors;
0492     } else if (role == WARNINGSROLE) {
0493         return m_layoutsTable[row].warnings;
0494     }
0495 
0496     switch (column) {
0497     case IDCOLUMN:
0498         if (role == Qt::DisplayRole || role == Qt::UserRole){
0499             return m_layoutsTable[row].id;
0500         }
0501         break;
0502     case HIDDENTEXTCOLUMN:
0503         return QVariant{};
0504     case BACKGROUNDCOLUMN:
0505         if (role == SORTINGROLE) {
0506             return m_layoutsTable[row].name;
0507         }
0508 
0509         if (role == Qt::DisplayRole) {
0510             return m_layoutsTable[row].background;
0511         } else if (role == Qt::UserRole) {
0512             Latte::Data::LayoutIcon _icon = icon(row);
0513             QVariant iconVariant;
0514             iconVariant.setValue<Latte::Data::LayoutIcon>(_icon);
0515             return iconVariant;
0516         }
0517         break;
0518     case NAMECOLUMN:
0519         if (role == SORTINGROLE) {
0520             if (m_layoutsTable[row].isConsideredActive) {
0521                 return sortingPriority(HIGHESTPRIORITY, row);
0522             }
0523 
0524             return sortingPriority(NORMALPRIORITY, row);
0525         }
0526 
0527         if ((role == Qt::DisplayRole) || (role == Qt::UserRole)) {
0528             return m_layoutsTable[row].name;
0529         }
0530         break;
0531     case MENUCOLUMN:
0532         if (role == SORTINGROLE) {
0533             if (m_layoutsTable[row].isShownInMenu) {
0534                 return sortingPriority(HIGHESTPRIORITY, row);
0535             }
0536 
0537             return sortingPriority(NORMALPRIORITY, row);
0538         }
0539 
0540         if (role == ORIGINALISSHOWNINMENUROLE) {
0541             return isNewLayout ? false : original.isShownInMenu;
0542         }
0543 
0544         if (role == Qt::UserRole) {
0545             return m_layoutsTable[row].isShownInMenu;
0546         }
0547         break;
0548     case BORDERSCOLUMN:
0549         if (role == SORTINGROLE) {
0550             if (m_layoutsTable[row].hasDisabledBorders) {
0551                 return sortingPriority(HIGHESTPRIORITY, row);
0552             }
0553 
0554             return sortingPriority(NORMALPRIORITY, row);
0555         }
0556 
0557         if (role == ORIGINALHASBORDERSROLE) {
0558             return isNewLayout ? false : original.hasDisabledBorders;
0559         }
0560 
0561         if (role == Qt::UserRole) {
0562             return m_layoutsTable[row].hasDisabledBorders;
0563         }
0564         break;
0565     case ACTIVITYCOLUMN:
0566         if (role == SORTINGROLE) {
0567             if (m_layoutsTable[row].activities.count() > 0) {
0568                 if (m_layoutsTable[row].activities.contains(Latte::Data::Layout::ALLACTIVITIESID)) {
0569                     return sortingPriority(HIGHESTPRIORITY, row);
0570                 } else if (m_layoutsTable[row].activities.contains(Latte::Data::Layout::FREEACTIVITIESID)) {
0571                     return sortingPriority(HIGHPRIORITY, row);
0572                 } else {
0573                     return sortingPriority(MEDIUMPRIORITY, row) + m_layoutsTable[row].activities.count();
0574                 }
0575             }
0576 
0577             return sortingPriority(NORMALPRIORITY, row) + m_layoutsTable[row].activities.count();
0578         }
0579 
0580         if (role == ORIGINALASSIGNEDACTIVITIESROLE) {
0581             return isNewLayout ? QStringList() : original.activities;
0582         }
0583 
0584         if (role == Qt::UserRole) {
0585             return m_layoutsTable[row].activities;
0586         }
0587         break;
0588     default:
0589         return QVariant{};
0590     };
0591 
0592     return QVariant{};
0593 }
0594 
0595 QStringList Layouts::cleanStrings(const QStringList &original, const QStringList &occupied)
0596 {
0597     QStringList result;
0598 
0599     for(int i=0; i<original.count(); ++i) {
0600         if (!occupied.contains(original[i])) {
0601             result << original[i];
0602         }
0603     }
0604 
0605     return result;
0606 }
0607 
0608 void Layouts::setOriginalActivitiesForLayout(const Latte::Data::Layout &layout)
0609 {
0610     if (o_layoutsTable.containsId(layout.id) && m_layoutsTable.containsId(layout.id)) {
0611         o_layoutsTable[layout.id].activities = layout.activities;
0612 
0613         int mrow = rowForId(layout.id);
0614         setActivities(mrow, layout.activities);
0615     }
0616 }
0617 
0618 void Layouts::setOriginalViewsForLayout(const Latte::Data::Layout &layout)
0619 {
0620     if (o_layoutsTable.containsId(layout.id) && m_layoutsTable.containsId(layout.id)) {
0621         o_layoutsTable[layout.id].views = layout.views;
0622     }
0623 }
0624 
0625 void Layouts::setActivities(const int &row, const QStringList &activities)
0626 {
0627     if (!m_layoutsTable.rowExists(row) || m_layoutsTable[row].activities == activities) {
0628         return;
0629     }
0630 
0631     QVector<int> roles;
0632     roles << Qt::DisplayRole;
0633     roles << Qt::UserRole;
0634     roles << ASSIGNEDACTIVITIESROLE;
0635 
0636     m_layoutsTable[row].activities = activities;
0637     emit dataChanged(index(row, BACKGROUNDCOLUMN), index(row,ACTIVITYCOLUMN), roles);
0638 }
0639 
0640 void Layouts::setId(const int &row, const QString &newId)
0641 {
0642     if (!m_layoutsTable.rowExists(row) || newId.isEmpty() || m_layoutsTable[row].id == newId) {
0643         return;
0644     }
0645 
0646     QVector<int> roles;
0647     roles << Qt::DisplayRole;
0648 
0649     QString oldId = m_layoutsTable[row].id;
0650     m_layoutsTable[row].id = newId;
0651     emit dataChanged(index(row, NAMECOLUMN), index(row,NAMECOLUMN), roles);
0652 }
0653 
0654 bool Layouts::setData(const QModelIndex &index, const QVariant &value, int role)
0655 {
0656     const int row = index.row();
0657     const int column = index.column();
0658 
0659     if (!m_layoutsTable.rowExists(row) || column<0 || column > ACTIVITYCOLUMN) {
0660         return false;
0661     }
0662 
0663     QVector<int> roles;
0664     roles << role;
0665 
0666     //! common roles for all row cells
0667     if (role == ISLOCKEDROLE) {
0668         m_layoutsTable[row].isLocked = value.toBool();
0669         emit dataChanged(this->index(row,0), this->index(row, ACTIVITYCOLUMN), roles);
0670         return true;
0671     }
0672 
0673     //! specific roles to each independent cell
0674     switch (column) {
0675     case IDCOLUMN:
0676         if (role==Qt::UserRole) {
0677             setId(row, value.toString());
0678             emit dataChanged(index, index, roles);
0679             return true;
0680         }
0681         break;
0682     case HIDDENTEXTCOLUMN:
0683         return true;
0684         break;
0685     case BACKGROUNDCOLUMN:
0686         if (role == Qt::UserRole) {
0687             QString back = value.toString();
0688 
0689             if (back.startsWith("/")) {
0690                 m_layoutsTable[row].background = back;
0691             } else {
0692                 m_layoutsTable[row].background = QString();
0693                 m_layoutsTable[row].color = back;
0694             }
0695             emit dataChanged(index, index, roles);
0696             return true;
0697         }
0698         break;
0699     case NAMECOLUMN:
0700         if (role == Qt::UserRole) {
0701             QString provenId = m_layoutsTable.idForName(value.toString());
0702 
0703             if (!provenId.isEmpty() && provenId != m_layoutsTable[row].id /*not the same row*/ ){
0704                 //! duplicate name should be rejected
0705                 emit nameDuplicated(provenId, m_layoutsTable[row].id);
0706                 return false;
0707             } else {
0708                 m_layoutsTable[row].name = value.toString();
0709                 emit dataChanged(index, index, roles);
0710                 return true;
0711             }
0712         }
0713         break;
0714     case MENUCOLUMN:
0715         if (role == Qt::UserRole) {
0716             m_layoutsTable[row].isShownInMenu = value.toBool();
0717             emit dataChanged(index, index, roles);
0718             emit dataChanged(this->index(row, NAMECOLUMN), this->index(row,NAMECOLUMN), roles);
0719             return true;
0720         }
0721         break;
0722     case BORDERSCOLUMN:
0723         if (role == Qt::UserRole) {
0724             m_layoutsTable[row].hasDisabledBorders = value.toBool();
0725             emit dataChanged(index, index, roles);
0726             emit dataChanged(this->index(row, NAMECOLUMN), this->index(row,NAMECOLUMN), roles);
0727             return true;
0728         }
0729         break;
0730     case ACTIVITYCOLUMN:
0731         if (role == Qt::UserRole)  {
0732             setActivities(row, value.toStringList());
0733             updateConsideredActiveStates();
0734             emit dataChanged(this->index(row, NAMECOLUMN), this->index(row,NAMECOLUMN), roles);
0735             return true;
0736         }
0737         break;
0738     };
0739 
0740     return false;
0741 }
0742 
0743 void Layouts::updateActiveStates()
0744 {
0745     QVector<int> roles;
0746     roles << Qt::DisplayRole;
0747     roles << Qt::UserRole;
0748     roles << ISACTIVEROLE;
0749     roles << SORTINGROLE;
0750 
0751     for(int i=0; i<rowCount(); ++i) {
0752         bool iActive{false};
0753 
0754         if (m_corona->layoutsManager()->synchronizer()->layout(m_layoutsTable[i].name)) {
0755             iActive = true;
0756         }
0757 
0758         if (m_layoutsTable[i].isActive != iActive) {
0759             m_layoutsTable[i].isActive = iActive;
0760             emit dataChanged(index(i, BACKGROUNDCOLUMN), index(i,ACTIVITYCOLUMN), roles);
0761         }
0762     }
0763 }
0764 
0765 void Layouts::updateConsideredActiveStates()
0766 {
0767     QVector<int> roles;
0768     roles << Qt::DisplayRole;
0769     roles << Qt::UserRole;
0770     roles << ISCONSIDEREDACTIVEROLE;
0771     roles << SORTINGROLE;
0772 
0773     if (!m_inMultipleMode) {
0774         //! single mode but not the running one
0775 
0776         for(int i=0; i<rowCount(); ++i) {
0777             bool iConsideredActive{false};
0778 
0779             if (m_corona->universalSettings()->singleModeLayoutName() == m_layoutsTable[i].name) {
0780                 iConsideredActive = true;
0781             }
0782 
0783             if (m_layoutsTable[i].isConsideredActive != iConsideredActive) {
0784                 m_layoutsTable[i].isConsideredActive = iConsideredActive;
0785                 emit dataChanged(index(i, BACKGROUNDCOLUMN), index(i,ACTIVITYCOLUMN), roles);
0786             }
0787         }
0788     } else if (m_inMultipleMode) {
0789         //! multiple mode but not the running one
0790 
0791         QStringList runningActivities = m_corona->layoutsManager()->synchronizer()->runningActivities();
0792         QStringList freeRunningActivities = m_corona->layoutsManager()->synchronizer()->freeRunningActivities();
0793 
0794         for(int i=0; i<rowCount(); ++i) {
0795             bool iConsideredActive{false};
0796 
0797             if (m_layoutsTable[i].activities.contains(Latte::Data::Layout::ALLACTIVITIESID)) {
0798                 iConsideredActive = true;
0799             } else if (freeRunningActivities.count()>0 && m_layoutsTable[i].activities.contains(Latte::Data::Layout::FREEACTIVITIESID)) {
0800                 iConsideredActive = true;
0801             } else if (m_layoutsTable[i].activities.count()>0 && containsSpecificRunningActivity(runningActivities, m_layoutsTable[i])) {
0802                 iConsideredActive = true;
0803             } else {
0804                 iConsideredActive = false;
0805             }
0806 
0807             if (m_layoutsTable[i].isConsideredActive != iConsideredActive) {
0808                 m_layoutsTable[i].isConsideredActive = iConsideredActive;
0809                 emit dataChanged(index(i, BACKGROUNDCOLUMN), index(i,ACTIVITYCOLUMN), roles);
0810             }
0811         }
0812     }
0813 }
0814 
0815 int Layouts::rowForId(const QString &id) const
0816 {
0817     return m_layoutsTable.indexOf(id);
0818 }
0819 
0820 const Latte::Data::Layout &Layouts::at(const int &row)
0821 {
0822     return m_layoutsTable[row];
0823 }
0824 
0825 const Latte::Data::Layout &Layouts::currentData(const QString &id)
0826 {
0827     if (m_layoutsTable.containsId(id)){
0828         return m_layoutsTable[id];
0829     }
0830 
0831     return Latte::Data::Layout();
0832 }
0833 
0834 
0835 const Latte::Data::Layout Layouts::originalData(const QString &id)
0836 {
0837     if (o_layoutsTable.containsId(id)){
0838         return o_layoutsTable[id];
0839     }
0840 
0841     return Latte::Data::Layout();
0842 }
0843 
0844 const Latte::Data::LayoutsTable &Layouts::originalLayoutsData()
0845 {
0846     return o_layoutsTable;
0847 }
0848 
0849 const Latte::Data::LayoutsTable &Layouts::currentLayoutsData()
0850 {
0851     return m_layoutsTable;
0852 }
0853 
0854 void Layouts::setOriginalInMultipleMode(const bool &inmultiple)
0855 {
0856     setInMultipleMode(inmultiple);
0857 
0858     if (o_inMultipleMode == inmultiple) {
0859         return;
0860     }
0861 
0862     o_inMultipleMode = inmultiple;
0863 }
0864 
0865 void Layouts::setOriginalData(Latte::Data::LayoutsTable &data)
0866 {
0867     clear();
0868 
0869     beginInsertRows(QModelIndex(), 0, data.rowCount() - 1);
0870     o_layoutsTable = data;
0871     m_layoutsTable = data;
0872     endInsertRows();
0873 
0874     emit rowsInserted();
0875 
0876     updateActiveStates();
0877     updateConsideredActiveStates();
0878 }
0879 
0880 QList<Latte::Data::Layout> Layouts::alteredLayouts() const
0881 {
0882     QList<Latte::Data::Layout> layouts;
0883 
0884     for(int i=0; i<rowCount(); ++i) {
0885         QString currentId = m_layoutsTable[i].id;
0886 
0887         if ((!o_layoutsTable.containsId(currentId))
0888                 || m_layoutsTable[currentId] != o_layoutsTable[currentId]) {
0889             layouts << m_layoutsTable[i];
0890         }
0891     }
0892 
0893     return layouts;
0894 }
0895 
0896 //! Activities code
0897 void Layouts::initActivities()
0898 {
0899     Latte::Data::Activity allActivities;
0900     allActivities.id = Latte::Data::Layout::ALLACTIVITIESID;
0901     allActivities.name = QString("[ " + i18n("All Activities") + " ]");
0902     allActivities.icon = "activities";
0903     allActivities.state = KActivities::Info::Stopped;
0904     m_activitiesTable << allActivities;
0905 
0906     Latte::Data::Activity freeActivities;
0907     freeActivities.id = Latte::Data::Layout::FREEACTIVITIESID;
0908     freeActivities.name = QString("[ " + i18n("Free Activities") + " ]");
0909     freeActivities.icon = "activities";
0910     freeActivities.state = KActivities::Info::Stopped;
0911     m_activitiesTable << freeActivities;
0912 
0913     Latte::Data::Activity currentActivity;
0914     currentActivity.id = Latte::Data::Layout::CURRENTACTIVITYID;
0915     currentActivity.name = QString("[ " + i18n("Current Activity") + " ]");
0916     currentActivity.icon = "dialog-yes";
0917     currentActivity.state = KActivities::Info::Stopped;
0918     m_activitiesTable << currentActivity;
0919 
0920     QStringList activities = m_corona->layoutsManager()->synchronizer()->activities();;
0921 
0922     for(const auto &id: activities) {
0923         KActivities::Info info(id);
0924 
0925         if (info.state() != KActivities::Info::Invalid) {
0926             onActivityAdded(id);
0927         }
0928     }
0929 
0930     connect(m_corona->activitiesConsumer(), &KActivities::Consumer::activityAdded, this, &Layouts::onActivityAdded);
0931     connect(m_corona->activitiesConsumer(), &KActivities::Consumer::activityRemoved, this, &Layouts::onActivityRemoved);
0932     connect(m_corona->activitiesConsumer(), &KActivities::Consumer::runningActivitiesChanged, this, &Layouts::onRunningActivitiesChanged);
0933 
0934     emit activitiesStatesChanged();
0935 }
0936 
0937 void Layouts::onActivitiesStatesChanged()
0938 {
0939     QVector<int> roles;
0940     roles << Qt::DisplayRole;
0941     roles << Qt::UserRole;
0942     roles << ALLACTIVITIESDATAROLE;
0943     roles << ALLACTIVITIESSORTEDROLE;
0944 
0945     emit dataChanged(index(0, BACKGROUNDCOLUMN), index(rowCount()-1, BACKGROUNDCOLUMN), roles);
0946     emit dataChanged(index(0, ACTIVITYCOLUMN), index(rowCount()-1, ACTIVITYCOLUMN), roles);
0947 }
0948 
0949 void Layouts::onActivityAdded(const QString &id)
0950 {
0951     m_activitiesInfo[id] = new KActivities::Info(id, this);
0952 
0953     Latte::Data::Activity activity;
0954     activity.id = m_activitiesInfo[id]->id();
0955     activity.name = m_activitiesInfo[id]->name();
0956     activity.icon = m_activitiesInfo[id]->icon();
0957     activity.state = m_activitiesInfo[id]->state();
0958     activity.isCurrent = m_activitiesInfo[id]->isCurrent();
0959 
0960     if (!m_activitiesTable.containsId(id)) {
0961         m_activitiesTable << activity;
0962     } else {
0963         m_activitiesTable[id] = activity;
0964     }
0965 
0966     connect(m_activitiesInfo[id], &KActivities::Info::nameChanged, [this, id]() {
0967         onActivityChanged(id);
0968     });
0969 
0970     connect(m_activitiesInfo[id], &KActivities::Info::iconChanged, [this, id]() {
0971         onActivityChanged(id);
0972     });
0973 
0974     connect(m_activitiesInfo[id], &KActivities::Info::isCurrentChanged, [this, id]() {
0975         onActivityChanged(id);
0976     });
0977 }
0978 
0979 void Layouts::onActivityRemoved(const QString &id)
0980 {
0981     if (m_activitiesTable.containsId(id)) {
0982         m_activitiesTable.remove(id);
0983     }
0984 
0985     if (m_activitiesInfo.contains(id)) {
0986         KActivities::Info *info = m_activitiesInfo.take(id);
0987         info->deleteLater();
0988     }
0989 
0990     emit activitiesStatesChanged();
0991 }
0992 
0993 void Layouts::onActivityChanged(const QString &id)
0994 {
0995     if (m_activitiesTable.containsId(id) && m_activitiesInfo.contains(id)) {
0996         m_activitiesTable[id].name = m_activitiesInfo[id]->name();
0997         m_activitiesTable[id].icon = m_activitiesInfo[id]->icon();
0998         m_activitiesTable[id].state = m_activitiesInfo[id]->state();
0999         m_activitiesTable[id].isCurrent = m_activitiesInfo[id]->isCurrent();
1000 
1001         emit activitiesStatesChanged();
1002     }
1003 }
1004 
1005 void Layouts::onRunningActivitiesChanged(const QStringList &runningIds)
1006 {
1007     for (int i = 0; i < m_activitiesTable.rowCount(); ++i) {
1008         if (runningIds.contains(m_activitiesTable[i].id)) {
1009             m_activitiesTable[i].state = KActivities::Info::Running;
1010         } else {
1011             m_activitiesTable[i].state = KActivities::Info::Stopped;
1012         }
1013     }
1014 
1015     emit activitiesStatesChanged();
1016 }
1017 
1018 bool Layouts::containsSpecificRunningActivity(const QStringList &runningIds, const Latte::Data::Layout &layout) const
1019 {
1020     if (runningIds.count()>0 && layout.activities.count()>0) {
1021         for (int i=0; i<layout.activities.count(); ++i) {
1022             if (runningIds.contains(layout.activities[i])) {
1023                 return true;
1024             }
1025         }
1026     }
1027 
1028     return false;
1029 }
1030 
1031 }
1032 }
1033 }