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 }