1 /**
2  * \file subframeseditor.cpp
3  * Editor for subframes contained in a frame.
4  *
5  * \b Project: Kid3
6  * \author Urs Fleisch
7  * \date 18 Sep 2015
8  *
9  * Copyright (C) 2015-2018  Urs Fleisch
10  *
11  * This file is part of Kid3.
12  *
13  * Kid3 is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2 of the License, or
16  * (at your option) any later version.
17  *
18  * Kid3 is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
25  */
26 
27 #include "subframeseditor.h"
28 #include <QVBoxLayout>
29 #include <QHBoxLayout>
30 #include <QPushButton>
31 #include <QInputDialog>
32 #include <QCoreApplication>
33 #include "frametablemodel.h"
34 #include "genremodel.h"
35 #include "frametable.h"
36 #include "framelist.h"
37 #include "taggedfile.h"
38 #include "editframefieldsdialog.h"
39 #include "iplatformtools.h"
40 
41 /**
42  * Constructor.
43  *
44  * @param platformTools platform tools
45  * @param app application context
46  * @param taggedFile tagged file
47  * @param parent parent widget
48  */
SubframesEditor(IPlatformTools * platformTools,Kid3Application * app,const TaggedFile * taggedFile,Frame::TagNumber tagNr,QWidget * parent)49 SubframesEditor::SubframesEditor(IPlatformTools* platformTools,
50                                  Kid3Application* app,
51                                  const TaggedFile* taggedFile,
52                                  Frame::TagNumber tagNr,
53                                  QWidget* parent)
54   : QWidget(parent), m_platformTools(platformTools), m_app(app),
55     m_taggedFile(taggedFile), m_tagNr(tagNr),
56     m_editFrameDialog(nullptr), m_editFrameRow(-1)
57 {
58   setObjectName(QLatin1String("SubframesEditor"));
59   auto layout = new QHBoxLayout(this);
60   m_frameTableModel = new FrameTableModel(
61         false, platformTools->iconProvider(), this);
62   m_frameTable = new FrameTable(m_frameTableModel, new GenreModel(false, this),
63                                 this);
64   layout->addWidget(m_frameTable);
65   auto buttonLayout = new QVBoxLayout;
66   m_editButton = new QPushButton(tr("Edit..."));
67   m_editButton->setDefault(false);
68   m_editButton->setAutoDefault(false);
69   connect(m_editButton, &QAbstractButton::clicked, this, &SubframesEditor::onEditClicked);
70   buttonLayout->addWidget(m_editButton);
71   m_addButton = new QPushButton(tr("Add..."));
72   m_addButton->setDefault(false);
73   m_addButton->setAutoDefault(false);
74   connect(m_addButton, &QAbstractButton::clicked, this, &SubframesEditor::onAddClicked);
75   buttonLayout->addWidget(m_addButton);
76   m_deleteButton = new QPushButton(tr("Delete"));
77   m_deleteButton->setDefault(false);
78   m_deleteButton->setAutoDefault(false);
79   connect(m_deleteButton, &QAbstractButton::clicked, this, &SubframesEditor::onDeleteClicked);
80   buttonLayout->addWidget(m_deleteButton);
81   buttonLayout->addStretch();
82   layout->addLayout(buttonLayout);
83 }
84 
85 /**
86  * Set subframes.
87  * @param frames subframes, will be cleared
88  */
setFrames(FrameCollection & frames)89 void SubframesEditor::setFrames(FrameCollection& frames)
90 {
91   m_frameTableModel->transferFrames(frames);
92 }
93 
94 /**
95  * Get subframes.
96  * @param frames the subframes are returned here
97  */
getFrames(FrameCollection & frames) const98 void SubframesEditor::getFrames(FrameCollection& frames) const
99 {
100   frames = m_frameTableModel->frames();
101   for (auto it = frames.begin(); it != frames.end(); ++it) {
102     auto& frame = const_cast<Frame&>(*it);
103     if (frame.isValueChanged()) {
104       frame.setFieldListFromValue();
105     }
106   }
107 }
108 
109 /**
110  * Called when the Edit button is clicked.
111  */
onEditClicked()112 void SubframesEditor::onEditClicked()
113 {
114   QModelIndex index = m_frameTable->currentIndex();
115   if (const Frame* selectedFrame = m_frameTableModel->getFrameOfIndex(index)) {
116     editFrame(*selectedFrame, index.row());
117   }
118 }
119 
120 /**
121  * Called when the Add button is clicked.
122  */
onAddClicked()123 void SubframesEditor::onAddClicked()
124 {
125   bool ok = false;
126   QStringList frameIds = m_taggedFile->getFrameIds(m_tagNr);
127   QMap<QString, QString> nameMap = Frame::getDisplayNameMap(frameIds);
128   QString displayName = QInputDialog::getItem(
129     this, tr("Add Frame"),
130     tr("Select the frame ID"), nameMap.keys(), 0, true, &ok);
131   if (ok) {
132     QString name = nameMap.value(displayName, displayName);
133     Frame::Type type = Frame::getTypeFromName(name);
134     Frame frame(type, QLatin1String(""), name, -1);
135     m_taggedFile->addFieldList(m_tagNr, frame);
136     editFrame(frame, -1);
137   }
138 }
139 
140 /**
141  * Called when the Delete button is clicked.
142  */
onDeleteClicked()143 void SubframesEditor::onDeleteClicked()
144 {
145   QModelIndex index = m_frameTable->currentIndex();
146   if (index.isValid()) {
147     m_frameTableModel->removeRow(index.row());
148   }
149 }
150 
151 /**
152  * Let user edit a frame and then update the fields
153  * when the edits are accepted.
154  *
155  * @param frame frame to edit
156  * @param row row of edited frame in frame table, -1 if newly added frame
157  */
editFrame(const Frame & frame,int row)158 void SubframesEditor::editFrame(const Frame& frame, int row)
159 {
160   m_editFrame = frame;
161   if (m_editFrame.isValueChanged()) {
162     m_editFrame.setFieldListFromValue();
163   }
164   m_editFrameRow = row;
165   QString name(m_editFrame.getInternalName());
166   if (name.isEmpty()) {
167     name = m_editFrame.getName();
168   }
169   if (!name.isEmpty()) {
170     int nlPos = name.indexOf(QLatin1Char('\n'));
171     if (nlPos > 0) {
172       // probably "TXXX - User defined text information\nDescription" or
173       // "WXXX - User defined URL link\nDescription"
174       name.truncate(nlPos);
175     }
176     name = QCoreApplication::translate("@default", name.toLatin1().data());
177   }
178   if (!m_editFrameDialog) {
179     m_editFrameDialog = new EditFrameFieldsDialog(m_platformTools, m_app, this);
180     connect(m_editFrameDialog, &QDialog::finished,
181             this, &SubframesEditor::onEditFrameDialogFinished);
182   }
183   m_editFrameDialog->setWindowTitle(name);
184   m_editFrameDialog->setFrame(m_editFrame, m_taggedFile, m_tagNr);
185   m_editFrameDialog->show();
186 }
187 
188 /**
189  * Called when the edit frame dialog is finished.
190  * @param result dialog result
191  */
onEditFrameDialogFinished(int result)192 void SubframesEditor::onEditFrameDialogFinished(int result)
193 {
194   if (auto dialog =
195       qobject_cast<EditFrameFieldsDialog*>(sender())) {
196     if (result == QDialog::Accepted) {
197       const Frame::FieldList& fields = dialog->getUpdatedFieldList();
198       if (fields.isEmpty()) {
199         m_editFrame.setValue(dialog->getFrameValue());
200       } else {
201         m_editFrame.setFieldList(fields);
202         m_editFrame.setValueFromFieldList();
203       }
204       if (m_editFrameRow != -1) {
205         m_frameTableModel->removeRow(m_editFrameRow);
206       }
207       m_frameTableModel->insertFrame(m_editFrame);
208     }
209   }
210 }
211