File indexing completed on 2024-05-19 04:56:13

0001 /**
0002  * \file trackdata.cpp
0003  * Track data, frames with association to tagged file.
0004  *
0005  * \b Project: Kid3
0006  * \author Urs Fleisch
0007  * \date 23 Feb 2007
0008  *
0009  * Copyright (C) 2007-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 "trackdata.h"
0028 #include <QString>
0029 #include <QUrl>
0030 #include <QDir>
0031 #include <QDateTime>
0032 #include <QCoreApplication>
0033 #include "fileproxymodel.h"
0034 
0035 /**
0036  * Constructor.
0037  *
0038  * @param trackData track data
0039  * @param str       string with format codes
0040  */
0041 TrackDataFormatReplacer::TrackDataFormatReplacer(
0042   const TrackData& trackData, const QString& str)
0043   : FrameFormatReplacer(trackData, str), m_trackData(trackData) {}
0044 
0045 /**
0046  * Replace a format code (one character %c or multiple characters %{chars}).
0047  * Supported format fields:
0048  * Those supported by FrameFormatReplacer::getReplacement()
0049  * %f filename
0050  * %p path to file
0051  * %u URL of file
0052  * %d duration in minutes:seconds
0053  * %D duration in seconds
0054  * %n number of tracks
0055  *
0056  * @param code format code
0057  *
0058  * @return replacement string,
0059  *         QString::null if code not found.
0060  */
0061 QString TrackDataFormatReplacer::getReplacement(const QString& code) const
0062 {
0063   QString result = FrameFormatReplacer::getReplacement(code);
0064   if (result.isNull()) {
0065     QString name;
0066 
0067     if (code.length() == 1) {
0068       static const struct {
0069         const char* longCode;
0070         char shortCode;
0071       } shortToLong[] = {
0072         { "file", 'f' },
0073         { "filepath", 'p' },
0074         { "url", 'u' },
0075         { "duration", 'd' },
0076         { "seconds", 'D' },
0077         { "tracks", 'n' },
0078         { "extension", 'e' },
0079         { "tag1", 'O' },
0080         { "tag2", 'o' },
0081         { "bitrate", 'b' },
0082         { "vbr", 'v' },
0083         { "samplerate", 'r' },
0084         { "mode", 'm' },
0085         { "channels", 'C' },
0086         { "codec", 'k' },
0087         { "marked", 'w' }
0088       };
0089       const char c = code[0].toLatin1();
0090       for (const auto& [longCode, shortCode] : shortToLong) {
0091         if (shortCode == c) {
0092           name = QString::fromLatin1(longCode);
0093           break;
0094         }
0095       }
0096     } else if (code.length() > 1) {
0097       name = code;
0098     }
0099 
0100     if (!name.isNull()) {
0101       TaggedFile::DetailInfo info;
0102       m_trackData.getDetailInfo(info);
0103       if (name == QLatin1String("file")) {
0104         QString filename(m_trackData.getAbsFilename());
0105         int sepPos = filename.lastIndexOf(QLatin1Char('/'));
0106         if (sepPos < 0) {
0107           sepPos = filename.lastIndexOf(QDir::separator());
0108         }
0109         if (sepPos >= 0) {
0110           filename.remove(0, sepPos + 1);
0111         }
0112         result = filename;
0113       } else if (name == QLatin1String("filepath")) {
0114         result = m_trackData.getAbsFilename();
0115       } else if (name == QLatin1String("modificationdate")) {
0116         return QFileInfo(m_trackData.getAbsFilename())
0117             .lastModified().toString(Qt::ISODate);
0118       } else if (name == QLatin1String("creationdate")) {
0119 #if QT_VERSION >= 0x050a00
0120         return QFileInfo(m_trackData.getAbsFilename())
0121             .birthTime().toString(Qt::ISODate);
0122 #else
0123         return QFileInfo(m_trackData.getAbsFilename())
0124             .created().toString(Qt::ISODate);
0125 #endif
0126       } else if (name == QLatin1String("url")) {
0127         QUrl url;
0128         url.setPath(m_trackData.getAbsFilename());
0129         url.setScheme(QLatin1String("file"));
0130         result = url.toString();
0131       } else if (name == QLatin1String("dirname")) {
0132         const QString dirPath = m_trackData.getDirname();
0133         int sepPos = dirPath.lastIndexOf(QLatin1Char('/'));
0134         if (sepPos < 0) {
0135           sepPos = dirPath.lastIndexOf(QDir::separator());
0136         }
0137         result = sepPos >= 0 ? dirPath.mid(sepPos + 1) : dirPath;
0138       } else if (name == QLatin1String("duration")) {
0139         result = TaggedFile::formatTime(m_trackData.getFileDuration());
0140       } else if (name == QLatin1String("seconds")) {
0141         result = QString::number(m_trackData.getFileDuration());
0142       } else if (name == QLatin1String("tracks")) {
0143         result = QString::number(m_trackData.getTotalNumberOfTracksInDir());
0144       } else if (name == QLatin1String("extension")) {
0145         result = m_trackData.getFileExtension();
0146       } else if (name.startsWith(QLatin1String("tag")) && name.length() == 4) {
0147         if (Frame::TagNumber tagNr = Frame::tagNumberFromString(name.mid(3));
0148             tagNr < Frame::Tag_NumValues) {
0149           result = m_trackData.getTagFormat(tagNr);
0150         }
0151       } else if (name == QLatin1String("bitrate")) {
0152         result.setNum(info.bitrate);
0153       } else if (name == QLatin1String("vbr")) {
0154         result = info.vbr ? QLatin1String("VBR") : QLatin1String("");
0155       } else if (name == QLatin1String("samplerate")) {
0156         result.setNum(info.sampleRate);
0157       } else if (name == QLatin1String("mode")) {
0158         switch (info.channelMode) {
0159           case TaggedFile::DetailInfo::CM_Stereo:
0160             result = QLatin1String("Stereo");
0161             break;
0162           case TaggedFile::DetailInfo::CM_JointStereo:
0163             result = QLatin1String("Joint Stereo");
0164             break;
0165           case TaggedFile::DetailInfo::CM_None:
0166           default:
0167             result = QLatin1String("");
0168         }
0169       } else if (name == QLatin1String("channels")) {
0170         result.setNum(info.channels);
0171       } else if (name == QLatin1String("codec")) {
0172         result = info.format;
0173       } else if (name == QLatin1String("marked")) {
0174         TaggedFile* taggedFile = m_trackData.getTaggedFile();
0175         result = taggedFile && taggedFile->isMarked()
0176             ? QLatin1String("1") : QLatin1String("");
0177       }
0178     }
0179   }
0180 
0181   return result;
0182 }
0183 
0184 /**
0185  * Get help text for supported format codes.
0186  *
0187  * @param onlyRows if true only the tr elements are returned,
0188  *                 not the surrounding table
0189  *
0190  * @return help text.
0191  */
0192 QString TrackDataFormatReplacer::getToolTip(bool onlyRows)
0193 {
0194   QString str;
0195   if (!onlyRows) str += QLatin1String("<table>\n");
0196   str += FrameFormatReplacer::getToolTip(true);
0197 
0198   str += QLatin1String("<tr><td>%f</td><td>%{file}</td><td>");
0199   str += QCoreApplication::translate("@default", "Filename");
0200   str += QLatin1String("</td></tr>\n");
0201 
0202   str += QLatin1String("<tr><td>%p</td><td>%{filepath}</td><td>");
0203   const char* const absolutePathToFileStr =
0204       QT_TRANSLATE_NOOP("@default", "Absolute path to file");
0205   str += QCoreApplication::translate("@default", absolutePathToFileStr);
0206   str += QLatin1String("</td></tr>\n");
0207 
0208   str += QLatin1String("<tr><td></td><td>%{modificationdate}</td><td>");
0209   const char* const modificationDateStr =
0210       QT_TRANSLATE_NOOP("@default", "Modification date");
0211   str += QCoreApplication::translate("@default", modificationDateStr);
0212   str += QLatin1String("</td></tr>\n");
0213 
0214   str += QLatin1String("<tr><td></td><td>%{creationdate}</td><td>");
0215   const char* const creationDateStr =
0216       QT_TRANSLATE_NOOP("@default", "Creation date");
0217   str += QCoreApplication::translate("@default", creationDateStr);
0218   str += QLatin1String("</td></tr>\n");
0219 
0220   str += QLatin1String("<tr><td>%u</td><td>%{url}</td><td>");
0221   str += QCoreApplication::translate("@default", "URL");
0222   str += QLatin1String("</td></tr>\n");
0223 
0224   str += QLatin1String("<tr><td></td><td>%{dirname}</td><td>");
0225   const char* const directoryNameStr =
0226       QT_TRANSLATE_NOOP("@default", "Directory name");
0227   str += QCoreApplication::translate("@default", directoryNameStr);
0228   str += QLatin1String("</td></tr>\n");
0229 
0230   str += QLatin1String("<tr><td>%d</td><td>%{duration}</td><td>");
0231   const char* const lengthStr = QT_TRANSLATE_NOOP("@default", "Length");
0232   str += QCoreApplication::translate("@default", lengthStr);
0233   str += QLatin1String(" &quot;M:S&quot;</td></tr>\n");
0234 
0235   str += QLatin1String("<tr><td>%D</td><td>%{seconds}</td><td>");
0236   str += QCoreApplication::translate("@default", lengthStr);
0237   str += QLatin1String(" &quot;S&quot;</td></tr>\n");
0238 
0239   str += QLatin1String("<tr><td>%n</td><td>%{tracks}</td><td>");
0240   const char* const numberOfTracksStr =
0241       QT_TRANSLATE_NOOP("@default", "Number of tracks");
0242   str += QCoreApplication::translate("@default", numberOfTracksStr);
0243   str += QLatin1String("</td></tr>\n");
0244 
0245   str += QLatin1String("<tr><td>%e</td><td>%{extension}</td><td>");
0246   const char* const extensionStr = QT_TRANSLATE_NOOP("@default", "Extension");
0247   str += QCoreApplication::translate("@default", extensionStr);
0248   str += QLatin1String("</td></tr>\n");
0249 
0250   str += QLatin1String("<tr><td>%O</td><td>%{tag1}</td><td>");
0251   str += QCoreApplication::translate("@default", "Tag 1");
0252   str += QLatin1String("</td></tr>\n");
0253 
0254   str += QLatin1String("<tr><td>%o</td><td>%{tag2}</td><td>");
0255   str += QCoreApplication::translate("@default", "Tag 2");
0256   str += QLatin1String("</td></tr>\n");
0257 
0258   str += QLatin1String("<tr><td>%b</td><td>%{bitrate}</td><td>");
0259   const char* const bitrateStr = QT_TRANSLATE_NOOP("@default", "Bitrate");
0260   str += QCoreApplication::translate("@default", bitrateStr);
0261   str += QLatin1String("</td></tr>\n");
0262 
0263   str += QLatin1String("<tr><td>%v</td><td>%{vbr}</td><td>");
0264   const char* const vbrStr = QT_TRANSLATE_NOOP("@default", "VBR");
0265   str += QCoreApplication::translate("@default", vbrStr);
0266   str += QLatin1String("</td></tr>\n");
0267 
0268   str += QLatin1String("<tr><td>%r</td><td>%{samplerate}</td><td>");
0269   const char* const samplerateStr = QT_TRANSLATE_NOOP("@default", "Samplerate");
0270   str += QCoreApplication::translate("@default", samplerateStr);
0271   str += QLatin1String("</td></tr>\n");
0272 
0273   str += QLatin1String("<tr><td>%m</td><td>%{mode}</td><td>Stereo, Joint Stereo</td></tr>\n");
0274 
0275   str += QLatin1String("<tr><td>%C</td><td>%{channels}</td><td>");
0276   const char* const channelsStr = QT_TRANSLATE_NOOP("@default", "Channels");
0277   str += QCoreApplication::translate("@default", channelsStr);
0278   str += QLatin1String("</td></tr>\n");
0279 
0280   str += QLatin1String("<tr><td>%k</td><td>%{codec}</td><td>");
0281   const char* const codecStr = QT_TRANSLATE_NOOP("@default", "Codec");
0282   str += QCoreApplication::translate("@default", codecStr);
0283   str += QLatin1String("</td></tr>\n");
0284 
0285   str += QLatin1String("<tr><td>%w</td><td>%{marked}</td><td>");
0286   const char* const markedStr = QT_TRANSLATE_NOOP("@default", "Marked");
0287   str += QCoreApplication::translate("@default", markedStr);
0288   str += QLatin1String("</td></tr>\n");
0289 
0290   str += QLatin1String("<tr><td>%ha...</td><td>%h{artist}...</td><td>");
0291   const char* const escapeForHtmlStr =
0292       QT_TRANSLATE_NOOP("@default", "Escape for HTML");
0293   str += QCoreApplication::translate("@default", escapeForHtmlStr);
0294   str += QLatin1String("</td></tr>\n");
0295 
0296   if (!onlyRows) str += QLatin1String("</table>\n");
0297   return str;
0298 }
0299 
0300 
0301 /**
0302  * Constructor.
0303  */
0304 TrackData::TrackData() = default;
0305 
0306 /**
0307  * Constructor.
0308  * All fields except the import duration are set from the tagged file,
0309  * which should be read using readTags() before.
0310  *
0311  * @param taggedFile tagged file providing track data
0312  * @param tagVersion source of frames
0313  */
0314 TrackData::TrackData(TaggedFile& taggedFile, Frame::TagVersion tagVersion)
0315   : m_taggedFileIndex(taggedFile.getIndex())
0316 {
0317   for (Frame::TagNumber tagNr : Frame::tagNumbersFromMask(tagVersion)) {
0318     if (empty()) {
0319       taggedFile.getAllFrames(tagNr, *this);
0320     } else {
0321       FrameCollection frames;
0322       taggedFile.getAllFrames(tagNr, frames);
0323       merge(frames);
0324     }
0325   }
0326 }
0327 
0328 /**
0329  * Get tagged file associated with this track data.
0330  * @return tagged file, 0 if none assigned.
0331  */
0332 TaggedFile* TrackData::getTaggedFile() const {
0333   return FileProxyModel::getTaggedFileOfIndex(m_taggedFileIndex);
0334 }
0335 
0336 /**
0337  * Get duration of file.
0338  * @return duration of file.
0339  */
0340 int TrackData::getFileDuration() const
0341 {
0342   TaggedFile* taggedFile = getTaggedFile();
0343   return taggedFile ? taggedFile->getDuration() : 0;
0344 }
0345 
0346 /**
0347  * Get absolute filename.
0348  *
0349  * @return absolute file path.
0350  */
0351 QString TrackData::getAbsFilename() const
0352 {
0353   TaggedFile* taggedFile = getTaggedFile();
0354   return taggedFile ? taggedFile->getAbsFilename() : QString();
0355 }
0356 
0357 /**
0358  * Get filename.
0359  *
0360  * @return filename.
0361  */
0362 QString TrackData::getFilename() const
0363 {
0364   TaggedFile* taggedFile = getTaggedFile();
0365   return taggedFile ? taggedFile->getFilename() : QString();
0366 }
0367 
0368 /**
0369  * Get directory name.
0370  *
0371  * @return directory name.
0372  */
0373 QString TrackData::getDirname() const
0374 {
0375   TaggedFile* taggedFile = getTaggedFile();
0376   return taggedFile ? taggedFile->getDirname() : QString();
0377 }
0378 
0379 /**
0380  * Get the format of tag.
0381  *
0382  * @param tagNr tag number
0383  * @return string describing format of tag 1,
0384  *         e.g. "ID3v1.1", "ID3v2.3", "Vorbis", "APE",
0385  *         QString::null if unknown.
0386  */
0387 QString TrackData::getTagFormat(Frame::TagNumber tagNr) const
0388 {
0389   TaggedFile* taggedFile = getTaggedFile();
0390   return taggedFile ? taggedFile->getTagFormat(tagNr) : QString();
0391 }
0392 
0393 /**
0394  * Get detail info.
0395  * @param info the detail information is returned here
0396  */
0397 void TrackData::getDetailInfo(TaggedFile::DetailInfo& info) const
0398 {
0399   if (TaggedFile* taggedFile = getTaggedFile()) {
0400     taggedFile->getDetailInfo(info);
0401   }
0402 }
0403 
0404 /**
0405  * Format a string from track data.
0406  * Supported format fields:
0407  * Those supported by TrackDataFormatReplacer::getReplacement()
0408  *
0409  * @param format    format specification
0410  *
0411  * @return formatted string.
0412  */
0413 QString TrackData::formatString(const QString& format) const
0414 {
0415   TrackDataFormatReplacer fmt(*this, format);
0416   fmt.replaceEscapedChars();
0417   fmt.replacePercentCodes(FormatReplacer::FSF_SupportHtmlEscape);
0418   return fmt.getString();
0419 }
0420 
0421 /**
0422  * Create filename from tags according to format string.
0423  *
0424  * @param str       format string containing codes supported by
0425  *                  TrackDataFormatReplacer::getReplacement()
0426  * @param isDirname true to generate a directory name
0427  *
0428  * @return format string with format codes replaced by tags.
0429  */
0430 QString TrackData::formatFilenameFromTags(QString str, bool isDirname) const
0431 {
0432   if (!isDirname) {
0433     transformToFilename(str);
0434   }
0435 
0436   TrackDataFormatReplacer fmt(*this, str);
0437   fmt.replacePercentCodes(isDirname ?
0438                           FormatReplacer::FSF_ReplaceSeparators : 0);
0439   return fmt.getString();
0440 }
0441 
0442 /**
0443  * Transform string to file name.
0444  * The directory part is removed and a file extension added.
0445  * @param str string to transform
0446  */
0447 void TrackData::transformToFilename(QString& str) const
0448 {
0449   // first remove directory part from str
0450   if (const int sepPos = str.lastIndexOf(QLatin1Char('/')); sepPos >= 0) {
0451     str.remove(0, sepPos + 1);
0452   }
0453   // add extension to str
0454   str += getFileExtension(true);
0455 }
0456 
0457 /**
0458  * Get help text for format codes supported by formatString().
0459  *
0460  * @param onlyRows if true only the tr elements are returned,
0461  *                 not the surrounding table
0462  *
0463  * @return help text.
0464  */
0465 QString TrackData::getFormatToolTip(bool onlyRows)
0466 {
0467   return TrackDataFormatReplacer::getToolTip(onlyRows);
0468 }
0469 
0470 /**
0471  * Get file extension including the dot.
0472  *
0473  * @param preferFromFilename true to prefer extension from current filename
0474  *                           over default extension for file type
0475  *
0476  * @return file extension, e.g. ".mp3".
0477  */
0478 QString TrackData::getFileExtension(bool preferFromFilename) const
0479 {
0480   QString fileExtension;
0481   QString absFilename;
0482   if (TaggedFile* taggedFile = getTaggedFile()) {
0483     fileExtension = taggedFile->getFileExtension();
0484     absFilename = taggedFile->getAbsFilename();
0485   }
0486   if (preferFromFilename || fileExtension.isEmpty()) {
0487     if (int dotPos = absFilename.lastIndexOf(QLatin1Char('.')); dotPos != -1) {
0488       return absFilename.mid(dotPos);
0489     }
0490   }
0491   return fileExtension;
0492 }
0493 
0494 /**
0495  * Get the total number of tracks in the directory.
0496  *
0497  * @return total number of tracks, -1 if unavailable.
0498  */
0499 int TrackData::getTotalNumberOfTracksInDir() const
0500 {
0501   TaggedFile* taggedFile = getTaggedFile();
0502   return taggedFile ? taggedFile->getTotalNumberOfTracksInDir() : -1;
0503 }
0504 
0505 
0506 /**
0507  * Get the difference between the imported duration and the track's duration.
0508  * @return absolute value of time difference in seconds, -1 if not available.
0509  */
0510 int ImportTrackData::getTimeDifference() const
0511 {
0512   int fileDuration = getFileDuration();
0513   int importDuration = getImportDuration();
0514   return fileDuration != 0 && importDuration != 0
0515       ? fileDuration > importDuration
0516         ? fileDuration - importDuration
0517         : importDuration - fileDuration
0518       : -1;
0519 }
0520 
0521 namespace {
0522 
0523 /**
0524  * Get lower case words found in string.
0525  * @return lower case words.
0526  */
0527 QSet<QString> getLowerCaseWords(const QString& str)
0528 {
0529   if (!str.isEmpty()) {
0530     QString normalized = str.normalized(QString::NormalizationForm_D).toLower();
0531     QString simplified;
0532     for (auto it = normalized.constBegin(); it != normalized.constEnd(); ++it) {
0533       if (it->isLetter()) {
0534         simplified += *it;
0535       } else if (it->isPunct() || it->isSpace() || it->isSymbol()) {
0536         simplified += QLatin1Char(' ');
0537       }
0538     }
0539 #if QT_VERSION >= 0x050e00
0540     const QStringList words =
0541         simplified.split(QLatin1Char(' '), Qt::SkipEmptyParts);
0542     return QSet(words.constBegin(), words.constEnd());
0543 #else
0544     return simplified.split(QLatin1Char(' '), QString::SkipEmptyParts).toSet();
0545 #endif
0546   }
0547   return QSet<QString>();
0548 }
0549 
0550 }
0551 
0552 /**
0553  * Get words of file name.
0554  * @return lower case words found in file name.
0555  */
0556 QSet<QString> ImportTrackData::getFilenameWords() const
0557 {
0558   QString fileName = getFilename();
0559   if (int endIndex = fileName.lastIndexOf(QLatin1Char('.')); endIndex > 0) {
0560     fileName.truncate(endIndex);
0561   }
0562   return getLowerCaseWords(fileName);
0563 }
0564 
0565 /**
0566  * Get words of title.
0567  * @return lower case words found in title.
0568  */
0569 QSet<QString> ImportTrackData::getTitleWords() const
0570 {
0571   return getLowerCaseWords(getTitle());
0572 }
0573 
0574 
0575 /**
0576  * Clear vector and associated data.
0577  */
0578 void ImportTrackDataVector::clearData()
0579 {
0580   clear();
0581   m_coverArtUrl.clear();
0582 }
0583 
0584 /**
0585  * Get album artist.
0586  * @return album artist.
0587  */
0588 QString ImportTrackDataVector::getArtist() const
0589 {
0590   return getFrame(Frame::FT_Artist);
0591 }
0592 
0593 /**
0594  * Get album title.
0595  * @return album title.
0596  */
0597 QString ImportTrackDataVector::getAlbum() const
0598 {
0599   return getFrame(Frame::FT_Album);
0600 }
0601 
0602 /**
0603  * Check if tag is supported in the first track.
0604  * @param tagNr tag number
0605  * @return true if tag is supported.
0606  */
0607 bool ImportTrackDataVector::isTagSupported(Frame::TagNumber tagNr) const
0608 {
0609   if (!isEmpty()) {
0610     if (TaggedFile* taggedFile = at(0).getTaggedFile()) {
0611       return taggedFile->isTagSupported(tagNr);
0612     }
0613   }
0614   return true;
0615 }
0616 
0617 /**
0618  * Get frame from first track.
0619  * @param type frame type
0620  * @return value of frame.
0621  */
0622 QString ImportTrackDataVector::getFrame(Frame::Type type) const
0623 {
0624   QString result;
0625   if (!isEmpty()) {
0626     const ImportTrackData& trackData = at(0);
0627     result = trackData.getValue(type);
0628     if (!result.isEmpty())
0629       return result;
0630     TaggedFile* taggedFile = trackData.getTaggedFile();
0631     FrameCollection frames;
0632     for (Frame::TagNumber tagNr : Frame::allTagNumbers()) {
0633       taggedFile->getAllFrames(tagNr, frames);
0634       result = frames.getValue(type);
0635       if (!result.isEmpty())
0636         return result;
0637     }
0638   }
0639   return result;
0640 }
0641 
0642 /**
0643  * Read the tags from the files.
0644  * This can be used to fill the track data with another tag version.
0645  *
0646  * @param tagVersion tag version to read
0647  */
0648 void ImportTrackDataVector::readTags(Frame::TagVersion tagVersion)
0649 {
0650   for (auto it = begin(); it != end(); ++it) {
0651     if (TaggedFile* taggedFile = it->getTaggedFile()) {
0652       it->clear();
0653       for (Frame::TagNumber tagNr : Frame::tagNumbersFromMask(tagVersion)) {
0654         if (it->empty()) {
0655           taggedFile->getAllFrames(tagNr, *it);
0656         } else {
0657           FrameCollection frames;
0658           taggedFile->getAllFrames(tagNr, frames);
0659           it->merge(frames);
0660         }
0661       }
0662     }
0663     it->setImportDuration(0);
0664     it->setEnabled(true);
0665   }
0666   setCoverArtUrl(QUrl());
0667 }
0668 
0669 #ifndef QT_NO_DEBUG
0670 /**
0671  * Dump contents of tracks to debug console.
0672  */
0673 void ImportTrackDataVector::dump() const
0674 {
0675   qDebug("ImportTrackDataVector (%s - %s, %s):",
0676          qPrintable(getArtist()), qPrintable(getAlbum()),
0677          qPrintable(getCoverArtUrl().toString()));
0678   for (auto it = constBegin(); it != constEnd(); ++it) {
0679     const ImportTrackData& trackData = *it;
0680     int fileDuration = trackData.getFileDuration();
0681     int importDuration = trackData.getImportDuration();
0682     qDebug("%d:%02d, %d:%02d, %s, %d, %s, %s, %s, %d, %s",
0683            fileDuration / 60, fileDuration % 60,
0684            importDuration / 60, importDuration % 60,
0685            qPrintable(trackData.getFilename()),
0686            trackData.getTrack(),
0687            qPrintable(trackData.getTitle()),
0688            qPrintable(trackData.getArtist()),
0689            qPrintable(trackData.getAlbum()),
0690            trackData.getYear(),
0691            qPrintable(trackData.getGenre()));
0692   }
0693 }
0694 #endif