File indexing completed on 2024-05-12 15:59:52
0001 /* 0002 * SPDX-FileCopyrightText: 2018 Boudewijn Rempt <boud@valdyas.org> 0003 * 0004 * SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "KisTag.h" 0008 0009 #include <QIODevice> 0010 #include <QLocale> 0011 #include <QBuffer> 0012 #include <QByteArray> 0013 #include <QStandardPaths> 0014 #include <QFile> 0015 #include <QTextCodec> 0016 #include <QTextStream> 0017 0018 #include <KLocalizedString> 0019 0020 #include <kis_debug.h> 0021 0022 const QString KisTag::s_group {"Desktop Entry"}; 0023 const QString KisTag::s_type {"Type"}; 0024 const QString KisTag::s_tag {"Tag"}; 0025 const QString KisTag::s_name {"Name"}; 0026 const QString KisTag::s_resourceType {"ResourceType"}; 0027 const QString KisTag::s_url {"URL"}; 0028 const QString KisTag::s_comment {"Comment"}; 0029 const QString KisTag::s_defaultResources {"Default Resources"}; 0030 const QString KisTag::s_desktop {"[Desktop Entry]"}; 0031 0032 class KisTag::Private { 0033 public: 0034 bool valid {false}; 0035 QString url; // This is the actual tag 0036 QString name; 0037 QString comment; 0038 QMap<QString, QString> names; // The translated tag names 0039 QMap<QString, QString> comments; // The translated tag comments 0040 QStringList defaultResources; // The list of resources as defined in the tag file 0041 QString resourceType; // The resource type this tag can be applied to 0042 QString filename; // the original filename for the tag 0043 int id {-1}; 0044 bool active{true}; 0045 }; 0046 0047 KisTag::KisTag() 0048 : d(new Private) 0049 { 0050 } 0051 0052 KisTag::~KisTag() 0053 { 0054 } 0055 0056 KisTag::KisTag(const KisTag &rhs) 0057 : d(new Private) 0058 { 0059 *this = rhs; 0060 } 0061 0062 KisTag &KisTag::operator=(const KisTag &rhs) 0063 { 0064 if (this != &rhs) { 0065 d->valid = rhs.d->valid; 0066 d->url = rhs.d->url; 0067 d->name = rhs.d->name; 0068 d->comment = rhs.d->comment; 0069 d->names = rhs.d->names; 0070 d->comments = rhs.d->comments; 0071 d->defaultResources = rhs.d->defaultResources; d->resourceType = rhs.d->resourceType; 0072 d->filename = rhs.d->filename; 0073 d->id = rhs.d->id; 0074 d->active = rhs.d->active; 0075 } 0076 return *this; 0077 } 0078 0079 KisTagSP KisTag::clone() const 0080 { 0081 return KisTagSP(new KisTag(*this)); 0082 } 0083 0084 QString KisTag::currentLocale() 0085 { 0086 const QStringList languages = KLocalizedString::languages(); 0087 QString locale; 0088 if (languages.isEmpty()) { 0089 locale = QLocale().name(); 0090 } 0091 else { 0092 locale = languages.first(); 0093 } 0094 return locale; 0095 } 0096 0097 bool KisTag::valid() const 0098 { 0099 return d->valid; 0100 } 0101 0102 int KisTag::id() const 0103 { 0104 return d->id; 0105 } 0106 0107 bool KisTag::active() const 0108 { 0109 return d->active; 0110 } 0111 0112 QString KisTag::filename() 0113 { 0114 return d->filename; 0115 } 0116 0117 void KisTag::setFilename(const QString &filename) 0118 { 0119 d->filename = filename; 0120 } 0121 0122 QString KisTag::name(bool translated) const 0123 { 0124 if (translated && d->names.contains(currentLocale())) { 0125 return d->names[currentLocale()]; 0126 } 0127 Q_ASSERT(!d->name.isEmpty()); 0128 return d->name; 0129 } 0130 0131 void KisTag::setName(const QString &name) 0132 { 0133 d->name = name; 0134 } 0135 0136 QMap<QString, QString> KisTag::names() const 0137 { 0138 return d->names; 0139 } 0140 0141 void KisTag::setNames(const QMap<QString, QString> &names) 0142 { 0143 d->names = names; 0144 } 0145 0146 QString KisTag::comment(bool translated) const 0147 { 0148 if (translated && d->comments.contains(currentLocale())) { 0149 return d->comments[currentLocale()]; 0150 } 0151 return d->comment; 0152 } 0153 0154 void KisTag::setComment(const QString comment) 0155 { 0156 d->comment = comment; 0157 } 0158 0159 QString KisTag::url() const 0160 { 0161 return d->url; 0162 } 0163 0164 void KisTag::setUrl(const QString &url) 0165 { 0166 d->url = url; 0167 } 0168 0169 0170 QMap<QString, QString> KisTag::comments() const 0171 { 0172 return d->comments; 0173 } 0174 0175 void KisTag::setComments(const QMap<QString, QString> &comments) 0176 { 0177 d->comments = comments; 0178 } 0179 0180 QString KisTag::resourceType() const 0181 { 0182 return d->resourceType; 0183 } 0184 0185 void KisTag::setResourceType(const QString &resourceType) 0186 { 0187 d->resourceType = resourceType; 0188 } 0189 0190 QStringList KisTag::defaultResources() const 0191 { 0192 return d->defaultResources; 0193 } 0194 0195 void KisTag::setDefaultResources(const QStringList &defaultResources) 0196 { 0197 d->defaultResources = defaultResources; 0198 } 0199 0200 bool KisTag::load(QIODevice &io) 0201 { 0202 if (!io.isOpen()) { 0203 io.open(QIODevice::ReadOnly); 0204 } 0205 KIS_ASSERT(io.isOpen()); 0206 0207 setValid(false); 0208 0209 QTextStream stream(&io); 0210 stream.setCodec("UTF-8"); 0211 QStringList lines; 0212 QString line; 0213 0214 while (stream.readLineInto(&line)) { 0215 lines << line; 0216 } 0217 0218 if (lines.length() < 6 ) { 0219 qWarning() << d->filename << ": Incomplete tag file" << lines.length(); 0220 return false; 0221 } 0222 if (lines[0].toUpper() != s_desktop.toUpper()) { 0223 qWarning() << d->filename << ":Invalid tag file" << lines[0]; 0224 return false; 0225 } 0226 0227 lines.removeFirst(); 0228 0229 Q_FOREACH(const QString line, lines) { 0230 if (line.isEmpty()) { 0231 continue; 0232 } 0233 0234 if (!line.contains("=")) { 0235 qWarning() << "Found invalid line:" << line; 0236 continue; 0237 } 0238 int isPos = line.indexOf("="); 0239 QString key = line.left(isPos).trimmed(); 0240 QString value = line.right(line.size() - (isPos + 1)).trimmed(); 0241 0242 if (key == s_url) { 0243 d->url = value; 0244 } 0245 else if (key == s_resourceType) { 0246 d->resourceType = value; 0247 } 0248 else if (key == s_defaultResources) { 0249 d->defaultResources = value.split(',', QString::SkipEmptyParts); 0250 } 0251 else if (key == s_name) { 0252 d->name = value; 0253 } 0254 else if (key == s_comment) { 0255 d->comment = value; 0256 } 0257 else if (key.startsWith(s_name + "[")) { 0258 int start = key.indexOf('[') + 1; 0259 int len = key.size() - (s_name.size() + 2); 0260 QString language = key.mid(start, len); 0261 d->names[language] = value; 0262 } 0263 else if (key.startsWith(s_comment + "[")) { 0264 int start = key.indexOf('[') + 1; 0265 int len = key.size() - (s_comment.size() + 2); 0266 QString language = key.mid(start, len); 0267 d->comments[language] = value; 0268 } 0269 } 0270 0271 setValid(true); 0272 0273 return true; 0274 } 0275 0276 bool KisTag::save(QIODevice &io) 0277 { 0278 if (!io.isOpen()) { 0279 io.open(QIODevice::WriteOnly | QIODevice::Text); 0280 } 0281 0282 QTextStream stream(&io); 0283 stream.setCodec("UTF-8"); 0284 stream << s_desktop << '\n'; 0285 stream << s_type << '=' << s_tag << '\n'; 0286 stream << s_url << '=' << d->url << '\n'; 0287 stream << s_resourceType << '=' << d->resourceType << '\n'; 0288 stream << s_name << '=' << d->name << '\n'; 0289 stream << s_comment << '=' << d->comment << '\n'; 0290 stream << s_defaultResources << '=' << d->defaultResources.join(',') << '\n'; 0291 0292 Q_FOREACH(const QString &language, d->names) { 0293 stream << s_name << '[' << language << "]=" << d->names[language] << '\n'; 0294 } 0295 0296 Q_FOREACH(const QString &language, d->comments) { 0297 stream << s_comment << '[' << language << "]=" << d->comments[language] << '\n'; 0298 } 0299 0300 return true; 0301 } 0302 0303 void KisTag::setId(int id) 0304 { 0305 d->id = id; 0306 } 0307 0308 void KisTag::setActive(bool active) 0309 { 0310 d->active = active; 0311 } 0312 0313 void KisTag::setValid(bool valid) 0314 { 0315 d->valid = valid; 0316 } 0317