File indexing completed on 2025-02-23 04:34:17

0001 /**
0002  * \file editframefieldsdialog.cpp
0003  * Field edit dialog.
0004  *
0005  * \b Project: Kid3
0006  * \author Urs Fleisch
0007  * \date 10 Jun 2009
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 "editframefieldsdialog.h"
0028 #include <QPushButton>
0029 #include <QImage>
0030 #include <QClipboard>
0031 #include <QTextEdit>
0032 #include <QLineEdit>
0033 #include <QComboBox>
0034 #include <QAction>
0035 #include <QSpinBox>
0036 #include <QApplication>
0037 #include <QFile>
0038 #include <QDir>
0039 #include <QBuffer>
0040 #include <QVBoxLayout>
0041 #include <QMimeData>
0042 #include <QMimeDatabase>
0043 #include <QMimeType>
0044 #include "kid3application.h"
0045 #include "imageviewer.h"
0046 #include "taggedfile.h"
0047 #include "config.h"
0048 #include "fileconfig.h"
0049 #include "iplatformtools.h"
0050 #include "timeeventmodel.h"
0051 #include "timeeventeditor.h"
0052 #include "chaptereditor.h"
0053 #include "tableofcontentseditor.h"
0054 #include "subframeseditor.h"
0055 #include "pictureframe.h"
0056 
0057 /** Base class for field controls */
0058 class FieldControl : public QObject {
0059 public:
0060   /**
0061    * Constructor.
0062    */
0063   FieldControl() {}
0064 
0065   /**
0066    * Destructor.
0067    */
0068   ~FieldControl() override;
0069 
0070   /**
0071    * Update field from data in field control.
0072    */
0073   virtual void updateTag() = 0;
0074 
0075   /**
0076    * Create widget to edit field data.
0077    *
0078    * @param parent parent widget
0079    *
0080    * @return widget to edit field data.
0081    */
0082   virtual QWidget* createWidget(QWidget* parent) = 0;
0083 };
0084 
0085 /**
0086  * Destructor.
0087  */
0088 FieldControl::~FieldControl()
0089 {
0090   // not inline or default to silence weak-vtables warning
0091 }
0092 
0093 
0094 namespace  {
0095 
0096 /** QTextEdit with label above */
0097 class LabeledTextEdit : public QWidget {
0098 public:
0099   /**
0100    * Constructor.
0101    *
0102    * @param parent parent widget
0103    */
0104   explicit LabeledTextEdit(QWidget* parent);
0105 
0106   /**
0107    * Destructor.
0108    */
0109   ~LabeledTextEdit() override = default;
0110 
0111   /**
0112    * Get text.
0113    *
0114    * @return text.
0115    */
0116   QString text() const {
0117     return m_edit->toPlainText();
0118   }
0119 
0120   /**
0121    * Set text.
0122    *
0123    * @param txt text
0124    */
0125   void setText(const QString& txt) {
0126     m_edit->setPlainText(txt);
0127   }
0128 
0129   /**
0130    * Set focus to text field.
0131    */
0132   void setEditFocus() {
0133     m_edit->setFocus();
0134   }
0135 
0136   /**
0137    * Set label.
0138    *
0139    * @param txt label
0140    */
0141   void setLabel(const QString& txt) { m_label->setText(txt); }
0142 
0143 private:
0144   Q_DISABLE_COPY(LabeledTextEdit)
0145 
0146   /** Label above edit */
0147   QLabel* m_label;
0148   /** Text editor */
0149   QTextEdit* m_edit;
0150 };
0151 
0152 /**
0153  * Constructor.
0154  *
0155  * @param parent parent widget
0156  */
0157 LabeledTextEdit::LabeledTextEdit(QWidget* parent)
0158   : QWidget(parent)
0159 {
0160   setObjectName(QLatin1String("LabeledTextEdit"));
0161   auto layout = new QVBoxLayout(this);
0162   m_label = new QLabel(this);
0163   m_edit = new QTextEdit(this);
0164   layout->setContentsMargins(0, 0, 0, 0);
0165   m_edit->setAcceptRichText(false);
0166   layout->addWidget(m_label);
0167   layout->addWidget(m_edit);
0168 }
0169 
0170 
0171 /** LineEdit with label above */
0172 class LabeledLineEdit : public QWidget {
0173 public:
0174   /**
0175    * Constructor.
0176    *
0177    * @param parent parent widget
0178    */
0179   explicit LabeledLineEdit(QWidget* parent);
0180 
0181   /**
0182    * Destructor.
0183    */
0184   ~LabeledLineEdit() override = default;
0185 
0186   /**
0187    * Get text.
0188    *
0189    * @return text.
0190    */
0191   QString text() const { return m_edit->text(); }
0192 
0193   /**
0194    * Set text.
0195    *
0196    * @param txt text
0197    */
0198   void setText(const QString& txt) { m_edit->setText(txt); }
0199 
0200   /**
0201    * Set label.
0202    *
0203    * @param txt label
0204    */
0205   void setLabel(const QString& txt) { m_label->setText(txt); }
0206 
0207 private:
0208   Q_DISABLE_COPY(LabeledLineEdit)
0209 
0210   /** Label above edit */
0211   QLabel* m_label;
0212   /** Line editor */
0213   QLineEdit* m_edit;
0214 };
0215 
0216 /**
0217  * Constructor.
0218  *
0219  * @param parent parent widget
0220  */
0221 LabeledLineEdit::LabeledLineEdit(QWidget* parent)
0222   : QWidget(parent)
0223 {
0224   setObjectName(QLatin1String("LabeledLineEdit"));
0225   auto layout = new QVBoxLayout(this);
0226   m_label = new QLabel(this);
0227   m_edit = new QLineEdit(this);
0228   layout->setContentsMargins(0, 0, 0, 0);
0229   layout->addWidget(m_label);
0230   layout->addWidget(m_edit);
0231 }
0232 
0233 
0234 /** Combo box with label above */
0235 class LabeledComboBox : public QWidget {
0236 public:
0237   /**
0238    * Constructor.
0239    *
0240    * @param parent parent widget
0241    * @param strlst list with ComboBox items, terminated by NULL
0242    */
0243   LabeledComboBox(QWidget* parent, const char* const* strlst);
0244 
0245   /**
0246    * Destructor.
0247    */
0248   ~LabeledComboBox() override = default;
0249 
0250   /**
0251    * Get index of selected item.
0252    *
0253    * @return index.
0254    */
0255   int currentItem() const {
0256     return m_combo->currentIndex();
0257   }
0258 
0259   /**
0260    * Set index of selected item.
0261    *
0262    * @param idx index
0263    */
0264   void setCurrentItem(int idx) {
0265     m_combo->setCurrentIndex(idx);
0266   }
0267 
0268   /**
0269    * Set label.
0270    *
0271    * @param txt label
0272    */
0273   void setLabel(const QString& txt) { m_label->setText(txt); }
0274 
0275 private:
0276   Q_DISABLE_COPY(LabeledComboBox)
0277 
0278   /** Label above combo box */
0279   QLabel* m_label;
0280   /** Combo box */
0281   QComboBox* m_combo;
0282 };
0283 
0284 /**
0285  * Constructor.
0286  *
0287  * @param parent parent widget
0288  * @param strlst list with ComboBox items, terminated by NULL
0289  */
0290 LabeledComboBox::LabeledComboBox(QWidget* parent,
0291          const char* const* strlst) : QWidget(parent)
0292 {
0293   setObjectName(QLatin1String("LabeledComboBox"));
0294   auto layout = new QVBoxLayout(this);
0295   m_label = new QLabel(this);
0296   m_combo = new QComboBox(this);
0297   layout->setContentsMargins(0, 0, 0, 0);
0298   QStringList strList;
0299   while (*strlst) {
0300     strList += QCoreApplication::translate("@default", *strlst++);
0301   }
0302   m_combo->addItems(strList);
0303   layout->addWidget(m_label);
0304   layout->addWidget(m_combo);
0305 }
0306 
0307 
0308 /** QSpinBox with label above */
0309 class LabeledSpinBox : public QWidget {
0310 public:
0311   /**
0312    * Constructor.
0313    *
0314    * @param parent parent widget
0315    */
0316   explicit LabeledSpinBox(QWidget* parent);
0317 
0318   /**
0319    * Destructor.
0320    */
0321   ~LabeledSpinBox() override = default;
0322 
0323   /**
0324    * Get value.
0325    *
0326    * @return text.
0327    */
0328   int value() const { return m_spinbox->value(); }
0329 
0330   /**
0331    * Set value.
0332    *
0333    * @param value value
0334    */
0335   void setValue(int value) { m_spinbox->setValue(value); }
0336 
0337   /**
0338    * Set label.
0339    *
0340    * @param txt label
0341    */
0342   void setLabel(const QString& txt) { m_label->setText(txt); }
0343 
0344 private:
0345   Q_DISABLE_COPY(LabeledSpinBox)
0346 
0347   /** Label above edit */
0348   QLabel* m_label;
0349   /** Text editor */
0350   QSpinBox* m_spinbox;
0351 };
0352 
0353 /**
0354  * Constructor.
0355  *
0356  * @param parent parent widget
0357  */
0358 LabeledSpinBox::LabeledSpinBox(QWidget* parent)
0359   : QWidget(parent)
0360 {
0361   setObjectName(QLatin1String("LabeledSpinBox"));
0362   auto layout = new QVBoxLayout(this);
0363   m_label = new QLabel(this);
0364   m_spinbox = new QSpinBox(this);
0365   if (layout && m_label && m_spinbox) {
0366     m_spinbox->setRange(0, INT_MAX);
0367     layout->setContentsMargins(0, 0, 0, 0);
0368     layout->addWidget(m_label);
0369     layout->addWidget(m_spinbox);
0370   }
0371 }
0372 
0373 
0374 /** Base class for MP3 field controls */
0375 class Mp3FieldControl : public FieldControl {
0376 public:
0377   /**
0378    * Constructor.
0379    * @param field field to edit
0380    */
0381   explicit Mp3FieldControl(Frame::Field& field)
0382     : m_field(field) {}
0383 
0384   /**
0385    * Destructor.
0386    */
0387   ~Mp3FieldControl() override = default;
0388 
0389 protected:
0390   /** field */
0391   Frame::Field& m_field;
0392 
0393 private:
0394   Q_DISABLE_COPY(Mp3FieldControl)
0395 };
0396 
0397 
0398 /** Control to edit standard UTF text fields */
0399 class TextFieldControl : public Mp3FieldControl {
0400 public:
0401   /**
0402    * Constructor.
0403    * @param field field to edit
0404    */
0405   explicit TextFieldControl(Frame::Field& field)
0406     : Mp3FieldControl(field), m_edit(nullptr) {}
0407 
0408   /**
0409    * Destructor.
0410    */
0411   ~TextFieldControl() override = default;
0412 
0413   /**
0414    * Update field from data in field control.
0415    */
0416   void updateTag() override;
0417 
0418   /**
0419    * Create widget to edit field data.
0420    *
0421    * @param parent parent widget
0422    *
0423    * @return widget to edit field data.
0424    */
0425   QWidget* createWidget(QWidget* parent) override;
0426 
0427 protected:
0428   /** Text editor widget */
0429   LabeledTextEdit* m_edit;
0430 
0431 private:
0432   Q_DISABLE_COPY(TextFieldControl)
0433 };
0434 
0435 /**
0436  * Update field with data from dialog.
0437  */
0438 void TextFieldControl::updateTag()
0439 {
0440   m_field.m_value = m_edit->text();
0441 }
0442 
0443 /**
0444  * Create widget for dialog.
0445  *
0446  * @param parent parent widget
0447  * @return widget to edit field.
0448  */
0449 QWidget* TextFieldControl::createWidget(QWidget* parent)
0450 {
0451   m_edit = new LabeledTextEdit(parent);
0452   if (m_edit == nullptr)
0453     return nullptr;
0454 
0455   m_edit->setLabel(Frame::Field::getFieldIdName(
0456                      static_cast<Frame::FieldId>(m_field.m_id)));
0457   m_edit->setText(m_field.m_value.toString());
0458   m_edit->setEditFocus();
0459   return m_edit;
0460 }
0461 
0462 
0463 /** Control to edit single line text fields */
0464 class LineFieldControl : public Mp3FieldControl {
0465 public:
0466   /**
0467    * Constructor.
0468    * @param field field to edit
0469    */
0470   explicit LineFieldControl(Frame::Field& field)
0471     : Mp3FieldControl(field), m_edit(nullptr) {}
0472 
0473   /**
0474    * Destructor.
0475    */
0476   ~LineFieldControl() override = default;
0477 
0478   /**
0479    * Update field from data in field control.
0480    */
0481   void updateTag() override;
0482 
0483   /**
0484    * Create widget to edit field data.
0485    *
0486    * @param parent parent widget
0487    *
0488    * @return widget to edit field data.
0489    */
0490   QWidget* createWidget(QWidget* parent) override;
0491 
0492 protected:
0493   /** Line editor widget */
0494   LabeledLineEdit* m_edit;
0495 
0496 private:
0497   Q_DISABLE_COPY(LineFieldControl)
0498 };
0499 
0500 /**
0501  * Update field with data from dialog.
0502  */
0503 void LineFieldControl::updateTag()
0504 {
0505   m_field.m_value = m_edit->text();
0506 }
0507 
0508 /**
0509  * Create widget for dialog.
0510  *
0511  * @param parent parent widget
0512  * @return widget to edit field.
0513  */
0514 QWidget* LineFieldControl::createWidget(QWidget* parent)
0515 {
0516   m_edit = new LabeledLineEdit(parent);
0517   m_edit->setLabel(Frame::Field::getFieldIdName(
0518                      static_cast<Frame::FieldId>(m_field.m_id)));
0519   m_edit->setText(m_field.m_value.toString());
0520   return m_edit;
0521 }
0522 
0523 
0524 /** Control to edit integer fields */
0525 class IntFieldControl : public Mp3FieldControl {
0526 public:
0527   /**
0528    * Constructor.
0529    * @param field field to edit
0530    */
0531   explicit IntFieldControl(Frame::Field& field)
0532     : Mp3FieldControl(field), m_numInp(nullptr) {}
0533 
0534   /**
0535    * Destructor.
0536    */
0537   ~IntFieldControl() override = default;
0538 
0539   /**
0540    * Update field from data in field control.
0541    */
0542   void updateTag() override;
0543 
0544   /**
0545    * Create widget to edit field data.
0546    *
0547    * @param parent parent widget
0548    *
0549    * @return widget to edit field data.
0550    */
0551   QWidget* createWidget(QWidget* parent) override;
0552 
0553 protected:
0554   /** Spin box widget */
0555   LabeledSpinBox* m_numInp;
0556 
0557 private:
0558   Q_DISABLE_COPY(IntFieldControl)
0559 };
0560 
0561 /**
0562  * Update field with data from dialog.
0563  */
0564 void IntFieldControl::updateTag()
0565 {
0566   m_field.m_value = m_numInp->value();
0567 }
0568 
0569 /**
0570  * Create widget for dialog.
0571  *
0572  * @param parent parent widget
0573  * @return widget to edit field.
0574  */
0575 QWidget* IntFieldControl::createWidget(QWidget* parent)
0576 {
0577   m_numInp = new LabeledSpinBox(parent);
0578   m_numInp->setLabel(Frame::Field::getFieldIdName(
0579                        static_cast<Frame::FieldId>(m_field.m_id)));
0580   m_numInp->setValue(m_field.m_value.toInt());
0581   return m_numInp;
0582 }
0583 
0584 
0585 /** Control to edit integer fields using a combo box with given values */
0586 class IntComboBoxControl : public Mp3FieldControl {
0587 public:
0588   /**
0589    * Constructor.
0590    * @param field field to edit
0591    * @param lst list of strings with possible selections, NULL terminated
0592    */
0593   IntComboBoxControl(Frame::Field& field,
0594                      const char* const* lst)
0595     : Mp3FieldControl(field), m_ptInp(nullptr), m_strLst(lst) {}
0596 
0597   /**
0598    * Destructor.
0599    */
0600   ~IntComboBoxControl() override = default;
0601 
0602   /**
0603    * Update field from data in field control.
0604    */
0605   void updateTag() override;
0606 
0607   /**
0608    * Create widget to edit field data.
0609    *
0610    * @param parent parent widget
0611    *
0612    * @return widget to edit field data.
0613    */
0614   QWidget* createWidget(QWidget* parent) override;
0615 
0616 protected:
0617   /** Combo box widget */
0618   LabeledComboBox* m_ptInp;
0619   /** List of strings with possible selections */
0620   const char* const* m_strLst;
0621 
0622 private:
0623   Q_DISABLE_COPY(IntComboBoxControl)
0624 };
0625 
0626 /**
0627  * Update field with data from dialog.
0628  */
0629 void IntComboBoxControl::updateTag()
0630 {
0631   m_field.m_value = m_ptInp->currentItem();
0632 }
0633 
0634 /**
0635  * Create widget for dialog.
0636  *
0637  * @param parent parent widget
0638  * @return widget to edit field.
0639  */
0640 QWidget* IntComboBoxControl::createWidget(QWidget* parent)
0641 {
0642   m_ptInp = new LabeledComboBox(parent, m_strLst);
0643   m_ptInp->setLabel(Frame::Field::getFieldIdName(
0644                       static_cast<Frame::FieldId>(m_field.m_id)));
0645   m_ptInp->setCurrentItem(m_field.m_value.toInt());
0646   return m_ptInp;
0647 }
0648 
0649 
0650 /** Control to import, export and view data from binary fields */
0651 class BinFieldControl : public Mp3FieldControl {
0652 public:
0653   /**
0654    * Constructor.
0655    * @param platformTools platform tools
0656    * @param app application context
0657    * @param field      field to edit
0658    * @param frame      frame with fields to edit
0659    * @param taggedFile file
0660    * @param tagNr tag number
0661    */
0662   BinFieldControl(IPlatformTools* platformTools, Kid3Application* app,
0663                   Frame::Field& field,
0664                   const Frame& frame, const TaggedFile* taggedFile,
0665                   Frame::TagNumber tagNr)
0666     : Mp3FieldControl(field), m_platformTools(platformTools), m_app(app),
0667       m_bos(nullptr), m_frame(frame), m_taggedFile(taggedFile), m_tagNr(tagNr)
0668   {}
0669 
0670   /**
0671    * Destructor.
0672    */
0673   ~BinFieldControl() override = default;
0674 
0675   /**
0676    * Update field from data in field control.
0677    */
0678   void updateTag() override;
0679 
0680   /**
0681    * Create widget to edit field data.
0682    *
0683    * @param parent parent widget
0684    *
0685    * @return widget to edit field data.
0686    */
0687   QWidget* createWidget(QWidget* parent) override;
0688 
0689 protected:
0690   /** Platform dependent tools */
0691   IPlatformTools* m_platformTools;
0692   /** Application context */
0693   Kid3Application* m_app;
0694   /** Import, Export, View buttons */
0695   BinaryOpenSave* m_bos;
0696   /** frame with fields to edit */
0697   const Frame& m_frame;
0698   /** tagged file */
0699   const TaggedFile* m_taggedFile;
0700   /** number of edited tag */
0701   Frame::TagNumber m_tagNr;
0702 
0703 private:
0704   Q_DISABLE_COPY(BinFieldControl)
0705 };
0706 
0707 /**
0708  * Update field with data from dialog.
0709  */
0710 void BinFieldControl::updateTag()
0711 {
0712   if (m_bos && m_bos->isChanged()) {
0713     m_field.m_value = m_bos->getData();
0714   }
0715 }
0716 
0717 /**
0718  * Create widget for dialog.
0719  *
0720  * @param parent parent widget
0721  * @return widget to edit field.
0722  */
0723 QWidget* BinFieldControl::createWidget(QWidget* parent)
0724 {
0725   m_bos = new BinaryOpenSave(m_platformTools, m_app, parent, m_field,
0726                              m_frame.getType() == Frame::FT_Picture);
0727   m_bos->setLabel(Frame::Field::getFieldIdName(
0728                     static_cast<Frame::FieldId>(m_field.m_id)));
0729   if (m_taggedFile) {
0730     m_bos->setDefaultDir(m_taggedFile->getDirname());
0731   }
0732   if (m_frame.getType() == Frame::FT_Picture) {
0733     QString coverFileName = FileConfig::instance().defaultCoverFileName();
0734     if (coverFileName.contains(QLatin1Char('%'))) {
0735       TrackData trackData(*const_cast<TaggedFile*>(m_taggedFile),
0736                           Frame::tagVersionFromNumber(m_tagNr));
0737       coverFileName = trackData.formatString(coverFileName);
0738     }
0739     m_bos->setDefaultFile(coverFileName);
0740     const char* const imagesStr = QT_TRANSLATE_NOOP("@default", "Images");
0741     const char* const allFilesStr = QT_TRANSLATE_NOOP("@default", "All Files");
0742     m_bos->setFilter(m_platformTools->fileDialogNameFilter(
0743                QList<QPair<QString, QString> >()
0744                << qMakePair(QCoreApplication::translate("@default", imagesStr),
0745                             QString(QLatin1String("*.jpg *.jpeg *.png *.webp")))
0746                << qMakePair(QCoreApplication::translate("@default",
0747                                                         allFilesStr),
0748                             QString(QLatin1Char('*')))));
0749   }
0750   return m_bos;
0751 }
0752 
0753 
0754 /**
0755  * Control to edit time event fields (synchronized lyrics and event timing
0756  * codes).
0757  */
0758 class TimeEventFieldControl : public Mp3FieldControl {
0759 public:
0760   /**
0761    * Constructor.
0762    * @param platformTools platform tools
0763    * @param app application context
0764    * @param field field to edit
0765    * @param fields fields of frame to edit
0766    * @param taggedFile file
0767    * @param tagNr tag number
0768    * @param type SynchronizedLyrics or EventTimingCodes
0769    */
0770   TimeEventFieldControl(IPlatformTools* platformTools,
0771                         Kid3Application* app, Frame::Field& field,
0772                         Frame::FieldList& fields, const TaggedFile* taggedFile,
0773                         Frame::TagNumber tagNr, TimeEventModel::Type type);
0774 
0775   /**
0776    * Destructor.
0777    */
0778   ~TimeEventFieldControl() override = default;
0779 
0780   /**
0781    * Update field from data in field control.
0782    */
0783   void updateTag() override;
0784 
0785   /**
0786    * Create widget to edit field data.
0787    *
0788    * @param parent parent widget
0789    *
0790    * @return widget to edit field data.
0791    */
0792   QWidget* createWidget(QWidget* parent) override;
0793 
0794 protected:
0795   /** Platform dependent tools */
0796   IPlatformTools* m_platformTools;
0797   /** application context */
0798   Kid3Application* m_app;
0799   /** frame with fields to edit */
0800   Frame::FieldList& m_fields;
0801   /** tagged file */
0802   const TaggedFile* m_taggedFile;
0803   /** item model */
0804   TimeEventModel* m_model;
0805   /** editor widget */
0806   TimeEventEditor* m_editor;
0807   /** number of edited tag */
0808   Frame::TagNumber m_tagNr;
0809 
0810 private:
0811   Q_DISABLE_COPY(TimeEventFieldControl)
0812 };
0813 
0814 /**
0815  * Constructor.
0816  * @param platformTools platform tools
0817  * @param app application context
0818  * @param field field to edit
0819  * @param fields fields of frame to edit
0820  * @param taggedFile file
0821  * @param tagNr tag number
0822  * @param type SynchronizedLyrics or EventTimingCodes
0823  */
0824 TimeEventFieldControl::TimeEventFieldControl(
0825     IPlatformTools* platformTools, Kid3Application* app, Frame::Field& field,
0826     Frame::FieldList& fields, const TaggedFile* taggedFile,
0827     Frame::TagNumber tagNr, TimeEventModel::Type type)
0828   : Mp3FieldControl(field), m_platformTools(platformTools), m_app(app),
0829     m_fields(fields), m_taggedFile(taggedFile),
0830     m_model(new TimeEventModel(platformTools->iconProvider(), this)), m_editor(nullptr), m_tagNr(tagNr)
0831 {
0832   m_model->setType(type);
0833   if (type == TimeEventModel::EventTimingCodes) {
0834     m_model->fromEtcoFrame(m_fields);
0835   } else {
0836     m_model->fromSyltFrame(m_fields);
0837   }
0838 }
0839 
0840 /**
0841  * Update field with data from dialog.
0842  */
0843 void TimeEventFieldControl::updateTag()
0844 {
0845   if (m_model->getType() == TimeEventModel::EventTimingCodes) {
0846     m_model->toEtcoFrame(m_fields);
0847   } else {
0848     m_model->toSyltFrame(m_fields);
0849   }
0850 }
0851 
0852 /**
0853  * Create widget for dialog.
0854  *
0855  * @param parent parent widget
0856  * @return widget to edit field.
0857  */
0858 QWidget* TimeEventFieldControl::createWidget(QWidget* parent)
0859 {
0860   m_editor = new TimeEventEditor(m_platformTools, m_app, parent,
0861                                  m_field, m_taggedFile, m_tagNr);
0862   m_editor->setModel(m_model);
0863   return m_editor;
0864 }
0865 
0866 
0867 /** Control to edit a subframe */
0868 class SubframeFieldControl : public Mp3FieldControl {
0869 public:
0870   /**
0871    * Constructor.
0872    */
0873   SubframeFieldControl(IPlatformTools* platformTools,
0874                        Kid3Application* app, const TaggedFile* taggedFile,
0875                        Frame::TagNumber tagNr,
0876                        Frame::FieldList& fields,
0877                        Frame::FieldList::iterator begin,
0878                        Frame::FieldList::iterator end);
0879 
0880   /**
0881    * Destructor.
0882    */
0883   ~SubframeFieldControl() override = default;
0884 
0885   /**
0886    * Update field from data in field control.
0887    */
0888   void updateTag() override;
0889 
0890   /**
0891    * Create widget to edit field data.
0892    *
0893    * @param parent parent widget
0894    *
0895    * @return widget to edit field data.
0896    */
0897   QWidget* createWidget(QWidget* parent) override;
0898 
0899 private:
0900   Q_DISABLE_COPY(SubframeFieldControl)
0901 
0902   IPlatformTools* m_platformTools;
0903   Kid3Application* m_app;
0904   const TaggedFile* m_taggedFile;
0905   Frame::FieldList& m_fields;
0906   Frame::FieldList::iterator m_begin;
0907   Frame::FieldList::iterator m_end;
0908   SubframesEditor* m_editor;
0909   Frame::TagNumber m_tagNr;
0910 };
0911 
0912 /**
0913  * Constructor.
0914  */
0915 SubframeFieldControl::SubframeFieldControl(
0916     IPlatformTools* platformTools, Kid3Application* app,
0917     const TaggedFile* taggedFile, Frame::TagNumber tagNr,
0918     Frame::FieldList& fields,
0919     Frame::FieldList::iterator begin, Frame::FieldList::iterator end) : // clazy:exclude=function-args-by-ref
0920   Mp3FieldControl(*begin), m_platformTools(platformTools), m_app(app),
0921   m_taggedFile(taggedFile), m_fields(fields),
0922   m_begin(begin), m_end(end), m_editor(nullptr), m_tagNr(tagNr)
0923 {
0924 }
0925 
0926 /**
0927  * Update field from data in field control.
0928  */
0929 void SubframeFieldControl::updateTag()
0930 {
0931   if (m_editor) {
0932     FrameCollection frames;
0933     m_editor->getFrames(frames);
0934     m_fields.erase(m_begin, m_end);
0935     Frame::Field field;
0936     field.m_id = Frame::ID_Subframe;
0937     for (auto it = frames.cbegin(); it != frames.cend(); ++it) {
0938       field.m_value = it->getExtendedType().getName();
0939       m_fields.append(field);
0940       m_fields.append(it->getFieldList());
0941     }
0942   }
0943 }
0944 
0945 /**
0946  * Create widget to edit field data.
0947  *
0948  * @param parent parent widget
0949  *
0950  * @return widget to edit field data.
0951  */
0952 QWidget* SubframeFieldControl::createWidget(QWidget* parent) {
0953   m_editor = new SubframesEditor(m_platformTools, m_app, m_taggedFile, m_tagNr,
0954                                  parent);
0955   FrameCollection frames = FrameCollection::fromSubframes(
0956         static_cast<Frame::FieldList::const_iterator>(m_begin),
0957         static_cast<Frame::FieldList::const_iterator>(m_end));
0958   m_editor->setFrames(frames);
0959   return m_editor;
0960 }
0961 
0962 
0963 /** Control to edit a chapter */
0964 class ChapterFieldControl : public Mp3FieldControl {
0965 public:
0966   /**
0967    * Constructor.
0968    * @param field field to edit
0969    */
0970   explicit ChapterFieldControl(Frame::Field& field);
0971 
0972   /**
0973    * Destructor.
0974    */
0975   ~ChapterFieldControl() override = default;
0976 
0977   /**
0978    * Update field from data in field control.
0979    */
0980   void updateTag() override;
0981 
0982   /**
0983    * Create widget to edit field data.
0984    *
0985    * @param parent parent widget
0986    *
0987    * @return widget to edit field data.
0988    */
0989   QWidget* createWidget(QWidget* parent) override;
0990 
0991 private:
0992   Q_DISABLE_COPY(ChapterFieldControl)
0993 
0994   ChapterEditor* m_editor;
0995 };
0996 
0997 /**
0998  * Constructor.
0999  * @param field field to edit
1000  */
1001 ChapterFieldControl::ChapterFieldControl(Frame::Field& field)
1002   : Mp3FieldControl(field), m_editor(nullptr)
1003 {
1004 }
1005 
1006 /**
1007  * Update field from data in field control.
1008  */
1009 void ChapterFieldControl::updateTag()
1010 {
1011   if (m_editor) {
1012     quint32 startTimeMs, endTimeMs, startOffset, endOffset;
1013     m_editor->getValues(startTimeMs, endTimeMs, startOffset, endOffset);
1014     QVariantList lst;
1015     lst << startTimeMs << endTimeMs << startOffset << endOffset;
1016     m_field.m_value = lst;
1017   }
1018 }
1019 
1020 /**
1021  * Create widget to edit field data.
1022  *
1023  * @param parent parent widget
1024  *
1025  * @return widget to edit field data.
1026  */
1027 QWidget* ChapterFieldControl::createWidget(QWidget* parent) {
1028   m_editor = new ChapterEditor(parent);
1029   if (QVariantList lst = m_field.m_value.toList(); lst.size() >= 4) {
1030     m_editor->setValues(lst.at(0).toUInt(), lst.at(1).toUInt(),
1031                         lst.at(2).toUInt(), lst.at(3).toUInt());
1032   }
1033   return m_editor;
1034 }
1035 
1036 
1037 /** Control to edit table of contents. */
1038 class TableOfContentsFieldControl : public Mp3FieldControl {
1039 public:
1040   /**
1041    * Constructor.
1042    * @param field field to edit
1043    */
1044   explicit TableOfContentsFieldControl(Frame::Field& field);
1045 
1046   /**
1047    * Destructor.
1048    */
1049   ~TableOfContentsFieldControl() override = default;
1050 
1051   /**
1052    * Update field from data in field control.
1053    */
1054   void updateTag() override;
1055 
1056   /**
1057    * Create widget to edit field data.
1058    *
1059    * @param parent parent widget
1060    *
1061    * @return widget to edit field data.
1062    */
1063   QWidget* createWidget(QWidget* parent) override;
1064 
1065 private:
1066   Q_DISABLE_COPY(TableOfContentsFieldControl)
1067 
1068   TableOfContentsEditor* m_editor;
1069 };
1070 
1071 /**
1072  * Constructor.
1073  * @param field field to edit
1074  */
1075 TableOfContentsFieldControl::TableOfContentsFieldControl(Frame::Field& field)
1076   : Mp3FieldControl(field), m_editor(nullptr)
1077 {
1078 }
1079 
1080 /**
1081  * Update field from data in field control.
1082  */
1083 void TableOfContentsFieldControl::updateTag()
1084 {
1085   if (m_editor) {
1086     bool isTopLevel, isOrdered;
1087     QStringList elements = m_editor->getValues(isTopLevel, isOrdered);
1088     QVariantList lst;
1089     lst << isTopLevel << isOrdered << elements;
1090     m_field.m_value = lst;
1091   }
1092 }
1093 
1094 /**
1095  * Create widget to edit field data.
1096  *
1097  * @param parent parent widget
1098  *
1099  * @return widget to edit field data.
1100  */
1101 QWidget* TableOfContentsFieldControl::createWidget(QWidget* parent) {
1102   m_editor = new TableOfContentsEditor(parent);
1103   if (QVariantList lst = m_field.m_value.toList(); lst.size() >= 3) {
1104     m_editor->setValues(lst.at(0).toBool(), lst.at(1).toBool(),
1105                         lst.at(2).toStringList());
1106   }
1107   return m_editor;
1108 }
1109 
1110 }
1111 
1112 
1113 /**
1114  * Constructor.
1115  *
1116  * @param platformTools platform tools
1117  * @param app application context
1118  * @param parent parent widget
1119  * @param field  field containing binary data
1120  * @param requiresPicture true if data must be picture
1121  */
1122 BinaryOpenSave::BinaryOpenSave(IPlatformTools* platformTools,
1123                                Kid3Application* app,
1124                                QWidget* parent, const Frame::Field& field,
1125                                bool requiresPicture)
1126   : QWidget(parent),
1127     m_platformTools(platformTools), m_app(app),
1128     m_byteArray(field.m_value.toByteArray()), m_isChanged(false),
1129     m_requiresPicture(requiresPicture)
1130 {
1131   setObjectName(QLatin1String("BinaryOpenSave"));
1132   auto layout = new QHBoxLayout(this);
1133   m_label = new QLabel(this);
1134   m_clipButton = new QPushButton(tr("From Clip&board"), this);
1135   auto toClipboardButton = new QPushButton(tr("&To Clipboard"), this);
1136   auto openButton = new QPushButton(tr("&Import..."), this);
1137   auto saveButton = new QPushButton(tr("&Export..."), this);
1138   auto viewButton = new QPushButton(tr("&View..."), this);
1139   layout->setContentsMargins(0, 0, 0, 0);
1140   layout->addWidget(m_label);
1141   layout->addWidget(m_clipButton);
1142   layout->addWidget(toClipboardButton);
1143   layout->addWidget(openButton);
1144   layout->addWidget(saveButton);
1145   layout->addWidget(viewButton);
1146   connect(m_clipButton, &QAbstractButton::clicked,
1147           this, &BinaryOpenSave::clipData);
1148   connect(toClipboardButton, &QAbstractButton::clicked,
1149           this, &BinaryOpenSave::copyData);
1150   connect(openButton, &QAbstractButton::clicked,
1151           this, &BinaryOpenSave::loadData);
1152   connect(saveButton, &QAbstractButton::clicked,
1153           this, &BinaryOpenSave::saveData);
1154   connect(viewButton, &QAbstractButton::clicked,
1155           this, &BinaryOpenSave::viewData);
1156   connect(QApplication::clipboard(), &QClipboard::dataChanged,
1157           this, &BinaryOpenSave::setClipButtonState);
1158   setClipButtonState();
1159 }
1160 
1161 /**
1162  * Enable the "From Clipboard" button if the clipboard contains an image.
1163  */
1164 void BinaryOpenSave::setClipButtonState()
1165 {
1166   QClipboard* cb = QApplication::clipboard();
1167   m_clipButton->setEnabled(
1168     cb && (!m_requiresPicture ||
1169            cb->mimeData()->hasFormat(QLatin1String("image/jpeg")) ||
1170            cb->mimeData()->hasImage()));
1171 }
1172 
1173 /**
1174  * Load image from clipboard.
1175  */
1176 void BinaryOpenSave::clipData()
1177 {
1178   if (QClipboard* cb = QApplication::clipboard()) {
1179     if (cb->mimeData()->hasFormat(QLatin1String("image/jpeg"))) {
1180       m_byteArray = cb->mimeData()->data(QLatin1String("image/jpeg"));
1181       m_isChanged = true;
1182     } else if (cb->mimeData()->hasImage()) {
1183       QBuffer buffer(&m_byteArray);
1184       buffer.open(QIODevice::WriteOnly);
1185       cb->image().save(&buffer, "JPG");
1186       m_isChanged = true;
1187     } else if (!m_requiresPicture && cb->mimeData()->hasText()) {
1188       m_byteArray = cb->mimeData()->text().toUtf8();
1189       m_isChanged = true;
1190     }
1191   }
1192 }
1193 
1194 /**
1195  * Request name of file to import binary data from.
1196  * The data is imported later when Ok is pressed in the parent dialog.
1197  */
1198 void BinaryOpenSave::loadData()
1199 {
1200   if (QString loadfilename = m_platformTools->getOpenFileName(
1201         this, QString(),
1202         m_defaultDir.isEmpty() ? m_app->getDirName() : m_defaultDir,
1203         m_filter, nullptr);
1204       !loadfilename.isEmpty()) {
1205     QFile file(loadfilename);
1206     if (file.open(QIODevice::ReadOnly)) {
1207       auto size = file.size();
1208       auto data = new char[size];
1209       QDataStream stream(&file);
1210       stream.readRawData(data, static_cast<int>(size));
1211       m_byteArray = QByteArray(data, static_cast<int>(size));
1212       m_isChanged = true;
1213       delete [] data;
1214       file.close();
1215     }
1216   }
1217 }
1218 
1219 /**
1220  * Request name of file and export binary data.
1221  */
1222 void BinaryOpenSave::saveData()
1223 {
1224   QString dir = m_defaultDir.isEmpty() ? m_app->getDirName() : m_defaultDir;
1225   QString fileName(m_defaultFile);
1226   if (fileName.isEmpty()) {
1227     fileName = QLatin1String("untitled");
1228   }
1229   if (QChar separator = QDir::separator(); !dir.endsWith(separator)) {
1230     dir += separator;
1231   }
1232   QFileInfo fileInfo(fileName);
1233   dir += fileInfo.completeBaseName();
1234   QMimeDatabase mimeDb;
1235   QString suffix = mimeDb.mimeTypeForData(m_byteArray).preferredSuffix();
1236   if (suffix == QLatin1String("jpeg")) {
1237     suffix = QLatin1String("jpg");
1238   }
1239   if (!suffix.isEmpty()) {
1240     dir += QLatin1Char('.');
1241     dir += suffix;
1242   }
1243   if (QString fn = m_platformTools->getSaveFileName(
1244         this, QString(), dir, m_filter, nullptr);
1245       !fn.isEmpty()) {
1246     QFile file(fn);
1247     if (file.open(QIODevice::WriteOnly)) {
1248       QDataStream stream(&file);
1249       stream.writeRawData(m_byteArray.constData(), m_byteArray.size());
1250       file.close();
1251     }
1252   }
1253 }
1254 
1255 /**
1256  * Create image from binary data and copy it to clipboard.
1257  */
1258 void BinaryOpenSave::copyData()
1259 {
1260   if (QClipboard* cb = QApplication::clipboard()) {
1261     if (QImage image; image.loadFromData(m_byteArray)) {
1262       cb->setImage(image, QClipboard::Clipboard);
1263     } else {
1264       QMimeDatabase mimeDb;
1265       if (QString mimeType = mimeDb.mimeTypeForData(m_byteArray).name();
1266           !mimeType.isEmpty()) {
1267         auto mimeData = new QMimeData;
1268         mimeData->setData(mimeType, m_byteArray);
1269         cb->setMimeData(mimeData);
1270       }
1271     }
1272   }
1273 }
1274 
1275 /**
1276  * Create image from binary data and display it in window.
1277  */
1278 void BinaryOpenSave::viewData()
1279 {
1280   if (QImage image; image.loadFromData(m_byteArray)) {
1281     ImageViewer iv(this, image);
1282     iv.exec();
1283   }
1284 }
1285 
1286 
1287 /**
1288  * Constructor.
1289  *
1290  * @param platformTools platform tools
1291  * @param app application context
1292  * @param parent     parent widget
1293  */
1294 EditFrameFieldsDialog::EditFrameFieldsDialog(IPlatformTools* platformTools,
1295                                              Kid3Application* app,
1296                                              QWidget* parent)
1297   : QDialog(parent), m_platformTools(platformTools), m_app(app)
1298 {
1299   setObjectName(QLatin1String("EditFrameFieldsDialog"));
1300 
1301 #ifdef Q_OS_MAC
1302   // Make sure that window stays on top, is necessary to keep the dialog
1303   // visible on Mac OS X while operating with the player for SYLT/ETCO frames.
1304   setWindowFlags(windowFlags() | Qt::Tool);
1305 #endif
1306 
1307   m_vlayout = new QVBoxLayout(this);
1308 
1309   auto hlayout = new QHBoxLayout;
1310   auto okButton = new QPushButton(tr("&OK"));
1311   auto cancelButton = new QPushButton(tr("&Cancel"));
1312   hlayout->addStretch();
1313   hlayout->addWidget(okButton);
1314   hlayout->addWidget(cancelButton);
1315   cancelButton->setAutoDefault(false);
1316   connect(okButton, &QAbstractButton::clicked, this, &QDialog::accept);
1317   connect(cancelButton, &QAbstractButton::clicked, this, &QDialog::reject);
1318   m_vlayout->addLayout(hlayout);
1319   setMinimumWidth(525);
1320   // Ctrl-Enter to OK
1321   auto action = new QAction(okButton);
1322   action->setAutoRepeat(false);
1323   action->setShortcut(Qt::CTRL | Qt::Key_Return);
1324   connect(action, &QAction::triggered, okButton, &QPushButton::click);
1325   okButton->addAction(action);
1326 }
1327 
1328 /**
1329  * Destructor.
1330  */
1331 EditFrameFieldsDialog::~EditFrameFieldsDialog()
1332 {
1333   qDeleteAll(m_fieldcontrols);
1334   m_fieldcontrols.clear();
1335 }
1336 
1337 /**
1338  * Set frame to edit.
1339  *
1340  * @param frame      frame with fields to edit
1341  * @param taggedFile file
1342  * @param tagNr      tag number
1343  */
1344 void EditFrameFieldsDialog::setFrame(const Frame& frame,
1345                                      const TaggedFile* taggedFile,
1346                                      Frame::TagNumber tagNr)
1347 {
1348   m_fields = frame.getFieldList();
1349 
1350   // Remove all items, keep the last item.
1351   for (int i = m_vlayout->count() - 2; i >= 0; --i) {
1352     if (QLayoutItem* item = m_vlayout->takeAt(i)) {
1353       delete item->widget();
1354       delete item;
1355     }
1356   }
1357 
1358   qDeleteAll(m_fieldcontrols);
1359   m_fieldcontrols.clear();
1360   bool subframeMissing = false;
1361 
1362   for (auto fldIt = m_fields.begin(); fldIt != m_fields.end(); ++fldIt) { // clazy:exclude=detaching-member
1363     Frame::Field& fld = *fldIt;
1364     if (fld.m_id == Frame::ID_ImageProperties)
1365       continue;
1366 
1367     if (fld.m_id == Frame::ID_Subframe) {
1368       auto subframeCtl =
1369           new SubframeFieldControl(m_platformTools, m_app, taggedFile, tagNr,
1370             m_fields, fldIt, m_fields.end()); // clazy:exclude=detaching-member
1371       m_fieldcontrols.append(subframeCtl);
1372       subframeMissing = false;
1373       break;
1374     }
1375 
1376 #if QT_VERSION >= 0x060000
1377     switch (fld.m_value.typeId()) {
1378       case QMetaType::Int:
1379       case QMetaType::UInt:
1380 #else
1381     switch (fld.m_value.type()) {
1382       case QVariant::Int:
1383       case QVariant::UInt:
1384 #endif
1385         if (fld.m_id == Frame::ID_TextEnc) {
1386           auto cbox = new IntComboBoxControl(
1387                 fld, Frame::Field::getTextEncodingNames());
1388           m_fieldcontrols.append(cbox);
1389         }
1390         else if (fld.m_id == Frame::ID_PictureType) {
1391           auto cbox = new IntComboBoxControl(
1392                 fld, PictureFrame::getPictureTypeNames());
1393           m_fieldcontrols.append(cbox);
1394         }
1395         else if (fld.m_id == Frame::ID_TimestampFormat) {
1396           auto cbox = new IntComboBoxControl(
1397                 fld, Frame::Field::getTimestampFormatNames());
1398           m_fieldcontrols.append(cbox);
1399         }
1400         else if (fld.m_id == Frame::ID_ContentType) {
1401           auto cbox = new IntComboBoxControl(
1402                 fld, Frame::Field::getContentTypeNames());
1403           m_fieldcontrols.append(cbox);
1404         }
1405         else {
1406           auto intctl = new IntFieldControl(fld);
1407           m_fieldcontrols.append(intctl);
1408         }
1409         break;
1410 
1411 #if QT_VERSION >= 0x060000
1412       case QMetaType::QString:
1413 #else
1414       case QVariant::String:
1415 #endif
1416         if (fld.m_id == Frame::ID_Text) {
1417           // Large textedit for text fields
1418           auto textctl = new TextFieldControl(fld);
1419           m_fieldcontrols.append(textctl);
1420         }
1421         else {
1422           auto textctl = new LineFieldControl(fld);
1423           m_fieldcontrols.append(textctl);
1424         }
1425         break;
1426 
1427 #if QT_VERSION >= 0x060000
1428       case QMetaType::QByteArray:
1429 #else
1430       case QVariant::ByteArray:
1431 #endif
1432       {
1433         auto binctl = new BinFieldControl(
1434               m_platformTools, m_app, fld, frame, taggedFile, tagNr);
1435         m_fieldcontrols.append(binctl);
1436         break;
1437       }
1438 
1439 #if QT_VERSION >= 0x060000
1440       case QMetaType::QVariantList:
1441 #else
1442       case QVariant::List:
1443 #endif
1444       {
1445         if (QString frameName = frame.getName();
1446             frameName.startsWith(QLatin1String("SYLT")) ||
1447             frameName == QLatin1String("Chapters")) {
1448           auto timeEventCtl = new TimeEventFieldControl(
1449                 m_platformTools, m_app, fld, m_fields, taggedFile, tagNr,
1450                 TimeEventModel::SynchronizedLyrics);
1451           m_fieldcontrols.append(timeEventCtl);
1452         } else if (frameName.startsWith(QLatin1String("ETCO"))) {
1453           auto timeEventCtl = new TimeEventFieldControl(
1454                 m_platformTools, m_app, fld, m_fields, taggedFile, tagNr,
1455                 TimeEventModel::EventTimingCodes);
1456           m_fieldcontrols.append(timeEventCtl);
1457         } else if (frameName.startsWith(QLatin1String("CHAP"))) {
1458           auto chapCtl = new ChapterFieldControl(fld);
1459           m_fieldcontrols.append(chapCtl);
1460           subframeMissing = true;
1461         } else if (frameName.startsWith(QLatin1String("CTOC"))) {
1462           auto tocCtl =
1463               new TableOfContentsFieldControl(fld);
1464           m_fieldcontrols.append(tocCtl);
1465           subframeMissing = true;
1466         } else {
1467           qDebug("Unexpected QVariantList in field %d", fld.m_id);
1468         }
1469         break;
1470       }
1471 
1472       default:
1473 #if QT_VERSION >= 0x060000
1474         qDebug("Unknown type %d in field %d", fld.m_value.typeId(), fld.m_id);
1475 #else
1476         qDebug("Unknown type %d in field %d", fld.m_value.type(), fld.m_id);
1477 #endif
1478     }
1479   }
1480 
1481   if (subframeMissing) {
1482     // Add an empty subframe so that subframes can be added
1483     auto subframeCtl =
1484         new SubframeFieldControl(m_platformTools, m_app, taggedFile, tagNr,
1485           m_fields, m_fields.end(), m_fields.end()); // clazy:exclude=detaching-member
1486     m_fieldcontrols.append(subframeCtl);
1487   }
1488 
1489   // Handle case for frames without fields, just a value.
1490   m_valueField.m_id = Frame::ID_Text;
1491   if (m_fields.isEmpty()) {
1492     m_valueField.m_value = frame.getValue();
1493     m_fieldcontrols.append(new TextFieldControl(m_valueField));
1494   } else {
1495     m_valueField.m_value = QString();
1496   }
1497 
1498   QListIterator it(m_fieldcontrols);
1499   it.toBack();
1500   while (it.hasPrevious()) {
1501     m_vlayout->insertWidget(0, it.previous()->createWidget(this));
1502   }
1503 }
1504 
1505 /**
1506  * Update fields and get edited fields.
1507  *
1508  * @return field list.
1509  */
1510 const Frame::FieldList& EditFrameFieldsDialog::getUpdatedFieldList()
1511 {
1512   QListIterator it(m_fieldcontrols);
1513   while (it.hasNext()) {
1514     it.next()->updateTag();
1515   }
1516   return m_fields;
1517 }
1518 
1519 /**
1520  * Get value of frame for frames without a field list.
1521  * First getUpdatedFieldList() has to be called, if the returned field list
1522  * is empty, the frame value is available with this method.
1523  *
1524  * @return frame value.
1525  */
1526 QString EditFrameFieldsDialog::getFrameValue() const
1527 {
1528   return m_valueField.m_value.toString();
1529 }