1/* This file is part of the KDE libraries
2 SPDX-FileCopyrightText: 1999 Waldo Bastian <bastian@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5*/
6
7// KDE color collection
8
9#include "kcolorcollection.h"
10
11#include <QDir>
12#include <QFile>
13#include <QSaveFile>
14#include <QSharedData>
15#include <QStandardPaths>
16#include <QTextStream>
17
18// BEGIN KColorCollectionPrivate
19class KColorCollectionPrivate : public QSharedData
20{
21public:
22 KColorCollectionPrivate(const QString &);
23 KColorCollectionPrivate(const KColorCollectionPrivate &) = default;
24 ~KColorCollectionPrivate()
25 {
26 }
27 struct ColorNode {
28 ColorNode(const QColor &c, const QString &n)
29 : color(c)
30 , name(n)
31 {
32 }
33 QColor color;
34 QString name;
35 };
36 QList<ColorNode> colorList;
37
38 QString name;
39 QString desc;
40 KColorCollection::Editable editable;
41};
42
43KColorCollectionPrivate::KColorCollectionPrivate(const QString &_name)
44 : name(_name)
45{
46 if (name.isEmpty()) {
47 return;
48 }
49
50 QString filename = QStandardPaths::locate(QStandardPaths::GenericConfigLocation, QLatin1String("colors/") + name);
51 if (filename.isEmpty()) {
52 return;
53 }
54
55 QFile paletteFile(filename);
56 if (!paletteFile.exists()) {
57 return;
58 }
59 if (!paletteFile.open(QIODevice::ReadOnly)) {
60 return;
61 }
62
63 // Read first line
64 // Expected "GIMP Palette"
65 QString line = QString::fromLocal8Bit(paletteFile.readLine());
66 if (line.contains(QLatin1String(" Palette"))) {
67 return;
68 }
69
70 while (!paletteFile.atEnd()) {
71 line = QString::fromLocal8Bit(paletteFile.readLine());
72 if (line[0] == QLatin1Char('#')) {
73 // This is a comment line
74 line.remove(0, 1); // Strip '#'
75 line = line.trimmed(); // Strip remaining white space..
76 if (!line.isEmpty()) {
77 desc += line + QLatin1Char('\n'); // Add comment to description
78 }
79 } else {
80 // This is a color line, hopefully
81 line = line.trimmed();
82 if (line.isEmpty()) {
83 continue;
84 }
85 int r;
86 int g;
87 int b;
88 int pos = 0;
89 if (sscanf(line.toLatin1().constData(), "%d %d %d%n", &r, &g, &b, &pos) >= 3) {
90 r = qBound(0, r, 255);
91 g = qBound(0, g, 255);
92 b = qBound(0, b, 255);
93 QString name = line.mid(pos).trimmed();
94 colorList.append(ColorNode(QColor(r, g, b), name));
95 }
96 }
97 }
98}
99// END KColorCollectionPrivate
100
101QStringList KColorCollection::installedCollections()
102{
103 const QStringList paletteDirs = QStandardPaths::locateAll(QStandardPaths::GenericConfigLocation, QStringLiteral("colors"), QStandardPaths::LocateDirectory);
104
105 QStringList paletteList;
106 for (const QString &dir : paletteDirs) {
107 paletteList += QDir(dir).entryList(QDir::Files | QDir::NoDotAndDotDot);
108 }
109 paletteList.removeDuplicates();
110
111 return paletteList;
112}
113
114KColorCollection::KColorCollection(const QString &name)
115 : d(new KColorCollectionPrivate(name))
116{
117}
118
119KColorCollection::KColorCollection(const KColorCollection &p) = default;
120
121// Need auto-save?
122KColorCollection::~KColorCollection() = default;
123
124bool KColorCollection::save()
125{
126 QString filename = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QLatin1String("/colors/") + d->name;
127 QSaveFile sf(filename);
128 if (!sf.open(QIODevice::WriteOnly)) {
129 return false;
130 }
131
132 QTextStream str(&sf);
133
134 QString description = d->desc.trimmed();
135 description = QLatin1Char('#') + description.split(QLatin1Char('\n'), Qt::KeepEmptyParts).join(QLatin1String("\n#"));
136
137 str << QLatin1String("KDE RGB Palette\n");
138 str << description << QLatin1Char('\n');
139 for (const KColorCollectionPrivate::ColorNode &node : std::as_const(d->colorList)) {
140 int r;
141 int g;
142 int b;
143 node.color.getRgb(&r, &g, &b);
144 str << r << " " << g << " " << b << " " << node.name << "\n";
145 }
146
147 return sf.commit();
148}
149
150QString KColorCollection::description() const
151{
152 return d->desc;
153}
154
155void KColorCollection::setDescription(const QString &desc)
156{
157 d->desc = desc;
158}
159
160QString KColorCollection::name() const
161{
162 return d->name;
163}
164
165void KColorCollection::setName(const QString &name)
166{
167 d->name = name;
168}
169
170KColorCollection::Editable KColorCollection::editable() const
171{
172 return d->editable;
173}
174
175void KColorCollection::setEditable(Editable editable)
176{
177 d->editable = editable;
178}
179
180int KColorCollection::count() const
181{
182 return d->colorList.count();
183}
184
185KColorCollection &KColorCollection::operator=(const KColorCollection &p) = default;
186
187QColor KColorCollection::color(int index) const
188{
189 if ((index < 0) || (index >= count())) {
190 return QColor();
191 }
192
193 return d->colorList[index].color;
194}
195
196int KColorCollection::findColor(const QColor &color) const
197{
198 for (int i = 0; i < d->colorList.size(); ++i) {
199 if (d->colorList[i].color == color) {
200 return i;
201 }
202 }
203 return -1;
204}
205
206QString KColorCollection::name(int index) const
207{
208 if ((index < 0) || (index >= count())) {
209 return QString();
210 }
211
212 return d->colorList[index].name;
213}
214
215QString KColorCollection::name(const QColor &color) const
216{
217 return name(findColor(color));
218}
219
220int KColorCollection::addColor(const QColor &newColor, const QString &newColorName)
221{
222 d->colorList.append(KColorCollectionPrivate::ColorNode(newColor, newColorName));
223 return count() - 1;
224}
225
226int KColorCollection::changeColor(int index, const QColor &newColor, const QString &newColorName)
227{
228 if ((index < 0) || (index >= count())) {
229 return -1;
230 }
231
232 KColorCollectionPrivate::ColorNode &node = d->colorList[index];
233 node.color = newColor;
234 node.name = newColorName;
235
236 return index;
237}
238
239int KColorCollection::changeColor(const QColor &oldColor, const QColor &newColor, const QString &newColorName)
240{
241 return changeColor(findColor(oldColor), newColor, newColorName);
242}
243

source code of kguiaddons/src/colors/kcolorcollection.cpp