File indexing completed on 2024-05-19 04:56:08
0001 /** 0002 * \file taggedfileselection.h 0003 * Information about selected tagged files. 0004 * 0005 * \b Project: Kid3 0006 * \author Urs Fleisch 0007 * \date 19 Jun 2014 0008 * 0009 * Copyright (C) 2014-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 "taggedfileselection.h" 0028 #include "taggedfile.h" 0029 #include "trackdata.h" 0030 #include "frametablemodel.h" 0031 #include "fileproxymodel.h" 0032 #include "pictureframe.h" 0033 #include "guiconfig.h" 0034 #include "tagconfig.h" 0035 #include "fileconfig.h" 0036 0037 /** 0038 * Constructor. 0039 * @param framesModel frame table models for all tags, Frame::Tag_NumValues 0040 * elements 0041 * @param parent parent object 0042 */ 0043 TaggedFileSelection::TaggedFileSelection( 0044 FrameTableModel* framesModel[], QObject* parent) : QObject(parent) 0045 { 0046 FOR_ALL_TAGS(tagNr) { 0047 m_framesModel[tagNr] = framesModel[tagNr]; 0048 m_tagContext[tagNr] = new TaggedFileSelectionTagContext(this, tagNr); 0049 } 0050 setObjectName(QLatin1String("TaggedFileSelection")); 0051 } 0052 0053 /** 0054 * Start adding tagged files to selection. 0055 * Has to be called before adding the first file using addTaggedFile(). 0056 */ 0057 void TaggedFileSelection::beginAddTaggedFiles() 0058 { 0059 m_lastState = m_state; 0060 m_state.m_singleFile = nullptr; 0061 m_state.m_fileCount = 0; 0062 FOR_ALL_TAGS(tagNr) { 0063 m_state.m_tagSupportedCount[tagNr] = 0; 0064 m_state.m_hasTag[tagNr] = false; 0065 m_framesModel[tagNr]->beginFilterDifferent(); 0066 } 0067 } 0068 0069 /** 0070 * End adding tagged files to selection. 0071 * Has to be called after adding the last file using addTaggedFile(). 0072 */ 0073 void TaggedFileSelection::endAddTaggedFiles() 0074 { 0075 FOR_ALL_TAGS(tagNr) { 0076 m_framesModel[tagNr]->setAllCheckStates( 0077 m_state.m_tagSupportedCount[tagNr] == 1); 0078 m_framesModel[tagNr]->endFilterDifferent(); 0079 } 0080 if (GuiConfig::instance().autoHideTags()) { 0081 // If a tag is supposed to be absent, make sure that there is really no 0082 // unsaved data in the tag. 0083 FOR_ALL_TAGS(tagNr) { 0084 if (!m_state.m_hasTag[tagNr] && 0085 (m_state.m_tagSupportedCount[tagNr] > 0 || 0086 m_state.m_fileCount == 0)) { 0087 const FrameCollection& frames = m_framesModel[tagNr]->frames(); 0088 for (auto it = frames.cbegin(); it != frames.cend(); ++it) { 0089 if (!it->getValue().isEmpty()) { 0090 m_state.m_hasTag[tagNr] = true; 0091 break; 0092 } 0093 } 0094 } 0095 } 0096 } 0097 FOR_ALL_TAGS(tagNr) { 0098 if (TagConfig::instance().markTruncations()) { 0099 m_framesModel[tagNr]->markRows(m_state.m_singleFile 0100 ? m_state.m_singleFile->getTruncationFlags(tagNr) 0101 : 0); 0102 } 0103 if (FileConfig::instance().markChanges()) { 0104 m_framesModel[tagNr]->markChangedFrames(m_state.m_singleFile 0105 ? m_state.m_singleFile->getChangedFrames(tagNr) 0106 : QList<Frame::ExtendedType>()); 0107 } 0108 if (m_state.hasTag(tagNr) != m_lastState.hasTag(tagNr)) { 0109 emit m_tagContext[tagNr]->hasTagChanged(m_state.hasTag(tagNr)); 0110 } 0111 if (m_state.isTagUsed(tagNr) != m_lastState.isTagUsed(tagNr)) { 0112 emit m_tagContext[tagNr]->tagUsedChanged(m_state.isTagUsed(tagNr)); 0113 } 0114 } 0115 0116 if (m_state.isEmpty() != m_lastState.isEmpty()) { 0117 emit emptyChanged(m_state.isEmpty()); 0118 } 0119 if (m_state.isSingleFileSelected() != m_lastState.isSingleFileSelected()) { 0120 emit singleFileSelectedChanged(m_state.isSingleFileSelected()); 0121 } 0122 if (m_state.isSingleFileSelected() || m_lastState.isSingleFileSelected()) { 0123 // The properties depending on the single file may have changed. 0124 emit singleFileChanged(); 0125 FOR_ALL_TAGS(tagNr) { 0126 emit m_tagContext[tagNr]->tagFormatChanged(); 0127 } 0128 } 0129 } 0130 0131 /** 0132 * Add a tagged file to the selection. 0133 * @param taggedFile tagged file 0134 */ 0135 void TaggedFileSelection::addTaggedFile(TaggedFile* taggedFile) 0136 { 0137 taggedFile = FileProxyModel::readTagsFromTaggedFile(taggedFile); 0138 0139 FOR_ALL_TAGS(tagNr) { 0140 if (taggedFile->isTagSupported(tagNr)) { 0141 if (m_state.m_tagSupportedCount[tagNr] == 0) { 0142 FrameCollection frames; 0143 taggedFile->getAllFrames(tagNr, frames); 0144 m_framesModel[tagNr]->transferFrames(frames); 0145 } else { 0146 FrameCollection fileFrames; 0147 taggedFile->getAllFrames(tagNr, fileFrames); 0148 m_framesModel[tagNr]->filterDifferent(fileFrames); 0149 } 0150 ++m_state.m_tagSupportedCount[tagNr]; 0151 } 0152 } 0153 m_state.m_singleFile = m_state.m_fileCount == 0 ? taggedFile : nullptr; 0154 ++m_state.m_fileCount; 0155 0156 FOR_ALL_TAGS(tagNr) { 0157 m_state.m_hasTag[tagNr] = 0158 m_state.m_hasTag[tagNr] || taggedFile->hasTag(tagNr); 0159 } 0160 } 0161 0162 /** 0163 * Get file name. 0164 * @return file name if single file selected, else null string. 0165 */ 0166 QString TaggedFileSelection::getFilename() const 0167 { 0168 return m_state.m_singleFile ? m_state.m_singleFile->getFilename() : QString(); 0169 } 0170 0171 /** 0172 * Set file name if single file selected. 0173 * @param fn file name 0174 */ 0175 void TaggedFileSelection::setFilename(const QString& fn) 0176 { 0177 if (m_state.m_singleFile && !fn.isEmpty() && 0178 m_state.m_singleFile->getFilename() != fn) { 0179 m_state.m_singleFile->setFilename(fn); 0180 emit fileNameModified(); 0181 } 0182 } 0183 0184 /** 0185 * Get file path. 0186 * @return absolute file path if single file selected, else null string. 0187 */ 0188 QString TaggedFileSelection::getFilePath() const 0189 { 0190 return m_state.m_singleFile 0191 ? m_state.m_singleFile->getAbsFilename() : QString(); 0192 } 0193 0194 /** 0195 * Get string representation of detail information. 0196 * @return information summary as string if single file else null string. 0197 */ 0198 QString TaggedFileSelection::getDetailInfo() const 0199 { 0200 TaggedFile::DetailInfo info; 0201 if (m_state.m_singleFile) { 0202 m_state.m_singleFile->getDetailInfo(info); 0203 } 0204 return info.toString(); 0205 } 0206 0207 /** 0208 * Get the format of tag. 0209 * @param tagNr tag number 0210 * @return string describing format of tag 2 if single file selected, 0211 * else null string. 0212 */ 0213 QString TaggedFileSelection::getTagFormat(Frame::TagNumber tagNr) const 0214 { 0215 return m_state.m_singleFile ? m_state.m_singleFile->getTagFormat(tagNr) 0216 : QString(); 0217 } 0218 0219 /** 0220 * Get the format of tag 1. 0221 * @return string describing format of tag 1 if single file selected, 0222 * else null string. 0223 * @deprecated Use tag(Frame::Tag_1)->tagFormat() instead. 0224 */ 0225 QString TaggedFileSelection::getTagFormatV1() const 0226 { 0227 return m_tagContext[Frame::Tag_1]->tagFormat(); 0228 } 0229 0230 /** 0231 * Get the format of tag 2. 0232 * @return string describing format of tag 2 if single file selected, 0233 * else null string. 0234 * @deprecated Use tag(Frame::Tag_2)->tagFormat() instead. 0235 */ 0236 QString TaggedFileSelection::getTagFormatV2() const 0237 { 0238 return m_tagContext[Frame::Tag_2]->tagFormat(); 0239 } 0240 0241 /** 0242 * Check if filename is changed. 0243 * @return true if single file selected and filename was changed. 0244 */ 0245 bool TaggedFileSelection::isFilenameChanged() const 0246 { 0247 return m_state.m_singleFile && m_state.m_singleFile->isFilenameChanged(); 0248 } 0249 0250 /** 0251 * Get data from a picture frame. 0252 * @return picture data, empty if not available. 0253 */ 0254 QByteArray TaggedFileSelection::getPicture() const 0255 { 0256 QByteArray data; 0257 const FrameCollection& frames = m_framesModel[Frame::Tag_Picture]->frames(); 0258 if (auto it = frames.find( 0259 Frame(Frame::FT_Picture, QLatin1String(""), QLatin1String(""), -1)); 0260 it != frames.cend() && !it->isInactive()) { 0261 PictureFrame::getData(*it, data); 0262 } 0263 return data; 0264 } 0265 0266 /** 0267 * Replace codes in format string with information from the tags. 0268 * @param tagVersion tag version 0269 * @param fmt format string 0270 * @return string with format codes replaced. 0271 */ 0272 QString TaggedFileSelection::formatString(Frame::TagVersion tagVersion, 0273 const QString& fmt) const 0274 { 0275 if (!m_state.m_singleFile) 0276 return fmt; 0277 0278 TrackData trackData(*m_state.m_singleFile, tagVersion); 0279 return trackData.formatString(fmt); 0280 } 0281 0282 /** 0283 * Select changed frames in the tables if multiple files are selected. 0284 */ 0285 void TaggedFileSelection::selectChangedFrames() 0286 { 0287 if (m_state.m_fileCount > 1) { 0288 FOR_ALL_TAGS(tagNr) { 0289 m_framesModel[tagNr]->selectChangedFrames(); 0290 } 0291 } 0292 } 0293 0294 /** 0295 * Clear frame collection in frame models not used by current selection. 0296 */ 0297 void TaggedFileSelection::clearUnusedFrames() 0298 { 0299 FOR_ALL_TAGS(tagNr) { 0300 if (m_state.m_tagSupportedCount[tagNr] == 0) { 0301 m_framesModel[tagNr]->clearFrames(); 0302 } 0303 } 0304 }