File indexing completed on 2024-05-19 04:55:57
0001 /** 0002 * \file tagconfig.cpp 0003 * Tag related configuration. 0004 * 0005 * \b Project: Kid3 0006 * \author Urs Fleisch 0007 * \date 29 Jun 2013 0008 * 0009 * Copyright (C) 2013-2024 Urs Fleisch 0010 * 0011 * This file is part of Kid3. 0012 * 0013 * Kid3 is free software; you can redistribute it and/or modify 0014 * it under the terms of the GNU General Public License as published by 0015 * the Free Software Foundation; either version 2 of the License, or 0016 * (at your option) any later version. 0017 * 0018 * Kid3 is distributed in the hope that it will be useful, 0019 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0020 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0021 * GNU General Public License for more details. 0022 * 0023 * You should have received a copy of the GNU General Public License 0024 * along with this program. If not, see <http://www.gnu.org/licenses/>. 0025 */ 0026 0027 #include "tagconfig.h" 0028 #include <QCoreApplication> 0029 #include <QVector> 0030 #include <QVariantMap> 0031 #include "taggedfile.h" 0032 #include "frame.h" 0033 #include "isettings.h" 0034 0035 namespace { 0036 0037 /** Default value for comment name */ 0038 const char* const defaultCommentName = "COMMENT"; 0039 0040 /** Default value for RIFF track name */ 0041 const char* const defaultRiffTrackName = "IPRT"; 0042 0043 } 0044 0045 0046 /** 0047 * Mapping between star count and rating values. 0048 */ 0049 class StarRatingMapping { 0050 public: 0051 /** Maximum number of stars. */ 0052 static constexpr int MAX_STAR_COUNT = 5; 0053 0054 /** Constructor. */ 0055 StarRatingMapping(); 0056 0057 /** 0058 * Get star count from rating value. 0059 * @param rating rating value stored in tag frame 0060 * @param type rating type containing frame name and optionally field value, 0061 * e.g. "POPM.Windows Media Player 9 Series" or "RATING" 0062 * @return number of stars (1..5). 0063 */ 0064 int starCountFromRating(int rating, const QString& type) const; 0065 0066 /** 0067 * Get rating value from star count. 0068 * @param starCount number of stars (1..5) 0069 * @param type rating type containing frame name and optionally field value, 0070 * e.g. "POPM.Windows Media Player 9 Series" or "RATING" 0071 * @return rating value stored in tag frame, usually a value between 1 and 255 0072 * or 1 and 100. 0073 */ 0074 int starCountToRating(int starCount, const QString& type) const; 0075 0076 /** Serialize to string list. */ 0077 QStringList toStringList() const; 0078 0079 /** Set from string list. */ 0080 void fromStringList(const QStringList& strs); 0081 0082 /** Get default value for Email field in POPM frame. */ 0083 QString defaultPopmEmail() const; 0084 0085 /** Get mappings. */ 0086 const QList<QPair<QString, QVector<int> > >& getMappings() const { 0087 return m_maps; 0088 } 0089 0090 /** Set mappings. */ 0091 void setMappings(const QList<QPair<QString, QVector<int> > >& maps) { 0092 m_maps = maps; 0093 } 0094 0095 private: 0096 const QVector<int>& valuesForType(const QString& type) const; 0097 0098 QVector<int> m_wmpValues; 0099 QList<QPair<QString, QVector<int> > > m_maps; 0100 }; 0101 0102 StarRatingMapping::StarRatingMapping() 0103 { 0104 m_wmpValues << 1 << 64 << 128 << 196 << 255; 0105 QVector<int> traktorValues, wmaValues, percentValues; 0106 traktorValues << 51 << 102 << 153 << 204 << 255; 0107 wmaValues << 1<< 25<< 50 << 75 << 99; 0108 percentValues << 20 << 40 << 60 << 80 << 100; 0109 m_maps << qMakePair(QString(QLatin1String("POPM")), m_wmpValues); 0110 m_maps << qMakePair(QString(QLatin1String("POPM.Windows Media Player 9 Series")), 0111 m_wmpValues); 0112 m_maps << qMakePair(QString(QLatin1String("POPM.traktor@native-instruments.de")), 0113 traktorValues); 0114 m_maps << qMakePair(QString(QLatin1String("WM/SharedUserRating")), wmaValues); 0115 m_maps << qMakePair(QString(QLatin1String("IRTD")), percentValues); 0116 m_maps << qMakePair(QString(QLatin1String("rate")), percentValues); 0117 m_maps << qMakePair(QString(QLatin1String("RATING")), percentValues); 0118 } 0119 0120 int StarRatingMapping::starCountFromRating(int rating, const QString& type) const 0121 { 0122 if (rating < 1) { 0123 return 0; 0124 } 0125 const QVector<int>& vals = valuesForType(type); 0126 const bool useWmpHack = vals.at(3) == 196; 0127 for (int i = 1; i < MAX_STAR_COUNT; ++i) { 0128 // This is done the weird way in order to get the same thresholds as 0129 // apparently used in Windows Explorer: 0130 // 1: 1-31, 2: 32-95, 3: 96-159, 4:160-223, 5:224-255 0131 if (int threshold = useWmpHack 0132 ? (((vals[i - 1] + 1) & ~7) + ((vals[i] + 1) & ~7)) / 2 0133 : (vals[i - 1] + vals[i] + 1) / 2; 0134 rating < threshold) { 0135 return i; 0136 } 0137 } 0138 return MAX_STAR_COUNT; 0139 } 0140 0141 int StarRatingMapping::starCountToRating(int starCount, const QString& type) const 0142 { 0143 if (starCount < 1) { 0144 return 0; 0145 } 0146 if (starCount > MAX_STAR_COUNT) { 0147 starCount = MAX_STAR_COUNT; 0148 } 0149 return valuesForType(type).at(starCount - 1); 0150 } 0151 0152 const QVector<int>& StarRatingMapping::valuesForType(const QString& type) const 0153 { 0154 // First search in the maps for the given type. 0155 for (auto it = m_maps.constBegin(); it != m_maps.constEnd(); ++it) { 0156 if (type == it->first) { 0157 return it->second; 0158 } 0159 } 0160 // If not found, use the first map or the WMP map if no maps are available. 0161 return m_maps.isEmpty() ? m_wmpValues : m_maps.first().second; 0162 } 0163 0164 QStringList StarRatingMapping::toStringList() const 0165 { 0166 QStringList strs; 0167 for (auto it = m_maps.constBegin(); it != m_maps.constEnd(); ++it) { 0168 QString str = it->first; 0169 for (auto sit = it->second.constBegin(); sit != it->second.constEnd(); ++sit) { 0170 str += QLatin1Char(','); 0171 str += QString::number(*sit); 0172 } 0173 strs.append(str); 0174 } 0175 return strs; 0176 } 0177 0178 void StarRatingMapping::fromStringList(const QStringList& strs) 0179 { 0180 QList<QPair<QString, QVector<int> > > maps; 0181 QVector<int> values; 0182 for (auto it = strs.constBegin(); it != strs.constEnd(); ++it) { 0183 QStringList parts = it->split(QLatin1Char(',')); 0184 if (const int numParts = parts.size(); numParts >= MAX_STAR_COUNT + 1) { 0185 bool ok = false; 0186 values.resize(0); 0187 int lastValue = -1; 0188 for (int i = numParts - MAX_STAR_COUNT; i < numParts; ++i) { 0189 int value = parts.at(i).toInt(&ok); 0190 if (value <= lastValue) { 0191 ok = false; 0192 } 0193 if (!ok) { 0194 break; 0195 } 0196 values.append(value); 0197 } 0198 if (ok) { 0199 const QStringList typeParts = parts.mid(0, numParts - MAX_STAR_COUNT); 0200 const QString type = typeParts.join(QLatin1String(",")); 0201 maps.append(qMakePair(type, values)); 0202 } 0203 } 0204 } 0205 if (!maps.isEmpty()) { 0206 m_maps.swap(maps); 0207 } 0208 } 0209 0210 QString StarRatingMapping::defaultPopmEmail() const 0211 { 0212 for (auto it = m_maps.constBegin(); it != m_maps.constEnd(); ++it) { 0213 if (QString type = it->first; type.startsWith(QLatin1String("POPM"))) { 0214 return type.length() > 4 && type.at(4) == QLatin1Char('.') 0215 ? type.mid(5) : QLatin1String(""); 0216 } 0217 } 0218 return QString(); 0219 } 0220 0221 0222 int TagConfig::s_index = -1; 0223 0224 /** 0225 * Constructor. 0226 */ 0227 TagConfig::TagConfig() 0228 : StoredConfig(QLatin1String("Tags")), 0229 m_starRatingMapping(new StarRatingMapping), 0230 m_commentName(QString::fromLatin1(defaultCommentName)), 0231 m_riffTrackName(QString::fromLatin1(defaultRiffTrackName)), 0232 m_pictureNameItem(VP_METADATA_BLOCK_PICTURE), 0233 m_id3v2Version(ID3v2_3_0), 0234 m_textEncodingV1(QLatin1String("ISO-8859-1")), 0235 m_textEncoding(TE_ISO8859_1), 0236 m_quickAccessFrames(FrameCollection::DEFAULT_QUICK_ACCESS_FRAMES), 0237 m_trackNumberDigits(1), 0238 m_taggedFileFeatures(0), 0239 m_maximumPictureSize(131072), 0240 m_markOversizedPictures(false), 0241 m_markStandardViolations(true), 0242 m_onlyCustomGenres(false), 0243 m_markTruncations(true), 0244 m_enableTotalNumberOfTracks(false), 0245 m_genreNotNumeric(true), 0246 m_lowercaseId3RiffChunk(false) 0247 { 0248 m_disabledPlugins << QLatin1String("Id3libMetadata") 0249 << QLatin1String("Mp4v2Metadata"); 0250 } 0251 0252 /** 0253 * Destructor. 0254 */ 0255 TagConfig::~TagConfig() 0256 { 0257 // Must not be inline because of forwared declared QScopedPointer. 0258 } 0259 0260 /** 0261 * Persist configuration. 0262 * 0263 * @param config configuration 0264 */ 0265 void TagConfig::writeToConfig(ISettings* config) const 0266 { 0267 config->beginGroup(m_group); 0268 config->setValue(QLatin1String("MarkTruncations"), 0269 QVariant(m_markTruncations)); 0270 config->setValue(QLatin1String("MarkOversizedPictures"), 0271 QVariant(m_markOversizedPictures)); 0272 config->setValue(QLatin1String("MaximumPictureSize"), 0273 QVariant(m_maximumPictureSize)); 0274 config->setValue(QLatin1String("MarkStandardViolations"), 0275 QVariant(m_markStandardViolations)); 0276 config->setValue(QLatin1String("EnableTotalNumberOfTracks"), 0277 QVariant(m_enableTotalNumberOfTracks)); 0278 config->setValue(QLatin1String("GenreNotNumeric"), 0279 QVariant(m_genreNotNumeric)); 0280 config->setValue(QLatin1String("LowercaseId3RiffChunk"), 0281 QVariant(m_lowercaseId3RiffChunk)); 0282 config->setValue(QLatin1String("CommentName"), 0283 QVariant(m_commentName)); 0284 config->setValue(QLatin1String("PictureNameItem"), 0285 QVariant(m_pictureNameItem)); 0286 config->setValue(QLatin1String("RiffTrackName"), 0287 QVariant(m_riffTrackName)); 0288 config->setValue(QLatin1String("CustomGenres"), 0289 QVariant(m_customGenres)); 0290 config->setValue(QLatin1String("CustomFrames"), 0291 QVariant(m_customFrames)); 0292 config->setValue(QLatin1String("ID3v2Version"), 0293 QVariant(m_id3v2Version)); 0294 config->setValue(QLatin1String("TextEncodingV1"), 0295 QVariant(m_textEncodingV1)); 0296 config->setValue(QLatin1String("TextEncoding"), 0297 QVariant(m_textEncoding)); 0298 #ifdef Q_OS_MAC 0299 // Convince Mac OS X to store a 64-bit value. 0300 config->setValue(QLatin1String("QuickAccessFrames"), 0301 QVariant(m_quickAccessFrames | (Q_UINT64_C(1) << 63))); 0302 #else 0303 config->setValue(QLatin1String("QuickAccessFrames"), 0304 QVariant(m_quickAccessFrames)); 0305 #endif 0306 config->setValue(QLatin1String("QuickAccessFrameOrder"), 0307 QVariant(intListToStringList(m_quickAccessFrameOrder))); 0308 config->setValue(QLatin1String("TrackNumberDigits"), 0309 QVariant(m_trackNumberDigits)); 0310 config->setValue(QLatin1String("OnlyCustomGenres"), 0311 QVariant(m_onlyCustomGenres)); 0312 config->setValue(QLatin1String("PluginOrder"), 0313 QVariant(m_pluginOrder)); 0314 config->setValue(QLatin1String("DisabledPlugins"), 0315 QVariant(m_disabledPlugins)); 0316 config->setValue(QLatin1String("StarRatingMapping"), 0317 QVariant(m_starRatingMapping->toStringList())); 0318 config->endGroup(); 0319 } 0320 0321 /** 0322 * Read persisted configuration. 0323 * 0324 * @param config configuration 0325 */ 0326 void TagConfig::readFromConfig(ISettings* config) 0327 { 0328 config->beginGroup(m_group); 0329 m_markTruncations = config->value(QLatin1String("MarkTruncations"), 0330 m_markTruncations).toBool(); 0331 m_markOversizedPictures = config->value(QLatin1String("MarkOversizedPictures"), 0332 m_markOversizedPictures).toBool(); 0333 m_maximumPictureSize = config->value(QLatin1String("MaximumPictureSize"), 0334 m_maximumPictureSize).toInt(); 0335 m_markStandardViolations = 0336 config->value(QLatin1String("MarkStandardViolations"), 0337 m_markStandardViolations).toBool(); 0338 m_enableTotalNumberOfTracks = 0339 config->value(QLatin1String("EnableTotalNumberOfTracks"), 0340 m_enableTotalNumberOfTracks).toBool(); 0341 m_genreNotNumeric = config->value(QLatin1String("GenreNotNumeric"), 0342 m_genreNotNumeric).toBool(); 0343 m_lowercaseId3RiffChunk = config->value(QLatin1String("LowercaseId3RiffChunk"), 0344 m_lowercaseId3RiffChunk).toBool(); 0345 m_commentName = 0346 config->value(QLatin1String("CommentName"), 0347 QString::fromLatin1(defaultCommentName)).toString(); 0348 m_pictureNameItem = config->value(QLatin1String("PictureNameItem"), 0349 VP_METADATA_BLOCK_PICTURE).toInt(); 0350 m_riffTrackName = 0351 config->value(QLatin1String("RiffTrackName"), 0352 QString::fromLatin1(defaultRiffTrackName)).toString(); 0353 m_customGenres = config->value(QLatin1String("CustomGenres"), 0354 m_customGenres).toStringList(); 0355 m_customFrames = config->value(QLatin1String("CustomFrames"), 0356 m_customFrames).toStringList(); 0357 m_id3v2Version = config->value(QLatin1String("ID3v2Version"), 0358 ID3v2_3_0).toInt(); 0359 m_textEncodingV1 = config->value(QLatin1String("TextEncodingV1"), 0360 QLatin1String("ISO-8859-1")).toString(); 0361 m_textEncoding = config->value(QLatin1String("TextEncoding"), 0362 TE_ISO8859_1).toInt(); 0363 m_quickAccessFrames = 0364 config->value(QLatin1String("QuickAccessFrames"), 0365 FrameCollection::DEFAULT_QUICK_ACCESS_FRAMES).toULongLong(); 0366 #ifdef Q_OS_MAC 0367 m_quickAccessFrames &= ~(Q_UINT64_C(1) << 63); 0368 #endif 0369 m_quickAccessFrameOrder = stringListToIntList( 0370 config->value(QLatin1String("QuickAccessFrameOrder"), QStringList()) 0371 .toStringList()); 0372 m_trackNumberDigits = config->value(QLatin1String("TrackNumberDigits"), 0373 1).toInt(); 0374 m_onlyCustomGenres = config->value(QLatin1String("OnlyCustomGenres"), 0375 m_onlyCustomGenres).toBool(); 0376 m_pluginOrder = config->value(QLatin1String("PluginOrder"), 0377 m_pluginOrder).toStringList(); 0378 m_disabledPlugins = config->value(QLatin1String("DisabledPlugins"), 0379 m_disabledPlugins).toStringList(); 0380 m_starRatingMapping->fromStringList( 0381 config->value(QLatin1String("StarRatingMapping"), 0382 QStringList()).toStringList()); 0383 config->endGroup(); 0384 0385 if (m_pluginOrder.isEmpty()) { 0386 setDefaultPluginOrder(); 0387 } 0388 } 0389 0390 /** 0391 * Set default plugin order. 0392 */ 0393 void TagConfig::setDefaultPluginOrder() 0394 { 0395 /** Default to filename format list */ 0396 static const char* const defaultPluginOrder[] = { 0397 "Id3libMetadata", 0398 "OggFlacMetadata", 0399 "Mp4v2Metadata", 0400 "TaglibMetadata", 0401 nullptr 0402 }; 0403 0404 m_pluginOrder.clear(); 0405 for (const char* const* pn = defaultPluginOrder; *pn != nullptr; ++pn) { 0406 m_pluginOrder += QString::fromLatin1(*pn); 0407 } 0408 } 0409 0410 /** version used for new ID3v2 tags */ 0411 int TagConfig::id3v2Version() const 0412 { 0413 if (m_id3v2Version == ID3v2_3_0 && 0414 !(taggedFileFeatures() & TaggedFile::TF_ID3v23)) 0415 return ID3v2_4_0; 0416 if (m_id3v2Version == ID3v2_4_0 && 0417 !(taggedFileFeatures() & TaggedFile::TF_ID3v24)) 0418 return ID3v2_3_0; 0419 return m_id3v2Version; 0420 } 0421 0422 /** 0423 * Set features provided by metadata plugins. 0424 * @param taggedFileFeatures bit mask with TaggedFile::Feature flags set 0425 */ 0426 void TagConfig::setTaggedFileFeatures(int taggedFileFeatures) 0427 { 0428 if (m_taggedFileFeatures != taggedFileFeatures) { 0429 m_taggedFileFeatures = taggedFileFeatures; 0430 emit taggedFileFeaturesChanged(m_taggedFileFeatures); 0431 } 0432 } 0433 0434 /** Set true to mark truncated ID3v1.1 fields. */ 0435 void TagConfig::setMarkTruncations(bool markTruncations) 0436 { 0437 if (m_markTruncations != markTruncations) { 0438 m_markTruncations = markTruncations; 0439 emit markTruncationsChanged(m_markTruncations); 0440 } 0441 } 0442 0443 /** Set true to mark oversized pictures. */ 0444 void TagConfig::setMarkOversizedPictures(bool markOversizedPictures) 0445 { 0446 if (m_markOversizedPictures != markOversizedPictures) { 0447 m_markOversizedPictures = markOversizedPictures; 0448 emit markOversizedPicturesChanged(m_markOversizedPictures); 0449 } 0450 } 0451 0452 /** Set maximum size of picture in bytes. */ 0453 void TagConfig::setMaximumPictureSize(int maximumPictureSize) 0454 { 0455 if (m_maximumPictureSize != maximumPictureSize) { 0456 m_maximumPictureSize = maximumPictureSize; 0457 emit maximumPictureSizeChanged(m_maximumPictureSize); 0458 } 0459 } 0460 0461 /** Set true to mark standard violations. */ 0462 void TagConfig::setMarkStandardViolations(bool markStandardViolations) 0463 { 0464 if (m_markStandardViolations != markStandardViolations) { 0465 m_markStandardViolations = markStandardViolations; 0466 emit markStandardViolationsChanged(m_markStandardViolations); 0467 } 0468 } 0469 0470 /** Set true to write total number of tracks into track fields. */ 0471 void TagConfig::setEnableTotalNumberOfTracks(bool enableTotalNumberOfTracks) 0472 { 0473 if (m_enableTotalNumberOfTracks != enableTotalNumberOfTracks) { 0474 m_enableTotalNumberOfTracks = enableTotalNumberOfTracks; 0475 emit enableTotalNumberOfTracksChanged(m_enableTotalNumberOfTracks); 0476 } 0477 } 0478 0479 /** Set true to write genres as text instead of numeric string. */ 0480 void TagConfig::setGenreNotNumeric(bool genreNotNumeric) 0481 { 0482 if (m_genreNotNumeric != genreNotNumeric) { 0483 m_genreNotNumeric = genreNotNumeric; 0484 emit genreNotNumericChanged(m_genreNotNumeric); 0485 } 0486 } 0487 0488 /** Set true to use "id3 " instead of "ID3 " chunk names in WAV files */ 0489 void TagConfig::setLowercaseId3RiffChunk(bool lowercaseId3RiffChunk) 0490 { 0491 if (m_lowercaseId3RiffChunk != lowercaseId3RiffChunk) { 0492 m_lowercaseId3RiffChunk = lowercaseId3RiffChunk; 0493 emit lowercaseId3RiffChunkChanged(m_lowercaseId3RiffChunk); 0494 } 0495 } 0496 0497 /** Set field name used for Vorbis comment entries. */ 0498 void TagConfig::setCommentName(const QString& commentName) 0499 { 0500 if (m_commentName != commentName) { 0501 m_commentName = commentName; 0502 emit commentNameChanged(m_commentName); 0503 } 0504 } 0505 0506 /** Set index of field name used for Vorbis picture entries. */ 0507 void TagConfig::setPictureNameIndex(int pictureNameIndex) 0508 { 0509 if (m_pictureNameItem != pictureNameIndex) { 0510 m_pictureNameItem = pictureNameIndex; 0511 emit pictureNameIndexChanged(m_pictureNameItem); 0512 } 0513 } 0514 0515 /** Set field name used for RIFF track entries. */ 0516 void TagConfig::setRiffTrackName(const QString& riffTrackName) 0517 { 0518 if (m_riffTrackName != riffTrackName) { 0519 m_riffTrackName = riffTrackName; 0520 emit riffTrackNameChanged(m_riffTrackName); 0521 } 0522 } 0523 0524 /** Set custom genres for ID3v2.3. */ 0525 void TagConfig::setCustomGenres(const QStringList& customGenres) 0526 { 0527 if (m_customGenres != customGenres) { 0528 m_customGenres = customGenres; 0529 emit customGenresChanged(m_customGenres); 0530 } 0531 } 0532 0533 /** Set custom frame names. */ 0534 void TagConfig::setCustomFrames(const QStringList& customFrames) 0535 { 0536 if (m_customFrames != customFrames) { 0537 m_customFrames = customFrames; 0538 emit customFramesChanged(m_customFrames); 0539 } 0540 } 0541 0542 /** Set version used for new ID3v2 tags. */ 0543 void TagConfig::setId3v2Version(int id3v2Version) 0544 { 0545 if (m_id3v2Version != id3v2Version) { 0546 m_id3v2Version = id3v2Version; 0547 emit id3v2VersionChanged(m_id3v2Version); 0548 } 0549 } 0550 0551 /** Set text encoding used for new ID3v1 tags. */ 0552 void TagConfig::setTextEncodingV1(const QString& textEncodingV1) 0553 { 0554 if (m_textEncodingV1 != textEncodingV1) { 0555 m_textEncodingV1 = textEncodingV1; 0556 emit textEncodingV1Changed(m_textEncodingV1); 0557 } 0558 } 0559 0560 /** index of ID3v1 text encoding in getTextCodecNames() */ 0561 int TagConfig::textEncodingV1Index() const 0562 { 0563 return indexFromTextCodecName(m_textEncodingV1); 0564 } 0565 0566 /** Set ID3v1 text encoding from index in getTextCodecNames(). */ 0567 void TagConfig::setTextEncodingV1Index(int index) 0568 { 0569 if (QString encoding = indexToTextCodecName(index); !encoding.isNull()) { 0570 setTextEncodingV1(encoding); 0571 } 0572 } 0573 0574 /** Set text encoding used for new ID3v2 tags. */ 0575 void TagConfig::setTextEncoding(int textEncoding) 0576 { 0577 if (m_textEncoding != textEncoding) { 0578 m_textEncoding = textEncoding; 0579 emit textEncodingChanged(m_textEncoding); 0580 } 0581 } 0582 0583 /** Set frames which are displayed for Tag 2 even if not present. */ 0584 void TagConfig::setQuickAccessFrames(quint64 quickAccessFrames) 0585 { 0586 if (m_quickAccessFrames != quickAccessFrames) { 0587 m_quickAccessFrames = quickAccessFrames; 0588 emit quickAccessFramesChanged(m_quickAccessFrames); 0589 } 0590 } 0591 0592 /** Set order of frames which are displayed for Tag 2 even if not present. */ 0593 void TagConfig::setQuickAccessFrameOrder(const QList<int>& frameTypes) 0594 { 0595 if (m_quickAccessFrameOrder != frameTypes) { 0596 m_quickAccessFrameOrder = frameTypes; 0597 emit quickAccessFrameOrderChanged(m_quickAccessFrameOrder); 0598 } 0599 } 0600 0601 /** Set number of digits in track number. */ 0602 void TagConfig::setTrackNumberDigits(int trackNumberDigits) 0603 { 0604 if (m_trackNumberDigits != trackNumberDigits) { 0605 m_trackNumberDigits = trackNumberDigits; 0606 emit trackNumberDigitsChanged(m_trackNumberDigits); 0607 } 0608 } 0609 0610 /** Set true to show only custom genres in combo boxes. */ 0611 void TagConfig::setOnlyCustomGenres(bool onlyCustomGenres) 0612 { 0613 if (m_onlyCustomGenres != onlyCustomGenres) { 0614 m_onlyCustomGenres = onlyCustomGenres; 0615 emit onlyCustomGenresChanged(m_onlyCustomGenres); 0616 } 0617 } 0618 0619 /** Set the order in which meta data plugins are tried when opening a file. */ 0620 void TagConfig::setPluginOrder(const QStringList& pluginOrder) 0621 { 0622 if (m_pluginOrder != pluginOrder) { 0623 m_pluginOrder = pluginOrder; 0624 emit pluginOrderChanged(m_pluginOrder); 0625 } 0626 } 0627 0628 /** Set list of disabled plugins. */ 0629 void TagConfig::setDisabledPlugins(const QStringList& disabledPlugins) 0630 { 0631 if (m_disabledPlugins != disabledPlugins) { 0632 m_disabledPlugins = disabledPlugins; 0633 emit disabledPluginsChanged(m_disabledPlugins); 0634 } 0635 } 0636 0637 /** 0638 * Set list of available plugins. 0639 * @param availablePlugins available plugins 0640 */ 0641 void TagConfig::setAvailablePlugins(const QStringList& availablePlugins) 0642 { 0643 if (m_availablePlugins != availablePlugins) { 0644 m_availablePlugins = availablePlugins; 0645 emit availablePluginsChanged(m_availablePlugins); 0646 } 0647 } 0648 0649 /** 0650 * Get list of star count rating mappings. 0651 * @return star count rating mappings as a list of strings. 0652 */ 0653 QStringList TagConfig::starRatingMappingStrings() const 0654 { 0655 return m_starRatingMapping->toStringList(); 0656 } 0657 0658 /** 0659 * Set list of star count rating mappings. 0660 * @param mappings star count rating mappings 0661 */ 0662 void TagConfig::setStarRatingMappingStrings(const QStringList& mappings) 0663 { 0664 if (m_starRatingMapping->toStringList() != mappings) { 0665 m_starRatingMapping->fromStringList(mappings); 0666 emit starRatingMappingsChanged(); 0667 } 0668 } 0669 0670 /** 0671 * Get list of star count rating mappings. 0672 * @return star count rating mappings. 0673 */ 0674 const QList<QPair<QString, QVector<int> > >& TagConfig::starRatingMappings() const 0675 { 0676 return m_starRatingMapping->getMappings(); 0677 } 0678 0679 /** 0680 * Set list of star count rating mappings. 0681 * @param maps star count rating mappings 0682 */ 0683 void TagConfig::setStarRatingMappings( 0684 const QList<QPair<QString, QVector<int> > >& maps) 0685 { 0686 if (m_starRatingMapping->getMappings() != maps) { 0687 m_starRatingMapping->setMappings(maps); 0688 emit starRatingMappingsChanged(); 0689 } 0690 } 0691 0692 /** 0693 * Get star count from rating value. 0694 * @param rating rating value stored in tag frame 0695 * @param type rating type containing frame name and optionally field value, 0696 * e.g. "POPM.Windows Media Player 9 Series" or "RATING" 0697 * @return number of stars (1..5). 0698 */ 0699 int TagConfig::starCountFromRating(int rating, const QString& type) const 0700 { 0701 return m_starRatingMapping->starCountFromRating(rating, type); 0702 } 0703 0704 /** 0705 * Get rating value from star count. 0706 * @param starCount number of stars (1..5) 0707 * @param type rating type containing frame name and optionally field value, 0708 * e.g. "POPM.Windows Media Player 9 Series" or "RATING" 0709 * @return rating value stored in tag frame, usually a value between 1 and 255 0710 * or 1 and 100. 0711 */ 0712 int TagConfig::starCountToRating(int starCount, const QString& type) const 0713 { 0714 return m_starRatingMapping->starCountToRating(starCount, type); 0715 } 0716 0717 /** 0718 * Get default value for Email field in POPM frame. 0719 * @return value for Email field in first POPM entry of star rating mappings. 0720 */ 0721 QString TagConfig::defaultPopmEmail() const 0722 { 0723 return m_starRatingMapping->defaultPopmEmail(); 0724 } 0725 0726 /** 0727 * String list of encodings for ID3v2. 0728 */ 0729 QStringList TagConfig::getTextEncodingNames() 0730 { 0731 static constexpr int NUM_NAMES = 3; 0732 static const char* const names[NUM_NAMES] = { 0733 QT_TRANSLATE_NOOP("@default", "ISO-8859-1"), 0734 QT_TRANSLATE_NOOP("@default", "UTF16"), 0735 QT_TRANSLATE_NOOP("@default", "UTF8") 0736 }; 0737 QStringList strs; 0738 strs.reserve(NUM_NAMES); 0739 for (int i = 0; i < NUM_NAMES; ++i) { 0740 strs.append(QCoreApplication::translate("@default", names[i])); 0741 } 0742 return strs; 0743 } 0744 0745 /** 0746 * String list of possible versions used for new ID3v2 tags. 0747 */ 0748 QStringList TagConfig::getId3v2VersionNames() 0749 { 0750 return {QLatin1String("ID3v2.3.0"), QLatin1String("ID3v2.4.0")}; 0751 } 0752 0753 /** 0754 * String list with suggested field names used for Vorbis comment entries. 0755 */ 0756 QStringList TagConfig::getCommentNames() 0757 { 0758 return {QLatin1String("COMMENT"), QLatin1String("DESCRIPTION")}; 0759 } 0760 0761 /** 0762 * String list with possible field names used for Vorbis picture entries. 0763 */ 0764 QStringList TagConfig::getPictureNames() 0765 { 0766 return {QLatin1String("METADATA_BLOCK_PICTURE"), QLatin1String("COVERART")}; 0767 } 0768 0769 /** 0770 * String list with suggested field names used for RIFF track entries. 0771 */ 0772 QStringList TagConfig::getRiffTrackNames() 0773 { 0774 return {QLatin1String("IPRT"), QLatin1String("ITRK"), QLatin1String("TRCK")}; 0775 } 0776 0777 /** 0778 * Available and selected quick access frames. 0779 */ 0780 QVariantList TagConfig::selectedQuickAccessFrames() const { 0781 return getQuickAccessFrameSelection( 0782 quickAccessFrameOrder(), quickAccessFrames(), 0783 customFrameNamesToDisplayNames(customFrames())); 0784 } 0785 0786 /** 0787 * Set selected quick access frames. 0788 * @param namesSelected list of maps with name, selected and type fields 0789 */ 0790 void TagConfig::setSelectedQuickAccessFrames( 0791 const QVariantList& namesSelected) { 0792 QList<int> frameTypes; 0793 quint64 frameMask = 0; 0794 setQuickAccessFrameSelection(namesSelected, frameTypes, frameMask); 0795 setQuickAccessFrameOrder(frameTypes); 0796 setQuickAccessFrames(frameMask); 0797 } 0798 0799 /** 0800 * Get the available and selected quick access frames. 0801 * @param types ordered frame types as in quickAccessFrameOrder() 0802 * @param frameMask quick access frame selection as in quickAccessFrames() 0803 * @param customFrameNames list of custom frame names as in customFrames() 0804 * @return list of name/type/selected maps. 0805 */ 0806 QVariantList TagConfig::getQuickAccessFrameSelection( 0807 const QList<int>& types, quint64 frameMask, 0808 const QStringList& customFrameNames) 0809 { 0810 QList frameTypes(types); 0811 if (frameTypes.size() < Frame::FT_Custom1) { 0812 frameTypes.clear(); 0813 frameTypes.reserve(Frame::FT_LastFrame - Frame::FT_FirstFrame + 1); 0814 for (int i = Frame::FT_FirstFrame; i <= Frame::FT_LastFrame; ++i) { 0815 frameTypes.append(i); 0816 } 0817 } else { 0818 for (int i = frameTypes.size(); i <= Frame::FT_LastFrame; ++i) { 0819 frameTypes.append(i); 0820 } 0821 } 0822 QVariantList namesSelected; 0823 const auto constFrameTypes = frameTypes; 0824 for (int frameType : constFrameTypes) { 0825 auto name = Frame::ExtendedType(static_cast<Frame::Type>(frameType)) 0826 .getTranslatedName(); 0827 if (Frame::isCustomFrameType(static_cast<Frame::Type>(frameType))) { 0828 if (int idx = frameType - Frame::FT_Custom1; 0829 idx >= 0 && idx < customFrameNames.size()) { 0830 name = customFrameNames.at(idx); 0831 } else { 0832 name.clear(); 0833 } 0834 } 0835 if (!name.isEmpty()) { 0836 const bool selected = (frameMask & (1ULL << frameType)) != 0ULL; 0837 namesSelected.append( 0838 QVariantMap{{QLatin1String("name"), name}, 0839 {QLatin1String("type"), frameType}, 0840 {QLatin1String("selected"), selected}}); 0841 } 0842 } 0843 return namesSelected; 0844 } 0845 0846 /** 0847 * Set the selected quick access frames. 0848 * @param namesSelected list of name/type/selected maps 0849 * @param frameTypes ordered frame types are returned here, 0850 * suitable for setQuickAccessFrameOrder() 0851 * @param frameMask the quick access frame selection is returned here, 0852 * suitable for setQuickAccessFrames() 0853 */ 0854 void TagConfig::setQuickAccessFrameSelection( 0855 const QVariantList& namesSelected, 0856 QList<int>& frameTypes, quint64& frameMask) 0857 { 0858 bool isStandardFrameOrder = true; 0859 const int numQuickAccessTags = namesSelected.size(); 0860 frameTypes.clear(); 0861 frameTypes.reserve(numQuickAccessTags); 0862 frameMask = 0; 0863 for (int row = 0; row < numQuickAccessTags; ++row) { 0864 auto map = namesSelected.at(row).toMap(); 0865 auto frameType = map.value(QLatin1String("type")).toInt(); 0866 auto selected = map.value(QLatin1String("selected")).toBool(); 0867 if (frameType != row) { 0868 isStandardFrameOrder = false; 0869 } 0870 frameTypes.append(frameType); 0871 if (selected) { 0872 frameMask |= 1ULL << frameType; 0873 } 0874 } 0875 if (isStandardFrameOrder) { 0876 frameTypes.clear(); 0877 } 0878 } 0879 0880 /** 0881 * Convert list of custom frame names to display names. 0882 * @param names custom frame names 0883 * @return possibly translated display representations of @a names. 0884 */ 0885 QStringList TagConfig::customFrameNamesToDisplayNames(const QStringList& names) 0886 { 0887 QStringList displayNames; 0888 for (const QString& name : names) { 0889 displayNames.append(Frame::getDisplayName(name)); 0890 } 0891 return displayNames; 0892 } 0893 0894 /** 0895 * Convert list of display names to custom frame names. 0896 * @param displayNames displayed frame names 0897 * @return internal representations of @a displayNames. 0898 */ 0899 QStringList TagConfig::customFrameNamesFromDisplayNames( 0900 const QStringList& displayNames) 0901 { 0902 QStringList names; 0903 for (const QString& displayName : displayNames) { 0904 QByteArray frameId = Frame::getFrameIdForTranslatedFrameName(displayName); 0905 names.append(frameId.isNull() 0906 ? Frame::getNameForTranslatedFrameName(displayName) 0907 : QString::fromLatin1(frameId)); 0908 } 0909 return names; 0910 }