File indexing completed on 2024-04-28 05:50:42
0001 /* 0002 This source file is part of Konsole, a terminal emulator. 0003 0004 SPDX-FileCopyrightText: 2007-2008 Robert Knight <robertknight@gmail.com> 0005 0006 SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 0009 // Own 0010 #include "KeyboardTranslatorManager.h" 0011 0012 #include "FallbackKeyboardTranslator.h" 0013 #include "KeyboardTranslatorReader.h" 0014 #include "KeyboardTranslatorWriter.h" 0015 0016 // Qt 0017 #include <QDir> 0018 #include <QFile> 0019 #include <QFileInfo> 0020 #include <QStandardPaths> 0021 0022 using namespace Konsole; 0023 0024 KeyboardTranslatorManager::KeyboardTranslatorManager() 0025 : _haveLoadedAll(false) 0026 , _fallbackTranslator(nullptr) 0027 , _translators(QHash<QString, KeyboardTranslator *>()) 0028 { 0029 _fallbackTranslator = new FallbackKeyboardTranslator(); 0030 } 0031 0032 KeyboardTranslatorManager::~KeyboardTranslatorManager() 0033 { 0034 qDeleteAll(_translators); 0035 delete _fallbackTranslator; 0036 } 0037 0038 Q_GLOBAL_STATIC(KeyboardTranslatorManager, theKeyboardTranslatorManager) 0039 KeyboardTranslatorManager *KeyboardTranslatorManager::instance() 0040 { 0041 return theKeyboardTranslatorManager; 0042 } 0043 0044 void KeyboardTranslatorManager::addTranslator(KeyboardTranslator *translator) 0045 { 0046 _translators.insert(translator->name(), translator); 0047 0048 if (!saveTranslator(translator)) { 0049 qCDebug(KonsoleKeyTrDebug) << "Unable to save translator" << translator->name() << "to disk."; 0050 } 0051 } 0052 0053 bool KeyboardTranslatorManager::deleteTranslator(const QString &name) 0054 { 0055 Q_ASSERT(_translators.contains(name)); 0056 0057 // locate and delete 0058 QString path = findTranslatorPath(name); 0059 if (QFile::remove(path)) { 0060 _translators.remove(name); 0061 return true; 0062 } 0063 qCDebug(KonsoleKeyTrDebug) << "Failed to remove translator - " << path; 0064 return false; 0065 } 0066 0067 bool KeyboardTranslatorManager::isTranslatorDeletable(const QString &name) const 0068 { 0069 const QString &dir = QFileInfo(findTranslatorPath(name)).path(); 0070 return QFileInfo(dir).isWritable(); 0071 } 0072 0073 bool KeyboardTranslatorManager::isTranslatorResettable(const QString &name) const 0074 { 0075 const QStringList &paths = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("konsole/") + name + QStringLiteral(".keytab")); 0076 0077 return (paths.count() > 1); 0078 } 0079 0080 const QString KeyboardTranslatorManager::findTranslatorPath(const QString &name) const 0081 { 0082 return QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("konsole/") + name + QStringLiteral(".keytab")); 0083 } 0084 0085 void KeyboardTranslatorManager::findTranslators() 0086 { 0087 QStringList list; 0088 const QStringList dirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("konsole"), QStandardPaths::LocateDirectory); 0089 list.reserve(dirs.size()); 0090 0091 for (const QString &dir : dirs) { 0092 const QStringList fileNames = QDir(dir).entryList(QStringList() << QStringLiteral("*.keytab")); 0093 for (const QString &file : fileNames) { 0094 list.append(dir + QLatin1Char('/') + file); 0095 } 0096 } 0097 0098 // add the name of each translator to the list and associated 0099 // the name with a null pointer to indicate that the translator 0100 // has not yet been loaded from disk 0101 for (const QString &translatorPath : std::as_const(list)) { 0102 QString name = QFileInfo(translatorPath).completeBaseName(); 0103 0104 if (!_translators.contains(name)) { 0105 _translators.insert(name, nullptr); 0106 } 0107 } 0108 0109 _haveLoadedAll = true; 0110 } 0111 0112 const KeyboardTranslator *KeyboardTranslatorManager::findTranslator(const QString &name) 0113 { 0114 if (name.isEmpty()) { 0115 return defaultTranslator(); 0116 } 0117 0118 if (_translators.contains(name) && _translators[name] != nullptr) { 0119 return _translators[name]; 0120 } 0121 0122 KeyboardTranslator *translator = loadTranslator(name); 0123 0124 if (translator != nullptr) { 0125 _translators[name] = translator; 0126 } else if (!name.isEmpty()) { 0127 qCDebug(KonsoleKeyTrDebug) << "Unable to load translator" << name; 0128 } 0129 0130 return translator; 0131 } 0132 0133 bool KeyboardTranslatorManager::saveTranslator(const KeyboardTranslator *translator) 0134 { 0135 const QString dir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QStringLiteral("/konsole/"); 0136 QDir().mkpath(dir); 0137 const QString path = dir + translator->name() + QStringLiteral(".keytab"); 0138 0139 ////qDebug() << "Saving translator to" << path; 0140 0141 QFile destination(path); 0142 if (!destination.open(QIODevice::WriteOnly | QIODevice::Text)) { 0143 qCDebug(KonsoleKeyTrDebug) << "Unable to save keyboard translation:" << destination.errorString(); 0144 return false; 0145 } 0146 0147 { 0148 KeyboardTranslatorWriter writer(&destination); 0149 writer.writeHeader(translator->description()); 0150 const QList<KeyboardTranslator::Entry> entriesList = translator->entries(); 0151 for (const KeyboardTranslator::Entry &entry : entriesList) { 0152 writer.writeEntry(entry); 0153 } 0154 } 0155 0156 destination.close(); 0157 0158 return true; 0159 } 0160 0161 KeyboardTranslator *KeyboardTranslatorManager::loadTranslator(const QString &name) 0162 { 0163 const QString &path = findTranslatorPath(name); 0164 0165 QFile source(path); 0166 if (name.isEmpty() || !source.open(QIODevice::ReadOnly | QIODevice::Text)) { 0167 return nullptr; 0168 } 0169 0170 return loadTranslator(&source, name); 0171 } 0172 0173 KeyboardTranslator *KeyboardTranslatorManager::loadTranslator(QIODevice *source, const QString &name) 0174 { 0175 auto translator = new KeyboardTranslator(name); 0176 KeyboardTranslatorReader reader(source); 0177 translator->setDescription(reader.description()); 0178 while (reader.hasNextEntry()) { 0179 translator->addEntry(reader.nextEntry()); 0180 } 0181 0182 source->close(); 0183 0184 if (!reader.parseError()) { 0185 return translator; 0186 } 0187 delete translator; 0188 return nullptr; 0189 } 0190 0191 const KeyboardTranslator *KeyboardTranslatorManager::defaultTranslator() 0192 { 0193 // Try to find the default.keytab file if it exists, otherwise 0194 // fall back to the internal hard-coded fallback translator 0195 const KeyboardTranslator *translator = findTranslator(QStringLiteral("default")); 0196 if (translator == nullptr) { 0197 translator = _fallbackTranslator; 0198 } 0199 return translator; 0200 } 0201 0202 const QStringList KeyboardTranslatorManager::allTranslators() 0203 { 0204 if (!_haveLoadedAll) { 0205 findTranslators(); 0206 } 0207 0208 return _translators.keys(); 0209 }