File indexing completed on 2024-04-14 14:20:59

0001 /*  This file is part of the KDE libraries
0002     SPDX-FileCopyrightText: 1999 Waldo Bastian <bastian@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005 */
0006 
0007 // KDE color collection
0008 
0009 #include "kcolorcollection.h"
0010 
0011 #include <QDir>
0012 #include <QFile>
0013 #include <QSaveFile>
0014 #include <QSharedData>
0015 #include <QStandardPaths>
0016 #include <QTextStream>
0017 
0018 // BEGIN KColorCollectionPrivate
0019 class KColorCollectionPrivate : public QSharedData
0020 {
0021 public:
0022     KColorCollectionPrivate(const QString &);
0023     KColorCollectionPrivate(const KColorCollectionPrivate &) = default;
0024     ~KColorCollectionPrivate()
0025     {
0026     }
0027     struct ColorNode {
0028         ColorNode(const QColor &c, const QString &n)
0029             : color(c)
0030             , name(n)
0031         {
0032         }
0033         QColor color;
0034         QString name;
0035     };
0036     QList<ColorNode> colorList;
0037 
0038     QString name;
0039     QString desc;
0040     KColorCollection::Editable editable;
0041 };
0042 
0043 KColorCollectionPrivate::KColorCollectionPrivate(const QString &_name)
0044     : name(_name)
0045 {
0046     if (name.isEmpty()) {
0047         return;
0048     }
0049 
0050     QString filename = QStandardPaths::locate(QStandardPaths::GenericConfigLocation, QLatin1String("colors/") + name);
0051     if (filename.isEmpty()) {
0052         return;
0053     }
0054 
0055     QFile paletteFile(filename);
0056     if (!paletteFile.exists()) {
0057         return;
0058     }
0059     if (!paletteFile.open(QIODevice::ReadOnly)) {
0060         return;
0061     }
0062 
0063     // Read first line
0064     // Expected "GIMP Palette"
0065     QString line = QString::fromLocal8Bit(paletteFile.readLine());
0066     if (line.contains(QLatin1String(" Palette"))) {
0067         return;
0068     }
0069 
0070     while (!paletteFile.atEnd()) {
0071         line = QString::fromLocal8Bit(paletteFile.readLine());
0072         if (line[0] == QLatin1Char('#')) {
0073             // This is a comment line
0074             line.remove(0, 1); // Strip '#'
0075             line = line.trimmed(); // Strip remaining white space..
0076             if (!line.isEmpty()) {
0077                 desc += line + QLatin1Char('\n'); // Add comment to description
0078             }
0079         } else {
0080             // This is a color line, hopefully
0081             line = line.trimmed();
0082             if (line.isEmpty()) {
0083                 continue;
0084             }
0085             int r;
0086             int g;
0087             int b;
0088             int pos = 0;
0089             if (sscanf(line.toLatin1().constData(), "%d %d %d%n", &r, &g, &b, &pos) >= 3) {
0090                 r = qBound(0, r, 255);
0091                 g = qBound(0, g, 255);
0092                 b = qBound(0, b, 255);
0093                 QString name = line.mid(pos).trimmed();
0094                 colorList.append(ColorNode(QColor(r, g, b), name));
0095             }
0096         }
0097     }
0098 }
0099 // END KColorCollectionPrivate
0100 
0101 QStringList KColorCollection::installedCollections()
0102 {
0103     const QStringList paletteDirs = QStandardPaths::locateAll(QStandardPaths::GenericConfigLocation, QStringLiteral("colors"), QStandardPaths::LocateDirectory);
0104 
0105     QStringList paletteList;
0106     for (const QString &dir : paletteDirs) {
0107         paletteList += QDir(dir).entryList(QDir::Files | QDir::NoDotAndDotDot);
0108     }
0109     paletteList.removeDuplicates();
0110 
0111     return paletteList;
0112 }
0113 
0114 KColorCollection::KColorCollection(const QString &name)
0115     : d(new KColorCollectionPrivate(name))
0116 {
0117 }
0118 
0119 KColorCollection::KColorCollection(const KColorCollection &p) = default;
0120 
0121 // Need auto-save?
0122 KColorCollection::~KColorCollection() = default;
0123 
0124 bool KColorCollection::save()
0125 {
0126     QString filename = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QLatin1String("/colors/") + d->name;
0127     QSaveFile sf(filename);
0128     if (!sf.open(QIODevice::WriteOnly)) {
0129         return false;
0130     }
0131 
0132     QTextStream str(&sf);
0133 
0134     QString description = d->desc.trimmed();
0135     description = QLatin1Char('#') + description.split(QLatin1Char('\n'), Qt::KeepEmptyParts).join(QLatin1String("\n#"));
0136 
0137     str << QLatin1String("KDE RGB Palette\n");
0138     str << description << QLatin1Char('\n');
0139     for (const KColorCollectionPrivate::ColorNode &node : std::as_const(d->colorList)) {
0140         int r;
0141         int g;
0142         int b;
0143         node.color.getRgb(&r, &g, &b);
0144         str << r << " " << g << " " << b << " " << node.name << "\n";
0145     }
0146 
0147     return sf.commit();
0148 }
0149 
0150 QString KColorCollection::description() const
0151 {
0152     return d->desc;
0153 }
0154 
0155 void KColorCollection::setDescription(const QString &desc)
0156 {
0157     d->desc = desc;
0158 }
0159 
0160 QString KColorCollection::name() const
0161 {
0162     return d->name;
0163 }
0164 
0165 void KColorCollection::setName(const QString &name)
0166 {
0167     d->name = name;
0168 }
0169 
0170 KColorCollection::Editable KColorCollection::editable() const
0171 {
0172     return d->editable;
0173 }
0174 
0175 void KColorCollection::setEditable(Editable editable)
0176 {
0177     d->editable = editable;
0178 }
0179 
0180 int KColorCollection::count() const
0181 {
0182     return d->colorList.count();
0183 }
0184 
0185 KColorCollection &KColorCollection::operator=(const KColorCollection &p) = default;
0186 
0187 QColor KColorCollection::color(int index) const
0188 {
0189     if ((index < 0) || (index >= count())) {
0190         return QColor();
0191     }
0192 
0193     return d->colorList[index].color;
0194 }
0195 
0196 int KColorCollection::findColor(const QColor &color) const
0197 {
0198     for (int i = 0; i < d->colorList.size(); ++i) {
0199         if (d->colorList[i].color == color) {
0200             return i;
0201         }
0202     }
0203     return -1;
0204 }
0205 
0206 QString KColorCollection::name(int index) const
0207 {
0208     if ((index < 0) || (index >= count())) {
0209         return QString();
0210     }
0211 
0212     return d->colorList[index].name;
0213 }
0214 
0215 QString KColorCollection::name(const QColor &color) const
0216 {
0217     return name(findColor(color));
0218 }
0219 
0220 int KColorCollection::addColor(const QColor &newColor, const QString &newColorName)
0221 {
0222     d->colorList.append(KColorCollectionPrivate::ColorNode(newColor, newColorName));
0223     return count() - 1;
0224 }
0225 
0226 int KColorCollection::changeColor(int index, const QColor &newColor, const QString &newColorName)
0227 {
0228     if ((index < 0) || (index >= count())) {
0229         return -1;
0230     }
0231 
0232     KColorCollectionPrivate::ColorNode &node = d->colorList[index];
0233     node.color = newColor;
0234     node.name = newColorName;
0235 
0236     return index;
0237 }
0238 
0239 int KColorCollection::changeColor(const QColor &oldColor, const QColor &newColor, const QString &newColorName)
0240 {
0241     return changeColor(findColor(oldColor), newColor, newColorName);
0242 }