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 }