127
/** List box to select frame */
128
Q3ListBox* FrameList::s_listbox = 0;
133
FrameList::FrameList() : m_file(0) {}
355
/** Field edit dialog */
356
class EditFrameDialog : public QDialog {
361
* @param parent parent widget
362
* @param caption window title
363
* @param text text to edit
365
EditFrameDialog(QWidget* parent, const QString& caption,
366
const QString& text);
371
virtual ~EditFrameDialog();
377
void setText(const QString& text) {
378
m_edit->QCM_setPlainText(text);
385
QString getText() const { return m_edit->QCM_toPlainText(); }
389
QPushButton* m_okButton;
390
QPushButton* m_cancelButton;
396
* @param parent parent widget
397
* @param caption window title
398
* @param text text to edit
400
EditFrameDialog::EditFrameDialog(QWidget* parent, const QString& caption,
401
const QString& text) :
405
QCM_setWindowTitle(caption);
406
QVBoxLayout* vlayout = new QVBoxLayout(this);
408
vlayout->setSpacing(6);
409
vlayout->setMargin(6);
410
m_edit = new QTextEdit(this);
412
m_edit->QCM_setPlainText(text);
413
#if QT_VERSION >= 0x040200
414
m_edit->moveCursor(QTextCursor::End);
415
#elif QT_VERSION >= 0x040000
416
QTextCursor cursor = m_edit->textCursor();
417
cursor.movePosition(QTextCursor::End);
418
m_edit->setTextCursor(cursor);
420
m_edit->moveCursor(QTextEdit::MoveEnd, false);
422
vlayout->addWidget(m_edit);
425
QHBoxLayout* hlayout = new QHBoxLayout;
426
QSpacerItem* hspacer = new QSpacerItem(16, 0, QSizePolicy::Expanding,
427
QSizePolicy::Minimum);
428
m_okButton = new QPushButton(i18n("&OK"), this);
429
m_cancelButton = new QPushButton(i18n("&Cancel"), this);
430
if (hlayout && m_okButton && m_cancelButton) {
431
hlayout->addItem(hspacer);
432
hlayout->addWidget(m_okButton);
433
hlayout->addWidget(m_cancelButton);
434
m_okButton->setDefault(true);
435
connect(m_okButton, SIGNAL(clicked()), this, SLOT(accept()));
436
connect(m_cancelButton, SIGNAL(clicked()), this, SLOT(reject()));
437
vlayout->addLayout(hlayout);
439
#if QT_VERSION >= 0x040000
440
setMinimumWidth(400);
449
EditFrameDialog::~EditFrameDialog() {
453
/** Base class for field controls */
454
class FieldControl : public QObject {
464
virtual ~FieldControl() {}
467
* Update field from data in field control.
469
virtual void updateTag() = 0;
472
* Create widget to edit field data.
474
* @param parent parent widget
476
* @return widget to edit field data.
478
virtual QWidget* createWidget(QWidget* parent) = 0;
481
/** List of field control pointers. */
482
#if QT_VERSION >= 0x040000
483
typedef QList<FieldControl*> FieldControlList;
485
typedef QPtrList<FieldControl> FieldControlList;
489
/** Base class for MP3 field controls */
490
class Mp3FieldControl : public FieldControl {
494
* @param field field to edit
496
Mp3FieldControl(Frame::Field& field) :
502
virtual ~Mp3FieldControl() {}
506
* Get description for ID3_Field.
508
* @param id ID of field
509
* @return description or NULL if id unknown.
511
const char* getFieldIDString(Frame::Field::Id id) const;
514
Frame::Field& m_field;
517
/** Control to edit standard UTF text fields */
518
class TextFieldControl : public Mp3FieldControl {
522
* @param field field to edit
524
TextFieldControl(Frame::Field& field) :
525
Mp3FieldControl(field) {}
530
virtual ~TextFieldControl() {}
533
* Update field from data in field control.
535
virtual void updateTag();
538
* Create widget to edit field data.
540
* @param parent parent widget
542
* @return widget to edit field data.
544
virtual QWidget* createWidget(QWidget* parent);
547
/** Text editor widget */
548
LabeledTextEdit* m_edit;
551
/** Control to edit single line text fields */
552
class LineFieldControl : public Mp3FieldControl {
556
* @param field field to edit
558
LineFieldControl(Frame::Field& field) :
559
Mp3FieldControl(field) {}
564
virtual ~LineFieldControl() {}
567
* Update field from data in field control.
569
virtual void updateTag();
572
* Create widget to edit field data.
574
* @param parent parent widget
576
* @return widget to edit field data.
578
virtual QWidget* createWidget(QWidget* parent);
581
/** Line editor widget */
582
LabeledLineEdit* m_edit;
585
/** Control to edit integer fields */
586
class IntFieldControl : public Mp3FieldControl {
590
* @param field field to edit
592
IntFieldControl(Frame::Field& field) :
593
Mp3FieldControl(field) {}
598
virtual ~IntFieldControl() {}
601
* Update field from data in field control.
603
virtual void updateTag();
606
* Create widget to edit field data.
608
* @param parent parent widget
610
* @return widget to edit field data.
612
virtual QWidget* createWidget(QWidget* parent);
615
/** Spin box widget */
616
LabeledSpinBox* m_numInp;
619
/** Control to edit integer fields using a combo box with given values */
620
class IntComboBoxControl : public Mp3FieldControl {
624
* @param field field to edit
625
* @param lst list of strings with possible selections, NULL terminated
627
IntComboBoxControl(Frame::Field& field,
629
Mp3FieldControl(field), m_strLst(lst) {}
634
virtual ~IntComboBoxControl() {}
637
* Update field from data in field control.
639
virtual void updateTag();
642
* Create widget to edit field data.
644
* @param parent parent widget
646
* @return widget to edit field data.
648
virtual QWidget* createWidget(QWidget* parent);
651
/** Combo box widget */
652
LabeledComboBox* m_ptInp;
653
/** List of strings with possible selections */
654
const char** m_strLst;
657
/** Control to import, export and view data from binary fields */
658
class BinFieldControl : public Mp3FieldControl {
662
* @param field field to edit
664
BinFieldControl(Frame::Field& field) :
665
Mp3FieldControl(field) {}
670
virtual ~BinFieldControl() {}
673
* Update field from data in field control.
675
virtual void updateTag();
678
* Create widget to edit field data.
680
* @param parent parent widget
682
* @return widget to edit field data.
684
virtual QWidget* createWidget(QWidget* parent);
687
/** Import, Export, View buttons */
688
BinaryOpenSave* m_bos;
695
* @param parent parent widget
696
* @param field field containing binary data
698
BinaryOpenSave::BinaryOpenSave(QWidget* parent, const Frame::Field& field) :
699
QWidget(parent), m_byteArray(field.m_value.toByteArray()),
702
QHBoxLayout* layout = new QHBoxLayout(this);
703
m_label = new QLabel(this);
704
QPushButton* openButton = new QPushButton(i18n("&Import"), this);
705
QPushButton* saveButton = new QPushButton(i18n("&Export"), this);
706
QPushButton* viewButton = new QPushButton(i18n("&View"), this);
707
if (layout && m_label && openButton && saveButton && viewButton) {
708
layout->setMargin(0);
709
layout->setSpacing(6);
710
layout->addWidget(m_label);
711
layout->addWidget(openButton);
712
layout->addWidget(saveButton);
713
layout->addWidget(viewButton);
714
connect(openButton, SIGNAL(clicked()), this, SLOT(loadData()));
715
connect(saveButton, SIGNAL(clicked()), this, SLOT(saveData()));
716
connect(viewButton, SIGNAL(clicked()), this, SLOT(viewData()));
721
* Request name of file to import binary data from.
722
* The data is imported later when Ok is pressed in the parent dialog.
724
void BinaryOpenSave::loadData()
726
#ifdef CONFIG_USE_KDE
727
QString loadfilename = KFileDialog::getOpenFileName(
728
Kid3App::getDirName(), QString::null, this);
730
QString loadfilename = QFileDialog::QCM_getOpenFileName(this, Kid3App::getDirName());
732
if (!loadfilename.isEmpty()) {
733
QFile file(loadfilename);
734
if (file.open(QCM_ReadOnly)) {
735
size_t size = file.size();
736
char* data = new char[size];
738
QDataStream stream(&file);
739
stream.QCM_readRawData(data, size);
740
QCM_duplicate(m_byteArray, data, size);
750
* Request name of file and export binary data.
752
void BinaryOpenSave::saveData()
754
#ifdef CONFIG_USE_KDE
755
QString fn = KFileDialog::getSaveFileName(Kid3App::getDirName(), QString::null,
758
QString fn = QFileDialog::QCM_getSaveFileName(this, Kid3App::getDirName());
762
if (file.open(QCM_WriteOnly)) {
763
QDataStream stream(&file);
764
stream.QCM_writeRawData(m_byteArray.data(), m_byteArray.size());
771
* Create image from binary data and display it in window.
773
void BinaryOpenSave::viewData()
776
if (image.loadFromData(m_byteArray)) {
777
ImageViewer iv(this, &image);
783
* Get description for ID3_Field.
785
* @param id ID of field
786
* @return description or NULL if id unknown.
788
const char* Mp3FieldControl::getFieldIDString(Frame::Field::Id id) const
790
static const char* const idStr[] = {
792
I18N_NOOP("Text Encoding"),
796
I18N_NOOP("Description"),
800
I18N_NOOP("Filename"),
801
I18N_NOOP("Language"),
802
I18N_NOOP("Picture Type"),
803
I18N_NOOP("Image format"),
804
I18N_NOOP("Mimetype"),
805
I18N_NOOP("Counter"),
806
I18N_NOOP("Identifier"),
807
I18N_NOOP("Volume Adjustment"),
808
I18N_NOOP("Number of Bits"),
809
I18N_NOOP("Volume Change Right"),
810
I18N_NOOP("Volume Change Left"),
811
I18N_NOOP("Peak Volume Right"),
812
I18N_NOOP("Peak Volume Left"),
813
I18N_NOOP("Timestamp Format"),
814
I18N_NOOP("Content Type")
816
class not_used { int array_size_check[
817
sizeof(idStr) / sizeof(idStr[0]) == Frame::Field::ID_ContentType + 1
819
return idStr[id <= Frame::Field::ID_ContentType ? id : 0];
823
* Update field with data from dialog.
825
void TextFieldControl::updateTag()
827
m_field.m_value = m_edit->text();
831
* Create widget for dialog.
833
* @param parent parent widget
834
* @return widget to edit field.
836
QWidget* TextFieldControl::createWidget(QWidget* parent)
838
m_edit = new LabeledTextEdit(parent);
842
m_edit->setLabel(QCM_translate(getFieldIDString(static_cast<Frame::Field::Id>(m_field.m_id))));
843
m_edit->setText(m_field.m_value.toString());
848
* Update field with data from dialog.
850
void LineFieldControl::updateTag()
852
m_field.m_value = m_edit->text();
856
* Create widget for dialog.
858
* @param parent parent widget
859
* @return widget to edit field.
861
QWidget* LineFieldControl::createWidget(QWidget* parent)
863
m_edit = new LabeledLineEdit(parent);
865
m_edit->setLabel(QCM_translate(getFieldIDString(static_cast<Frame::Field::Id>(m_field.m_id))));
866
m_edit->setText(m_field.m_value.toString());
872
* Update field with data from dialog.
874
void IntFieldControl::updateTag()
876
m_field.m_value = m_numInp->value();
880
* Create widget for dialog.
882
* @param parent parent widget
883
* @return widget to edit field.
885
QWidget* IntFieldControl::createWidget(QWidget* parent)
887
m_numInp = new LabeledSpinBox(parent);
889
m_numInp->setLabel(QCM_translate(getFieldIDString(static_cast<Frame::Field::Id>(m_field.m_id))));
890
m_numInp->setValue(m_field.m_value.toInt());
896
* Update field with data from dialog.
898
void IntComboBoxControl::updateTag()
900
m_field.m_value = m_ptInp->currentItem();
904
* Create widget for dialog.
906
* @param parent parent widget
907
* @return widget to edit field.
909
QWidget* IntComboBoxControl::createWidget(QWidget* parent)
911
m_ptInp = new LabeledComboBox(parent, m_strLst);
913
m_ptInp->setLabel(QCM_translate(getFieldIDString(static_cast<Frame::Field::Id>(m_field.m_id))));
914
m_ptInp->setCurrentItem(m_field.m_value.toInt());
920
* Update field with data from dialog.
922
void BinFieldControl::updateTag()
924
if (m_bos && m_bos->isChanged()) {
925
m_field.m_value = m_bos->getData();
930
* Create widget for dialog.
932
* @param parent parent widget
933
* @return widget to edit field.
935
QWidget* BinFieldControl::createWidget(QWidget* parent)
937
m_bos = new BinaryOpenSave(parent, m_field);
939
m_bos->setLabel(QCM_translate(getFieldIDString(static_cast<Frame::Field::Id>(m_field.m_id))));
945
/** Field edit dialog */
946
class EditFrameFieldsDialog : public QDialog {
951
* @param parent parent widget
952
* @param caption caption
953
* @param fields fields to edit
955
EditFrameFieldsDialog(QWidget* parent, const QString& caption,
956
const Frame::FieldList& fields);
961
virtual ~EditFrameFieldsDialog();
964
* Update fields and get edited fields.
966
* @return field list.
968
const Frame::FieldList& getUpdatedFieldList();
971
Frame::FieldList m_fields;
972
FieldControlList m_fieldcontrols;
978
* @param parent parent widget
979
* @param caption caption
980
* @param fields fields to edit
982
EditFrameFieldsDialog::EditFrameFieldsDialog(QWidget* parent, const QString& caption,
983
const Frame::FieldList& fields) :
984
QDialog(parent), m_fields(fields)
987
QCM_setWindowTitle(caption);
988
#if QT_VERSION >= 0x040000
989
qDeleteAll(m_fieldcontrols);
991
m_fieldcontrols.setAutoDelete(true);
993
m_fieldcontrols.clear();
994
QVBoxLayout* vlayout = new QVBoxLayout(this);
996
vlayout->setSpacing(6);
997
vlayout->setMargin(6);
999
for (Frame::FieldList::iterator fldIt = m_fields.begin();
1000
fldIt != m_fields.end();
1002
Frame::Field& fld = *fldIt;
1003
switch (fld.m_value.type()) {
1005
case QVariant::UInt:
1006
if (fld.m_id == Frame::Field::ID_TextEnc) {
1007
static const char* strlst[] = {
1008
I18N_NOOP("ISO-8859-1"),
1010
I18N_NOOP("UTF16BE"),
1014
IntComboBoxControl* cbox =
1015
new IntComboBoxControl(fld, strlst);
1017
m_fieldcontrols.append(cbox);
1020
else if (fld.m_id == Frame::Field::ID_PictureType) {
1021
static const char* strlst[] = {
1023
I18N_NOOP("32x32 pixels PNG file icon"),
1024
I18N_NOOP("Other file icon"),
1025
I18N_NOOP("Cover (front)"),
1026
I18N_NOOP("Cover (back)"),
1027
I18N_NOOP("Leaflet page"),
1029
I18N_NOOP("Lead artist/lead performer/soloist"),
1030
I18N_NOOP("Artist/performer"),
1031
I18N_NOOP("Conductor"),
1032
I18N_NOOP("Band/Orchestra"),
1033
I18N_NOOP("Composer"),
1034
I18N_NOOP("Lyricist/text writer"),
1035
I18N_NOOP("Recording Location"),
1036
I18N_NOOP("During recording"),
1037
I18N_NOOP("During performance"),
1038
I18N_NOOP("Movie/video screen capture"),
1039
I18N_NOOP("A bright coloured fish"),
1040
I18N_NOOP("Illustration"),
1041
I18N_NOOP("Band/artist logotype"),
1042
I18N_NOOP("Publisher/Studio logotype"),
1045
IntComboBoxControl* cbox =
1046
new IntComboBoxControl(fld, strlst);
1048
m_fieldcontrols.append(cbox);
1051
else if (fld.m_id == Frame::Field::ID_TimestampFormat) {
1052
static const char* strlst[] = {
1054
I18N_NOOP("MPEG frames as unit"),
1055
I18N_NOOP("Milliseconds as unit"),
1058
IntComboBoxControl* cbox =
1059
new IntComboBoxControl(fld, strlst);
1061
m_fieldcontrols.append(cbox);
1064
else if (fld.m_id == Frame::Field::ID_ContentType) {
1065
static const char* strlst[] = {
1067
I18N_NOOP("Lyrics"),
1068
I18N_NOOP("Text transcription"),
1069
I18N_NOOP("Movement/part name"),
1070
I18N_NOOP("Events"),
1072
I18N_NOOP("Trivia/pop up"),
1075
IntComboBoxControl* cbox =
1076
new IntComboBoxControl(fld, strlst);
1078
m_fieldcontrols.append(cbox);
1082
IntFieldControl* intctl =
1083
new IntFieldControl(fld);
1085
m_fieldcontrols.append(intctl);
1090
case QVariant::String:
1091
if (fld.m_id == Frame::Field::ID_Text) {
1092
// Large textedit for text fields
1093
TextFieldControl* textctl =
1094
new TextFieldControl(fld);
1096
m_fieldcontrols.append(textctl);
1100
LineFieldControl* textctl =
1101
new LineFieldControl(fld);
1103
m_fieldcontrols.append(textctl);
1108
case QVariant::ByteArray:
1110
BinFieldControl* binctl =
1111
new BinFieldControl(fld);
1113
m_fieldcontrols.append(binctl);
1119
qDebug("Unknown type %d in field %d", fld.m_value.type(), fld.m_id);
1123
#if QT_VERSION >= 0x040000
1124
QListIterator<FieldControl*> it(m_fieldcontrols);
1125
while (it.hasNext()) {
1126
vlayout->addWidget(it.next()->createWidget(this));
1129
FieldControl* fldCtl = m_fieldcontrols.first();
1130
while (fldCtl != NULL) {
1131
vlayout->addWidget(fldCtl->createWidget(this));
1132
fldCtl = m_fieldcontrols.next();
1136
QHBoxLayout* hlayout = new QHBoxLayout;
1137
QSpacerItem* hspacer = new QSpacerItem(16, 0, QSizePolicy::Expanding,
1138
QSizePolicy::Minimum);
1139
QPushButton* okButton = new QPushButton(i18n("&OK"), this);
1140
QPushButton* cancelButton = new QPushButton(i18n("&Cancel"), this);
1141
if (hlayout && okButton && cancelButton) {
1142
hlayout->addItem(hspacer);
1143
hlayout->addWidget(okButton);
1144
hlayout->addWidget(cancelButton);
1145
okButton->setDefault(true);
1146
connect(okButton, SIGNAL(clicked()), this, SLOT(accept()));
1147
connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject()));
1148
vlayout->addLayout(hlayout);
1150
#if QT_VERSION >= 0x040000
1151
setMinimumWidth(525);
1160
EditFrameFieldsDialog::~EditFrameFieldsDialog()
1162
#if QT_VERSION >= 0x040000
1163
qDeleteAll(m_fieldcontrols);
1164
m_fieldcontrols.clear();
1169
* Update fields and get edited fields.
1171
* @return field list.
1173
const Frame::FieldList& EditFrameFieldsDialog::getUpdatedFieldList()
1175
#if QT_VERSION >= 0x040000
1176
QListIterator<FieldControl*> it(m_fieldcontrols);
1177
while (it.hasNext()) {
1178
it.next()->updateTag();
1181
FieldControl* fldCtl = m_fieldcontrols.first();
1182
while (fldCtl != NULL) {
1183
fldCtl->updateTag();
1184
fldCtl = m_fieldcontrols.next();
1194
* @param ft frame table
1196
FrameList::FrameList(FrameTable* ft) :
1197
m_file(0), m_frameTable(ft)
246
1301
void FrameList::clearListBox()
1304
m_frameTable->frames().clear();
1305
m_frameTable->framesToTable();
1310
* Fill listbox with frame descriptions.
1311
* Before using this method, the listbox and file have to be set.
1312
* @see setListBox(), setTags()
1314
void FrameList::readTags()
1317
m_file->getAllFramesV2(m_frameTable->frames());
1318
m_frameTable->framesToTable();
1323
* Set file and fill the list box with its frames.
1324
* The listbox has to be set with setListBox() before calling this
1327
* @param taggedFile file
1329
void FrameList::setTags(TaggedFile* taggedFile)
1331
m_file = taggedFile;
1335
* Create dialog to edit a frame and update the fields
1336
* if Ok is returned.
1338
* @param frame frame to edit
1340
* @return true if Ok selected in dialog.
1342
bool FrameList::editFrame(Frame& frame)
1345
QString name(frame.getName(true));
1346
if (!name.isEmpty()) {
1347
#if QT_VERSION >= 0x040000
1348
name = QCM_translate(name.toLatin1().data());
1350
name = QCM_translate(name);
1353
if (frame.getFieldList().empty()) {
1354
EditFrameDialog* dialog =
1355
new EditFrameDialog(0, name, frame.getValue());
1356
result = dialog && dialog->exec() == QDialog::Accepted;
1358
frame.setValue(dialog->getText());
1361
EditFrameFieldsDialog* dialog =
1362
new EditFrameFieldsDialog(0, name, frame.getFieldList());
1363
result = dialog && dialog->exec() == QDialog::Accepted;
1365
frame.setFieldList(dialog->getUpdatedFieldList());
1366
frame.setValueFromFieldList();
1369
if (result && m_file) {
1370
if (m_file->setFrameV2(frame)) {
1371
m_file->markTag2Changed();
1378
* Create dialog to edit the selected frame and update the fields
1379
* if Ok is returned.
1381
* @return true if Ok selected in dialog.
1383
bool FrameList::editFrame()
1385
if (getSelectedFrame(m_frame)) {
1386
return editFrame(m_frame);
1392
* Delete selected frame.
1394
* @return false if frame not found.
1396
bool FrameList::deleteFrame()
1398
m_frameTable->saveCursor();
1400
if (getSelectedFrame(frame) && m_file) {
1401
m_file->deleteFrameV2(frame);
1403
m_frameTable->restoreCursor();
1412
* @param edit true to edit frame after adding it
1414
* @return true if frame added.
1416
bool FrameList::addFrame(bool edit)
1419
if (!m_file->addFrameV2(m_frame)) {
1423
if (!editFrame(m_frame)) {
1424
m_file->deleteFrameV2(m_frame);
1425
m_file->markTag2Changed(false);
1429
int index = m_frame.getIndex();
1430
readTags(); // refresh listbox
1432
setSelectedId(index);
1433
#if QT_VERSION < 0x040000
1434
m_frameTable->ensureCellVisible(m_frameTable->currentRow(), m_frameTable->currentColumn());
1443
* Get type of frame from name.
1445
* @param name name, spaces and case are ignored
1449
static Frame::Type getTypeFromName(QString name)
1451
static QMap<QString, int> strNumMap;
1452
if (strNumMap.empty()) {
1453
// first time initialization
1454
for (int i = 0; i <= Frame::FT_LastFrame; ++i) {
1455
Frame::Type type = static_cast<Frame::Type>(i);
1456
strNumMap.insert(QCM_translate(Frame::getNameFromType(type)).remove(' ').QCM_toUpper(),
1460
QMap<QString, int>::const_iterator it =
1461
strNumMap.find(name.remove(' ').QCM_toUpper());
1462
if (it != strNumMap.end()) {
1463
return static_cast<Frame::Type>(*it);
1465
return Frame::FT_Other;
1469
* Display a dialog to select a frame type.
1471
* @return false if no frame selected.
1473
bool FrameList::selectFrame()
1475
// strange, but necessary to get the strings translated with Qt4 without KDE
1476
const char* const title = I18N_NOOP("Add Frame");
1477
const char* const msg = I18N_NOOP("Select the frame ID");
1480
QString name = QInputDialog::QCM_getItem(
1481
0, QCM_translate(title),
1482
QCM_translate(msg), m_file->getFrameIds(), 0, true, &ok);
1484
Frame::Type type = getTypeFromName(name);
1485
m_frame = Frame(type, "", name, -1);
1492
* Paste the selected frame from the copy buffer.
1494
* @return true if frame pasted.
1496
bool FrameList::pasteFrame() {
1497
if (m_file && m_frame.getType() != Frame::FT_UnknownFrame) {
1498
m_file->addFrameV2(m_frame);
1499
m_file->setFrameV2(m_frame);