Warning, file /utilities/konsole/src/colorscheme/ColorSchemeManager.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002     This source file is part of Konsole, a terminal emulator.
0003 
0004     SPDX-FileCopyrightText: 2007-2008 Robert Knight <robertknight@gmail.com>
0005     SPDX-FileCopyrightText: 2018 Harald Sitter <sitter@kde.org>
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 
0010 // Own
0011 #include "ColorSchemeManager.h"
0012 
0013 #include "colorschemedebug.h"
0014 
0015 // Qt
0016 #include <QDir>
0017 #include <QFile>
0018 #include <QFileInfo>
0019 
0020 // KDE
0021 #include <KConfig>
0022 
0023 using namespace Konsole;
0024 
0025 ColorSchemeManager::ColorSchemeManager()
0026 {
0027 }
0028 
0029 Q_GLOBAL_STATIC(ColorSchemeManager, theColorSchemeManager)
0030 
0031 ColorSchemeManager *ColorSchemeManager::instance()
0032 {
0033     return theColorSchemeManager;
0034 }
0035 
0036 QList<std::shared_ptr<const ColorScheme>> ColorSchemeManager::allColorSchemes()
0037 {
0038     int failed = 0;
0039 
0040     QList<std::shared_ptr<const ColorScheme>> ret;
0041     for (const QString &name : listColorSchemes()) {
0042         std::shared_ptr<const ColorScheme> scheme = findColorScheme(colorSchemeNameFromPath(name));
0043         if (!scheme) {
0044             failed++;
0045             continue;
0046         }
0047         ret.append(scheme);
0048     }
0049 
0050     if (failed > 0) {
0051         qCDebug(ColorSchemeDebug) << "failed to load " << failed << " color schemes.";
0052     }
0053 
0054     return ret;
0055 }
0056 
0057 std::shared_ptr<const ColorScheme> ColorSchemeManager::loadColorScheme(const QString &filePath)
0058 {
0059     if (!pathIsColorScheme(filePath) || !QFile::exists(filePath)) {
0060         return nullptr;
0061     }
0062 
0063     const QString name = colorSchemeNameFromPath(filePath);
0064 
0065     KConfig config(filePath, KConfig::NoGlobals);
0066     std::shared_ptr<ColorScheme> scheme = std::make_shared<ColorScheme>();
0067     scheme->setName(name);
0068     scheme->read(config);
0069 
0070     if (scheme->name().isEmpty()) {
0071         qCDebug(ColorSchemeDebug) << "Color scheme in" << filePath << "does not have a valid name and was not loaded.";
0072         return nullptr;
0073     }
0074 
0075     if (!_colorSchemes.contains(name)) {
0076         _colorSchemes.insert(scheme->name(), scheme);
0077     } else {
0078         // qDebug() << "color scheme with name" << scheme->name() << "has already been" <<
0079         //         "found, replacing.";
0080 
0081         _colorSchemes[name] = scheme;
0082     }
0083 
0084     return scheme;
0085 }
0086 
0087 bool ColorSchemeManager::unloadColorScheme(const QString &filePath)
0088 {
0089     if (!pathIsColorScheme(filePath)) {
0090         return false;
0091     }
0092     _colorSchemes.remove(colorSchemeNameFromPath(filePath));
0093     return true;
0094 }
0095 
0096 QString ColorSchemeManager::colorSchemeNameFromPath(const QString &path)
0097 {
0098     if (!pathIsColorScheme(path)) {
0099         return QString();
0100     }
0101     return QFileInfo(path).completeBaseName();
0102 }
0103 
0104 QStringList ColorSchemeManager::listColorSchemes()
0105 {
0106     QStringList colorschemes;
0107     const QStringList dirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("konsole"), QStandardPaths::LocateDirectory);
0108     colorschemes.reserve(dirs.size());
0109 
0110     for (const QString &dir : dirs) {
0111         const QStringList fileNames = QDir(dir).entryList(QStringList() << QStringLiteral("*.colorscheme"));
0112         for (const QString &file : fileNames) {
0113             colorschemes.append(dir + QLatin1Char('/') + file);
0114         }
0115     }
0116     return colorschemes;
0117 }
0118 
0119 const std::shared_ptr<const ColorScheme> &ColorSchemeManager::defaultColorScheme() const
0120 {
0121     static const std::shared_ptr<const ColorScheme> defaultScheme = std::make_shared<const ColorScheme>();
0122     return defaultScheme;
0123 }
0124 
0125 void ColorSchemeManager::addColorScheme(const std::shared_ptr<ColorScheme> &scheme)
0126 {
0127     _colorSchemes[scheme->name()] = scheme;
0128 
0129     // save changes to disk
0130 
0131     const QString dir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QStringLiteral("/konsole/");
0132     QDir().mkpath(dir);
0133     const QString path = dir + scheme->name() + QStringLiteral(".colorscheme");
0134     KConfig config(path, KConfig::NoGlobals);
0135 
0136     scheme->write(config);
0137 }
0138 
0139 bool ColorSchemeManager::deleteColorScheme(const QString &name)
0140 {
0141     Q_ASSERT(_colorSchemes.contains(name));
0142 
0143     // look up the path and delete
0144     QString path = findColorSchemePath(name);
0145     if (QFile::remove(path)) {
0146         _colorSchemes.remove(name);
0147         return true;
0148     }
0149     qCDebug(ColorSchemeDebug) << "Failed to remove color scheme -" << path;
0150     return false;
0151 }
0152 
0153 std::shared_ptr<const ColorScheme> ColorSchemeManager::findColorScheme(const QString &name)
0154 {
0155     if (name.isEmpty()) {
0156         return defaultColorScheme();
0157     }
0158 
0159     // A fix to prevent infinite loops if users puts / in ColorScheme name
0160     // Konsole will create a sub-folder in that case (bko 315086)
0161     // More code will have to go in to prevent the users from doing that.
0162     if (name.contains(QLatin1String("/"))) {
0163         qCDebug(ColorSchemeDebug) << name << " has an invalid character / in the name ... skipping";
0164         return defaultColorScheme();
0165     }
0166 
0167     if (_colorSchemes.contains(name)) {
0168         std::shared_ptr<const ColorScheme> colorScheme = _colorSchemes.value(name).lock();
0169         if (colorScheme) {
0170             return colorScheme;
0171         } else {
0172             // Remove outdated weak pointer
0173             _colorSchemes.remove(name);
0174         }
0175     }
0176     // look for this color scheme
0177     QString path = findColorSchemePath(name);
0178     if (path.isEmpty()) {
0179         qCDebug(ColorSchemeDebug) << "Could not find color scheme - " << name;
0180         return nullptr;
0181     }
0182     return loadColorScheme(path);
0183 }
0184 
0185 QString ColorSchemeManager::findColorSchemePath(const QString &name) const
0186 {
0187     QString path = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("konsole/") + name + QStringLiteral(".colorscheme"));
0188 
0189     if (!path.isEmpty()) {
0190         return path;
0191     }
0192 
0193     return QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("konsole/") + name + QStringLiteral(".schema"));
0194 }
0195 
0196 bool ColorSchemeManager::pathIsColorScheme(const QString &path)
0197 {
0198     return path.endsWith(QLatin1String(".colorscheme"));
0199 }
0200 
0201 bool ColorSchemeManager::isColorSchemeDeletable(const QString &name)
0202 {
0203     QFileInfo fileInfo(findColorSchemePath(name));
0204     QFileInfo dirInfo(fileInfo.path());
0205 
0206     return dirInfo.isWritable();
0207 }
0208 
0209 bool ColorSchemeManager::canResetColorScheme(const QString &name)
0210 {
0211     const QStringList paths =
0212         QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("konsole/") + name + QStringLiteral(".colorscheme"));
0213 
0214     // if the colorscheme exists in both a writable location under the
0215     // user's home dir and a system-wide location, then it's possible
0216     // to delete the colorscheme under the user's home dir so that the
0217     // colorscheme from the system-wide location can be used instead,
0218     // i.e. resetting the colorscheme
0219     return (paths.count() > 1);
0220 }