File indexing completed on 2024-05-19 04:56:04
0001 /** 0002 * \file framelist.cpp 0003 * List of ID3v2.3 frames. 0004 * 0005 * \b Project: Kid3 0006 * \author Urs Fleisch 0007 * \date 9 Jan 2003 0008 * 0009 * Copyright (C) 2003-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 "framelist.h" 0028 #include <QItemSelectionModel> 0029 #include "taggedfile.h" 0030 #include "frametablemodel.h" 0031 #include "iframeeditor.h" 0032 #include "pictureframe.h" 0033 0034 /** 0035 * Constructor. 0036 * 0037 * @param tagNr tag number 0038 * @param ftm frame table model 0039 * @param selModel item selection model 0040 */ 0041 FrameList::FrameList(Frame::TagNumber tagNr, 0042 FrameTableModel* ftm, QItemSelectionModel* selModel) 0043 : QObject(ftm), m_taggedFile(nullptr), 0044 m_frameEditor(nullptr), m_frameTableModel(ftm), m_selectionModel(selModel), 0045 m_cursorRow(-1), m_cursorColumn(-1), m_tagNr(tagNr), m_addingFrame(false) 0046 { 0047 setObjectName(QLatin1String("FrameList")); 0048 } 0049 0050 /** 0051 * Get ID of selected frame list item. 0052 * 0053 * @return ID of selected item, 0054 * -1 if not item is selected. 0055 */ 0056 int FrameList::getSelectedId() const 0057 { 0058 const Frame* currentFrame = 0059 m_frameTableModel->getFrameOfIndex(m_selectionModel->currentIndex()); 0060 return currentFrame ? currentFrame->getIndex() : -1; 0061 } 0062 0063 /** 0064 * Get frame of selected frame list item. 0065 * 0066 * @param frame the selected frame is returned here 0067 * 0068 * @return false if not item is selected. 0069 */ 0070 bool FrameList::getSelectedFrame(Frame& frame) const 0071 { 0072 if (const Frame* currentFrame = 0073 m_frameTableModel->getFrameOfIndex(m_selectionModel->currentIndex())) { 0074 frame = *currentFrame; 0075 return true; 0076 } 0077 return false; 0078 } 0079 0080 /** 0081 * Select the frame by ID. 0082 * 0083 * @param id ID of frame to select 0084 */ 0085 void FrameList::setSelectedId(int id) 0086 { 0087 m_selectionModel->setCurrentIndex( 0088 m_frameTableModel->index( 0089 m_frameTableModel->getRowWithFrameIndex(id), 0), 0090 QItemSelectionModel::SelectCurrent); 0091 } 0092 0093 /** 0094 * Get the name of the selected frame. 0095 * 0096 * @return name, QString::null if nothing selected. 0097 */ 0098 QString FrameList::getSelectedName() const 0099 { 0100 const Frame* currentFrame = 0101 m_frameTableModel->getFrameOfIndex(m_selectionModel->currentIndex()); 0102 return currentFrame ? currentFrame->getName() : QString(); 0103 } 0104 0105 /** 0106 * Select a frame with a given name. 0107 * 0108 * @param name name of frame 0109 * 0110 * @return true if a frame with that name could be selected. 0111 */ 0112 bool FrameList::selectByName(const QString& name) 0113 { 0114 return selectByRow(m_frameTableModel->getRowWithFrameName(name)); 0115 } 0116 0117 /** 0118 * Select a frame by row number in the frame table. 0119 * 0120 * @param row row of frame 0121 * 0122 * @return true if a frame could be selected. 0123 */ 0124 bool FrameList::selectByRow(int row) 0125 { 0126 if (row < 0 || row >= m_frameTableModel->rowCount()) 0127 return false; 0128 0129 m_selectionModel->setCurrentIndex(m_frameTableModel->index(row, 0), 0130 QItemSelectionModel::SelectCurrent); 0131 return true; 0132 } 0133 0134 /** 0135 * Set the frame table model from the tagged file. 0136 */ 0137 void FrameList::setModelFromTaggedFile() 0138 { 0139 if (m_taggedFile) { 0140 FrameCollection frames; 0141 m_taggedFile->getAllFrames(m_tagNr, frames); 0142 m_frameTableModel->transferFrames(frames); 0143 } 0144 } 0145 0146 /** 0147 * Delete selected frame. 0148 * 0149 * @return false if frame not found. 0150 */ 0151 bool FrameList::deleteFrame() 0152 { 0153 saveCursor(); 0154 if (Frame frame; getSelectedFrame(frame) && m_taggedFile) { 0155 m_taggedFile->deleteFrame(m_tagNr, frame); 0156 setModelFromTaggedFile(); 0157 restoreCursor(); 0158 return true; 0159 } 0160 return false; 0161 } 0162 0163 /** 0164 * Set editor for frames. 0165 * 0166 * @param frameEditor frame editor 0167 */ 0168 void FrameList::setFrameEditor(IFrameEditor* frameEditor) 0169 { 0170 if (m_frameEditor != frameEditor) { 0171 if (m_frameEditor) { 0172 QObject* obj = m_frameEditor->qobject(); 0173 disconnect(obj, SIGNAL(frameSelected(Frame::TagNumber,const Frame*)), // clazy:exclude=old-style-connect 0174 this, SLOT(onFrameSelected(Frame::TagNumber,const Frame*))); 0175 disconnect(obj, SIGNAL(frameEdited(Frame::TagNumber,const Frame*)), // clazy:exclude=old-style-connect 0176 this, SLOT(onFrameEdited(Frame::TagNumber,const Frame*))); 0177 } 0178 m_frameEditor = frameEditor; 0179 if (m_frameEditor) { 0180 QObject* obj = m_frameEditor->qobject(); 0181 connect(obj, SIGNAL(frameSelected(Frame::TagNumber,const Frame*)), // clazy:exclude=old-style-connect 0182 this, SLOT(onFrameSelected(Frame::TagNumber,const Frame*))); 0183 connect(obj, SIGNAL(frameEdited(Frame::TagNumber,const Frame*)), // clazy:exclude=old-style-connect 0184 this, SLOT(onFrameEdited(Frame::TagNumber,const Frame*))); 0185 } 0186 } 0187 } 0188 0189 /** 0190 * Let the user select and edit a frame type and then edit the frame. 0191 * Add the frame if the edits are accepted. 0192 * frameEdited() is emitted with the added frame. 0193 */ 0194 void FrameList::selectAddAndEditFrame() 0195 { 0196 if (m_taggedFile && m_frameEditor) { 0197 m_addingFrame = true; 0198 m_frameEditor->setTagNumber(m_tagNr); 0199 m_frameEditor->selectFrame(&m_frame, m_taggedFile); 0200 } else { 0201 emit frameAdded(nullptr); 0202 } 0203 } 0204 0205 /** 0206 * Called when the frame is selected. 0207 * @param tagNr tag number 0208 * @param frame selected frame, 0 if none selected. 0209 */ 0210 void FrameList::onFrameSelected(Frame::TagNumber tagNr, const Frame* frame) 0211 { 0212 if (tagNr != m_tagNr) 0213 return; 0214 0215 if (frame) { 0216 addAndEditFrame(); 0217 } else { 0218 emit frameAdded(nullptr); 0219 } 0220 } 0221 0222 /** 0223 * Add and edit a new frame. 0224 * frameEdited() is emitted with the added frame. 0225 */ 0226 void FrameList::addAndEditFrame() 0227 { 0228 if (m_taggedFile) { 0229 m_oldChangedFrames = m_taggedFile->getChangedFrames(m_tagNr); 0230 if (!m_taggedFile->addFrame(m_tagNr, m_frame)) { 0231 emit frameAdded(nullptr); 0232 } else if (m_frameEditor) { 0233 m_addingFrame = true; 0234 m_frameEditor->setTagNumber(m_tagNr); 0235 m_frameEditor->editFrameOfTaggedFile(&m_frame, m_taggedFile); 0236 } else { 0237 m_addingFrame = true; 0238 onFrameEdited(m_tagNr, &m_frame); 0239 } 0240 } else { 0241 emit frameAdded(nullptr); 0242 } 0243 } 0244 0245 /** 0246 * Edit the current frame. 0247 * The frame and its file have to be set using setFrame() and setTaggedFile(). 0248 */ 0249 void FrameList::editFrame() 0250 { 0251 if (m_frameEditor) { 0252 m_addingFrame = false; 0253 m_frameEditor->setTagNumber(m_tagNr); 0254 m_frameEditor->editFrameOfTaggedFile(&m_frame, m_taggedFile); 0255 } 0256 } 0257 0258 /** 0259 * Called when the frame is edited. 0260 * @param tagNr tag number 0261 * @param frame edited frame, 0 if canceled 0262 */ 0263 void FrameList::onFrameEdited(Frame::TagNumber tagNr, const Frame* frame) 0264 { 0265 if (tagNr != m_tagNr) 0266 return; 0267 0268 if (frame) { 0269 int index = frame->getIndex(); 0270 setModelFromTaggedFile(); 0271 if (index != -1) { 0272 setSelectedId(index); 0273 } 0274 } else { 0275 if (m_addingFrame) { 0276 m_taggedFile->deleteFrame(m_tagNr, m_frame); 0277 m_taggedFile->setChangedFrames(m_tagNr, m_oldChangedFrames); 0278 } 0279 } 0280 if (m_addingFrame) { 0281 emit frameAdded(frame); 0282 } else { 0283 emit frameEdited(frame); 0284 } 0285 } 0286 0287 /** 0288 * Paste the selected frame from the copy buffer. 0289 * 0290 * @return true if frame pasted. 0291 */ 0292 bool FrameList::pasteFrame() { 0293 if (m_taggedFile && m_frame.getType() != Frame::FT_UnknownFrame) { 0294 m_taggedFile->addFrame(m_tagNr, m_frame); 0295 m_taggedFile->setFrame(m_tagNr, m_frame); 0296 return true; 0297 } 0298 return false; 0299 } 0300 0301 /** 0302 * Add a suitable field list for the frame in the copy buffer if missing. 0303 */ 0304 void FrameList::addFrameFieldList() 0305 { 0306 if (m_taggedFile) { 0307 m_taggedFile->addFieldList(m_tagNr, m_frame); 0308 if (m_frame.getFieldList().isEmpty() && 0309 m_frame.getType() == Frame::FT_Picture) { 0310 PictureFrame::setFields(m_frame); 0311 } 0312 } 0313 } 0314 0315 /** 0316 * Save the current cursor position. 0317 */ 0318 void FrameList::saveCursor() 0319 { 0320 m_cursorRow = m_selectionModel->currentIndex().row(); 0321 m_cursorColumn = m_selectionModel->currentIndex().column(); 0322 } 0323 0324 /** 0325 * Restore the cursor position saved with saveCursor(). 0326 */ 0327 void FrameList::restoreCursor() 0328 { 0329 if (int lastRow = m_frameTableModel->rowCount() - 1; 0330 m_cursorRow >= 0 && m_cursorColumn >= 0 && lastRow >= 0) { 0331 if (m_cursorRow > lastRow) { 0332 m_cursorRow = lastRow; 0333 } 0334 m_selectionModel->setCurrentIndex( 0335 m_frameTableModel->index(m_cursorRow, m_cursorColumn), 0336 QItemSelectionModel::SelectCurrent); 0337 } 0338 }