Warning, file /plasma/plasma-workspace/kcms/colors/colorsmodel.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 SPDX-FileCopyrightText: 2007 Matthew Woehlke <mw_triad@users.sourceforge.net> 0003 SPDX-FileCopyrightText: 2007 Jeremy Whiting <jpwhiting@kde.org> 0004 SPDX-FileCopyrightText: 2016 Olivier Churlaud <olivier@churlaud.com> 0005 SPDX-FileCopyrightText: 2019 Kai Uwe Broulik <kde@privat.broulik.de> 0006 0007 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0008 */ 0009 0010 #include "colorsmodel.h" 0011 0012 #include <QCollator> 0013 #include <QDir> 0014 #include <QStandardPaths> 0015 0016 #include <KColorScheme> 0017 #include <KConfigGroup> 0018 #include <KSharedConfig> 0019 0020 #include <algorithm> 0021 0022 #include "colorsapplicator.h" 0023 0024 ColorsModel::ColorsModel(QObject *parent) 0025 : QAbstractListModel(parent) 0026 { 0027 } 0028 0029 ColorsModel::~ColorsModel() = default; 0030 0031 int ColorsModel::rowCount(const QModelIndex &parent) const 0032 { 0033 if (parent.isValid()) { 0034 return 0; 0035 } 0036 0037 return m_data.count(); 0038 } 0039 0040 QVariant ColorsModel::data(const QModelIndex &index, int role) const 0041 { 0042 if (!index.isValid() || index.row() >= m_data.count()) { 0043 return QVariant(); 0044 } 0045 0046 const auto &item = m_data.at(index.row()); 0047 0048 switch (role) { 0049 case Qt::DisplayRole: 0050 return item.display; 0051 case SchemeNameRole: 0052 return item.schemeName; 0053 case PaletteRole: 0054 return item.palette; 0055 case DisabledText: 0056 return item.palette.color(QPalette::Disabled, QPalette::Text); 0057 case ActiveTitleBarBackgroundRole: 0058 return item.activeTitleBarBackground; 0059 case ActiveTitleBarForegroundRole: 0060 return item.activeTitleBarForeground; 0061 case PendingDeletionRole: 0062 return item.pendingDeletion; 0063 case RemovableRole: 0064 return item.removable; 0065 case AccentActiveTitlebarRole: 0066 return item.accentActiveTitlebar; 0067 case Tints: 0068 return item.tints; 0069 case TintFactor: 0070 return item.tintFactor; 0071 } 0072 0073 return QVariant(); 0074 } 0075 0076 bool ColorsModel::setData(const QModelIndex &index, const QVariant &value, int role) 0077 { 0078 if (!index.isValid() || index.row() >= m_data.count()) { 0079 return false; 0080 } 0081 0082 if (role == PendingDeletionRole) { 0083 auto &item = m_data[index.row()]; 0084 0085 const bool pendingDeletion = value.toBool(); 0086 0087 if (item.pendingDeletion != pendingDeletion) { 0088 item.pendingDeletion = pendingDeletion; 0089 Q_EMIT dataChanged(index, index, {PendingDeletionRole}); 0090 0091 if (index.row() == selectedSchemeIndex() && pendingDeletion) { 0092 // move to the next non-pending theme 0093 const auto nonPending = match(index, PendingDeletionRole, false); 0094 if (!nonPending.isEmpty()) { 0095 setSelectedScheme(nonPending.first().data(SchemeNameRole).toString()); 0096 } 0097 } 0098 0099 Q_EMIT pendingDeletionsChanged(); 0100 return true; 0101 } 0102 } 0103 0104 return false; 0105 } 0106 0107 QHash<int, QByteArray> ColorsModel::roleNames() const 0108 { 0109 return { 0110 {Qt::DisplayRole, QByteArrayLiteral("display")}, 0111 {SchemeNameRole, QByteArrayLiteral("schemeName")}, 0112 {PaletteRole, QByteArrayLiteral("palette")}, 0113 {ActiveTitleBarBackgroundRole, QByteArrayLiteral("activeTitleBarBackground")}, 0114 {ActiveTitleBarForegroundRole, QByteArrayLiteral("activeTitleBarForeground")}, 0115 {DisabledText, QByteArrayLiteral("disabledText")}, 0116 {RemovableRole, QByteArrayLiteral("removable")}, 0117 {AccentActiveTitlebarRole, QByteArrayLiteral("accentActiveTitlebar")}, 0118 {PendingDeletionRole, QByteArrayLiteral("pendingDeletion")}, 0119 {Tints, QByteArrayLiteral("tints")}, 0120 {TintFactor, QByteArrayLiteral("tintFactor")}, 0121 }; 0122 } 0123 0124 QString ColorsModel::selectedScheme() const 0125 { 0126 return m_selectedScheme; 0127 } 0128 0129 void ColorsModel::setSelectedScheme(const QString &scheme) 0130 { 0131 if (m_selectedScheme == scheme) { 0132 return; 0133 } 0134 0135 m_selectedScheme = scheme; 0136 0137 Q_EMIT selectedSchemeChanged(scheme); 0138 Q_EMIT selectedSchemeIndexChanged(); 0139 } 0140 0141 int ColorsModel::indexOfScheme(const QString &scheme) const 0142 { 0143 auto it = std::find_if(m_data.begin(), m_data.end(), [&scheme](const ColorsModelData &item) { 0144 return item.schemeName == scheme; 0145 }); 0146 0147 if (it != m_data.end()) { 0148 return std::distance(m_data.begin(), it); 0149 } 0150 0151 return -1; 0152 } 0153 0154 int ColorsModel::selectedSchemeIndex() const 0155 { 0156 return indexOfScheme(m_selectedScheme); 0157 } 0158 0159 void ColorsModel::load() 0160 { 0161 beginResetModel(); 0162 0163 const int oldCount = m_data.count(); 0164 0165 m_data.clear(); 0166 0167 QStringList schemeFiles; 0168 0169 const QStringList schemeDirs = 0170 QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("color-schemes"), QStandardPaths::LocateDirectory); 0171 for (const QString &dir : schemeDirs) { 0172 const QStringList fileNames = QDir(dir).entryList(QStringList{QStringLiteral("*.colors")}); 0173 for (const QString &file : fileNames) { 0174 const QString suffixedFileName = QLatin1String("color-schemes/") + file; 0175 // can't use QSet because of the transform below (passing const QString as this argument discards qualifiers) 0176 if (!schemeFiles.contains(suffixedFileName)) { 0177 schemeFiles.append(suffixedFileName); 0178 } 0179 } 0180 } 0181 0182 std::transform(schemeFiles.begin(), schemeFiles.end(), schemeFiles.begin(), [](const QString &item) { 0183 return QStandardPaths::locate(QStandardPaths::GenericDataLocation, item); 0184 }); 0185 0186 for (const QString &schemeFile : schemeFiles) { 0187 const QFileInfo fi(schemeFile); 0188 const QString baseName = fi.baseName(); 0189 0190 KSharedConfigPtr config = KSharedConfig::openConfig(schemeFile, KConfig::SimpleConfig); 0191 KConfigGroup group(config, "General"); 0192 const QString name = group.readEntry("Name", baseName); 0193 0194 const QPalette palette = KColorScheme::createApplicationPalette(config); 0195 0196 QColor activeTitleBarBackground, activeTitleBarForeground; 0197 if (KColorScheme::isColorSetSupported(config, KColorScheme::Header)) { 0198 KColorScheme headerColorScheme(QPalette::Active, KColorScheme::Header, config); 0199 activeTitleBarBackground = headerColorScheme.background().color(); 0200 activeTitleBarForeground = headerColorScheme.foreground().color(); 0201 } else { 0202 KConfigGroup wmConfig(config, QStringLiteral("WM")); 0203 activeTitleBarBackground = wmConfig.readEntry("activeBackground", palette.color(QPalette::Active, QPalette::Highlight)); 0204 activeTitleBarForeground = wmConfig.readEntry("activeForeground", palette.color(QPalette::Active, QPalette::HighlightedText)); 0205 } 0206 0207 const bool colorActiveTitleBar = group.readEntry("accentActiveTitlebar", false); 0208 0209 ColorsModelData item{ 0210 name, 0211 baseName, 0212 palette, 0213 activeTitleBarBackground, 0214 activeTitleBarForeground, 0215 fi.isWritable(), 0216 colorActiveTitleBar, 0217 false, // pending deletion 0218 group.hasKey("TintFactor"), 0219 group.readEntry<qreal>("TintFactor", DefaultTintFactor), 0220 }; 0221 0222 m_data.append(item); 0223 } 0224 0225 // Sort case-insensitively 0226 QCollator collator; 0227 collator.setCaseSensitivity(Qt::CaseInsensitive); 0228 std::sort(m_data.begin(), m_data.end(), [&collator](const ColorsModelData &a, const ColorsModelData &b) { 0229 return collator.compare(a.display, b.display) < 0; 0230 }); 0231 0232 endResetModel(); 0233 0234 // an item might have been added before the currently selected one 0235 if (oldCount != m_data.count()) { 0236 Q_EMIT selectedSchemeIndexChanged(); 0237 } 0238 } 0239 0240 QStringList ColorsModel::pendingDeletions() const 0241 { 0242 QStringList pendingDeletions; 0243 0244 for (const auto &item : m_data) { 0245 if (item.pendingDeletion) { 0246 pendingDeletions.append(item.schemeName); 0247 } 0248 } 0249 0250 return pendingDeletions; 0251 } 0252 0253 void ColorsModel::removeItemsPendingDeletion() 0254 { 0255 for (int i = m_data.count() - 1; i >= 0; --i) { 0256 if (m_data.at(i).pendingDeletion) { 0257 beginRemoveRows(QModelIndex(), i, i); 0258 m_data.remove(i); 0259 endRemoveRows(); 0260 } 0261 } 0262 }