From 9e3508134b5b8d4e93fe2c869d94063c174cab62 Mon Sep 17 00:00:00 2001 From: Jonas Kvinge <jonas@jkvinge.net> Date: Wed, 23 Sep 2020 00:52:41 +0200 Subject: [PATCH] Add compilation to edit tag dialog --- src/dialogs/edittagdialog.cpp | 34 ++++++++- src/dialogs/edittagdialog.ui | 139 ++++++++++++++++++++++++++++------ src/widgets/lineedit.cpp | 30 ++++++-- src/widgets/lineedit.h | 88 ++++++++++++++++----- 4 files changed, 239 insertions(+), 52 deletions(-) diff --git a/src/dialogs/edittagdialog.cpp b/src/dialogs/edittagdialog.cpp index 7b4e0695b..adabcb5d6 100644 --- a/src/dialogs/edittagdialog.cpp +++ b/src/dialogs/edittagdialog.cpp @@ -54,6 +54,7 @@ #include <QShortcut> #include <QSize> #include <QSpinBox> +#include <QCheckBox> #include <QSplitter> #include <QTabWidget> #include <QTextEdit> @@ -156,6 +157,9 @@ EditTagDialog::EditTagDialog(Application *app, QWidget *parent) else if (qobject_cast<QSpinBox*>(widget)) { connect(widget, SIGNAL(valueChanged(int)), SLOT(FieldValueEdited())); } + else if (qobject_cast<QCheckBox*>(widget)) { + connect(widget, SIGNAL(stateChanged(int)), SLOT(FieldValueEdited())); + } } } @@ -275,6 +279,7 @@ QList<EditTagDialog::Data> EditTagDialog::LoadData(const SongList &songs) const } return ret; + } void EditTagDialog::SetSongs(const SongList &s, const PlaylistItemList &items) { @@ -325,9 +330,11 @@ void EditTagDialog::SetSongsFinished(QFuture<QList<Data>> future) { } void EditTagDialog::SetSongListVisibility(bool visible) { + ui_->song_list->setVisible(visible); previous_button_->setEnabled(visible); next_button_->setEnabled(visible); + } QVariant EditTagDialog::Data::value(const Song &song, const QString &id) { @@ -345,6 +352,7 @@ QVariant EditTagDialog::Data::value(const Song &song, const QString &id) { if (id == "track") return song.track(); if (id == "disc") return song.disc(); if (id == "year") return song.year(); + if (id == "compilation") return song.compilation(); qLog(Warning) << "Unknown ID" << id; return QVariant(); @@ -365,16 +373,19 @@ void EditTagDialog::Data::set_value(const QString &id, const QVariant &value) { else if (id == "track") current_.set_track(value.toInt()); else if (id == "disc") current_.set_disc(value.toInt()); else if (id == "year") current_.set_year(value.toInt()); + else if (id == "compilation") current_.set_compilation(value.toBool()); else qLog(Warning) << "Unknown ID" << id; } bool EditTagDialog::DoesValueVary(const QModelIndexList &sel, const QString &id) const { + QVariant value = data_[sel.first().row()].current_value(id); for (int i = 1; i < sel.count(); ++i) { if (value != data_[sel[i].row()].current_value(id)) return true; } return false; + } bool EditTagDialog::IsValueModified(const QModelIndexList &sel, const QString &id) const { @@ -396,11 +407,15 @@ void EditTagDialog::InitFieldValue(const FieldData &field, const QModelIndexList editor->clear_hint(); if (varies) { editor->set_hint(tr(EditTagDialog::kHintText)); + editor->set_partially(); } else { - editor->set_text(data_[sel[0].row()].current_value(field.id_).toString()); + editor->set_value(data_[sel[0].row()].current_value(field.id_)); } } + else { + qLog(Error) << "Missing editor for" << field.editor_->objectName(); + } UpdateModifiedField(field, sel); @@ -410,8 +425,12 @@ void EditTagDialog::UpdateFieldValue(const FieldData &field, const QModelIndexLi // Get the value from the field QVariant value; + if (ExtendedEditor *editor = dynamic_cast<ExtendedEditor*>(field.editor_)) { - value = editor->text(); + value = editor->value(); + } + else { + qLog(Error) << "Missing editor for" << field.editor_->objectName(); } // Did we get it? @@ -654,6 +673,7 @@ void EditTagDialog::LoadCoverFromURL() { QUrl cover_url = album_cover_choice_controller_->LoadCoverFromURL(song); if (!cover_url.isEmpty()) UpdateCoverOf(*song, sel, cover_url); + } void EditTagDialog::SearchForCover() { @@ -666,6 +686,7 @@ void EditTagDialog::SearchForCover() { QUrl cover_url = album_cover_choice_controller_->SearchForCover(song); if (!cover_url.isEmpty()) UpdateCoverOf(*song, sel, cover_url); + } void EditTagDialog::UnsetCover() { @@ -677,6 +698,7 @@ void EditTagDialog::UnsetCover() { QUrl cover_url = album_cover_choice_controller_->UnsetCover(song); UpdateCoverOf(*song, sel, cover_url); + } void EditTagDialog::ShowCover() { @@ -687,6 +709,7 @@ void EditTagDialog::ShowCover() { } album_cover_choice_controller_->ShowCover(*song); + } void EditTagDialog::UpdateCoverOf(const Song &selected, const QModelIndexList &sel, const QUrl &cover_url) { @@ -716,6 +739,7 @@ void EditTagDialog::NextSong() { int row = (ui_->song_list->currentRow() + 1) % ui_->song_list->count(); ui_->song_list->setCurrentRow(row); + } void EditTagDialog::PreviousSong() { @@ -726,12 +750,15 @@ void EditTagDialog::PreviousSong() { int row = (ui_->song_list->currentRow() - 1 + ui_->song_list->count()) % ui_->song_list->count(); ui_->song_list->setCurrentRow(row); + } void EditTagDialog::ButtonClicked(QAbstractButton *button) { + if (button == ui_->button_box->button(QDialogButtonBox::Discard)) { reject(); } + } void EditTagDialog::SaveData(const QList<Data> &tag_data) { @@ -802,6 +829,7 @@ bool EditTagDialog::eventFilter(QObject *o, QEvent *e) { } } return false; + } void EditTagDialog::showEvent(QShowEvent *e) { @@ -815,6 +843,7 @@ void EditTagDialog::showEvent(QShowEvent *e) { ui_->tab_widget->setCurrentIndex(s.value("current_tab").toInt()); QDialog::showEvent(e); + } void EditTagDialog::hideEvent(QHideEvent *e) { @@ -825,6 +854,7 @@ void EditTagDialog::hideEvent(QHideEvent *e) { s.setValue("current_tab", ui_->tab_widget->currentIndex()); QDialog::hideEvent(e); + } void EditTagDialog::ResetPlayCounts() { diff --git a/src/dialogs/edittagdialog.ui b/src/dialogs/edittagdialog.ui index 4427bad0f..a28359365 100644 --- a/src/dialogs/edittagdialog.ui +++ b/src/dialogs/edittagdialog.ui @@ -7,7 +7,7 @@ <x>0</x> <y>0</y> <width>863</width> - <height>645</height> + <height>671</height> </rect> </property> <property name="windowTitle"> @@ -30,7 +30,7 @@ </widget> <widget class="QTabWidget" name="tab_widget"> <property name="currentIndex"> - <number>0</number> + <number>1</number> </property> <widget class="QWidget" name="summary_tab"> <attribute name="title"> @@ -150,7 +150,7 @@ <number>18</number> </property> <item row="0" column="0"> - <widget class="QLabel" name="length_label"> + <widget class="QLabel" name="label_length"> <property name="sizePolicy"> <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> <horstretch>0</horstretch> @@ -194,7 +194,7 @@ </widget> </item> <item row="0" column="2"> - <widget class="QLabel" name="playcount_label"> + <widget class="QLabel" name="label_playcount"> <property name="sizePolicy"> <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> <horstretch>0</horstretch> @@ -226,7 +226,7 @@ </widget> </item> <item row="1" column="2"> - <widget class="QLabel" name="skipcount_label"> + <widget class="QLabel" name="label_skipcount"> <property name="sizePolicy"> <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> <horstretch>0</horstretch> @@ -252,7 +252,7 @@ </widget> </item> <item row="1" column="0"> - <widget class="QLabel" name="bitrate_label"> + <widget class="QLabel" name="label_bitrate"> <property name="sizePolicy"> <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> <horstretch>0</horstretch> @@ -290,7 +290,7 @@ </widget> </item> <item row="2" column="2"> - <widget class="QLabel" name="lastplayed_label"> + <widget class="QLabel" name="label_lastplayed"> <property name="sizePolicy"> <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> <horstretch>0</horstretch> @@ -316,7 +316,7 @@ </widget> </item> <item row="2" column="0"> - <widget class="QLabel" name="samplerate_label"> + <widget class="QLabel" name="label_samplerate"> <property name="sizePolicy"> <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> <horstretch>0</horstretch> @@ -348,7 +348,7 @@ </widget> </item> <item row="3" column="0"> - <widget class="QLabel" name="bitdepth_label"> + <widget class="QLabel" name="label_bitdepth"> <property name="sizePolicy"> <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> <horstretch>0</horstretch> @@ -380,7 +380,7 @@ </widget> </item> <item row="4" column="0"> - <widget class="QLabel" name="filesize_label"> + <widget class="QLabel" name="label_filesize"> <property name="sizePolicy"> <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> <horstretch>0</horstretch> @@ -412,7 +412,7 @@ </widget> </item> <item row="6" column="0"> - <widget class="QLabel" name="filetype_label"> + <widget class="QLabel" name="label_filetype"> <property name="sizePolicy"> <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> <horstretch>0</horstretch> @@ -447,7 +447,7 @@ </widget> </item> <item row="7" column="0"> - <widget class="QLabel" name="mtime_label"> + <widget class="QLabel" name="label_mtime"> <property name="sizePolicy"> <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> <horstretch>0</horstretch> @@ -473,7 +473,7 @@ </widget> </item> <item row="8" column="0"> - <widget class="QLabel" name="ctime_label"> + <widget class="QLabel" name="label_ctime"> <property name="sizePolicy"> <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> <horstretch>0</horstretch> @@ -499,7 +499,7 @@ </widget> </item> <item row="5" column="0"> - <widget class="QLabel" name="filename_label"> + <widget class="QLabel" name="label_filename"> <property name="text"> <string>File name</string> </property> @@ -580,6 +580,12 @@ </item> <item row="7" column="0"> <widget class="QLabel" name="genre_label"> + <property name="minimumSize"> + <size> + <width>80</width> + <height>0</height> + </size> + </property> <property name="text"> <string>Genre</string> </property> @@ -609,7 +615,13 @@ </widget> </item> <item row="0" column="0"> - <widget class="QLabel" name="title_label"> + <widget class="QLabel" name="label_title"> + <property name="minimumSize"> + <size> + <width>80</width> + <height>0</height> + </size> + </property> <property name="text"> <string>Title</string> </property> @@ -619,7 +631,13 @@ </widget> </item> <item row="6" column="0"> - <widget class="QLabel" name="grouping_label"> + <widget class="QLabel" name="label_grouping"> + <property name="minimumSize"> + <size> + <width>80</width> + <height>0</height> + </size> + </property> <property name="text"> <string>Grouping</string> </property> @@ -629,7 +647,13 @@ </widget> </item> <item row="2" column="0"> - <widget class="QLabel" name="album_label"> + <widget class="QLabel" name="label_album"> + <property name="minimumSize"> + <size> + <width>80</width> + <height>0</height> + </size> + </property> <property name="text"> <string>Album</string> </property> @@ -669,7 +693,13 @@ </widget> </item> <item row="3" column="0"> - <widget class="QLabel" name="albumartist_label"> + <widget class="QLabel" name="label_albumartist"> + <property name="minimumSize"> + <size> + <width>80</width> + <height>0</height> + </size> + </property> <property name="text"> <string>Album artist</string> </property> @@ -689,7 +719,13 @@ </widget> </item> <item row="4" column="0"> - <widget class="QLabel" name="composer_label"> + <widget class="QLabel" name="label_composer"> + <property name="minimumSize"> + <size> + <width>80</width> + <height>0</height> + </size> + </property> <property name="text"> <string>Composer</string> </property> @@ -699,7 +735,13 @@ </widget> </item> <item row="11" column="0"> - <widget class="QLabel" name="comment_label"> + <widget class="QLabel" name="label_comment"> + <property name="minimumSize"> + <size> + <width>80</width> + <height>0</height> + </size> + </property> <property name="text"> <string>Comment</string> </property> @@ -719,7 +761,7 @@ </widget> </item> <item row="0" column="2"> - <widget class="QLabel" name="track_label"> + <widget class="QLabel" name="label_track"> <property name="text"> <string>Track</string> </property> @@ -755,7 +797,13 @@ </widget> </item> <item row="1" column="0"> - <widget class="QLabel" name="artist_label"> + <widget class="QLabel" name="label_artist"> + <property name="minimumSize"> + <size> + <width>80</width> + <height>0</height> + </size> + </property> <property name="text"> <string>Artist</string> </property> @@ -791,7 +839,7 @@ </widget> </item> <item row="2" column="2"> - <widget class="QLabel" name="year_label"> + <widget class="QLabel" name="label_year"> <property name="text"> <string>Year</string> </property> @@ -811,7 +859,13 @@ </widget> </item> <item row="5" column="0"> - <widget class="QLabel" name="performer_label"> + <widget class="QLabel" name="label_performer"> + <property name="minimumSize"> + <size> + <width>80</width> + <height>0</height> + </size> + </property> <property name="text"> <string>Performer</string> </property> @@ -822,6 +876,12 @@ </item> <item row="10" column="0"> <widget class="QLabel" name="label_lyrics"> + <property name="minimumSize"> + <size> + <width>80</width> + <height>0</height> + </size> + </property> <property name="text"> <string>Lyrics</string> </property> @@ -840,6 +900,32 @@ </property> </widget> </item> + <item row="8" column="1"> + <widget class="CheckBox" name="compilation"> + <property name="has_reset_button" stdset="0"> + <bool>false</bool> + </property> + <property name="has_clear_button" stdset="0"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="8" column="0"> + <widget class="QLabel" name="label_compilation"> + <property name="minimumSize"> + <size> + <width>80</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string>Compilation</string> + </property> + <property name="buddy"> + <cstring>compilation</cstring> + </property> + </widget> + </item> </layout> </widget> </widget> @@ -878,6 +964,11 @@ <extends>QSpinBox</extends> <header>widgets/lineedit.h</header> </customwidget> + <customwidget> + <class>CheckBox</class> + <extends>QCheckBox</extends> + <header>widgets/lineedit.h</header> + </customwidget> </customwidgets> <tabstops> <tabstop>song_list</tabstop> diff --git a/src/widgets/lineedit.cpp b/src/widgets/lineedit.cpp index 6eff359c3..7aaa1061f 100644 --- a/src/widgets/lineedit.cpp +++ b/src/widgets/lineedit.cpp @@ -71,19 +71,21 @@ ExtendedEditor::ExtendedEditor(QWidget *widget, int extra_right_padding, bool dr reset_button_->setFocusPolicy(Qt::NoFocus); reset_button_->hide(); - widget->connect(clear_button_, SIGNAL(clicked()), widget, SLOT(clear())); widget->connect(clear_button_, SIGNAL(clicked()), widget, SLOT(setFocus())); + if (qobject_cast<QLineEdit*>(widget) || qobject_cast<QPlainTextEdit*>(widget) || qobject_cast<QSpinBox*>(widget)) { + widget->connect(clear_button_, SIGNAL(clicked()), widget, SLOT(clear())); + } UpdateButtonGeometry(); } -void ExtendedEditor::set_hint(const QString& hint) { +void ExtendedEditor::set_hint(const QString &hint) { hint_ = hint; widget_->update(); } -void ExtendedEditor::set_clear_button(bool visible) { +void ExtendedEditor::set_clear_button(const bool visible) { has_clear_button_ = visible; clear_button_->setVisible(visible); UpdateButtonGeometry(); @@ -93,7 +95,7 @@ bool ExtendedEditor::has_reset_button() const { return reset_button_->isVisible(); } -void ExtendedEditor::set_reset_button(bool visible) { +void ExtendedEditor::set_reset_button(const bool visible) { reset_button_->setVisible(visible); UpdateButtonGeometry(); } @@ -161,7 +163,7 @@ LineEdit::LineEdit(QWidget *parent) : QLineEdit(parent), ExtendedEditor(this) { connect(this, SIGNAL(textChanged(QString)), SLOT(text_changed(QString))); } -void LineEdit::text_changed(const QString& text) { +void LineEdit::text_changed(const QString &text) { if (text.isEmpty()) { // Consider empty string as LTR @@ -222,8 +224,26 @@ void SpinBox::resizeEvent(QResizeEvent *e) { Resize(); } +CheckBox::CheckBox(QWidget *parent) + : QCheckBox(parent), ExtendedEditor(this, 14, false) +{ + connect(reset_button_, SIGNAL(clicked()), SIGNAL(Reset())); +} + +void CheckBox::paintEvent(QPaintEvent *e) { + QCheckBox::paintEvent(e); + Paint(this); +} + +void CheckBox::resizeEvent(QResizeEvent *e) { + QCheckBox::resizeEvent(e); + Resize(); +} + QString SpinBox::textFromValue(int val) const { + if (val <= 0 && !hint_.isEmpty()) return "-"; return QSpinBox::textFromValue(val); + } diff --git a/src/widgets/lineedit.h b/src/widgets/lineedit.h index 83470c3df..f999bf7eb 100644 --- a/src/widgets/lineedit.h +++ b/src/widgets/lineedit.h @@ -30,6 +30,7 @@ #include <QLineEdit> #include <QPlainTextEdit> #include <QSpinBox> +#include <QCheckBox> class QToolButton; class QPaintDevice; @@ -37,6 +38,7 @@ class QPaintEvent; class QResizeEvent; class LineEditInterface { + public: explicit LineEditInterface(QWidget *widget) : widget_(widget) {} @@ -44,40 +46,43 @@ class LineEditInterface { virtual ~LineEditInterface() {} - virtual void clear() { set_text(QString()); } + virtual void set_enabled(const bool enabled) = 0; virtual void set_focus() = 0; - virtual QString text() const = 0; - virtual void set_text(const QString& text) = 0; + + virtual void clear() = 0; + virtual QVariant value() const = 0; + virtual void set_value(const QVariant &value) = 0; virtual QString hint() const = 0; - virtual void set_hint(const QString& hint) = 0; + virtual void set_hint(const QString &hint) = 0; virtual void clear_hint() = 0; - virtual void set_enabled(bool enabled) = 0; + virtual void set_partially() {} protected: QWidget *widget_; }; class ExtendedEditor : public LineEditInterface { + public: explicit ExtendedEditor(QWidget *widget, int extra_right_padding = 0, bool draw_hint = true); ~ExtendedEditor() override {} - virtual bool is_empty() const { return text().isEmpty(); } + virtual bool is_empty() const { return value().toString().isEmpty(); } QString hint() const override { return hint_; } - void set_hint(const QString& hint) override; + void set_hint(const QString &hint) override; void clear_hint() override { set_hint(QString()); } bool has_clear_button() const { return has_clear_button_; } - void set_clear_button(bool visible); + void set_clear_button(const bool visible); bool has_reset_button() const; - void set_reset_button(bool visible); + void set_reset_button(const bool visible); qreal font_point_size() const { return font_point_size_; } - void set_font_point_size(qreal size) { font_point_size_ = size; } + void set_font_point_size(const qreal size) { font_point_size_ = size; } protected: void Paint(QPaintDevice *device); @@ -111,10 +116,14 @@ class LineEdit : public QLineEdit, public ExtendedEditor { explicit LineEdit(QWidget *parent = nullptr); // ExtendedEditor - void set_focus() override { QLineEdit::setFocus(); } - QString text() const override { return QLineEdit::text(); } - void set_text(const QString& text) override { QLineEdit::setText(text); } void set_enabled(bool enabled) override { QLineEdit::setEnabled(enabled); } + void set_focus() override { QLineEdit::setFocus(); } + + QVariant value() const override { return QLineEdit::text(); } + void set_value(const QVariant &value) override { QLineEdit::setText(value.toString()); } + + public slots: + void clear() override { QLineEdit::clear(); } protected: void paintEvent(QPaintEvent*) override; @@ -125,7 +134,7 @@ class LineEdit : public QLineEdit, public ExtendedEditor { void set_rtl(bool rtl) { is_rtl_ = rtl; } private slots: - void text_changed(const QString& text); + void text_changed(const QString &text); signals: void Reset(); @@ -141,10 +150,14 @@ class TextEdit : public QPlainTextEdit, public ExtendedEditor { explicit TextEdit(QWidget *parent = nullptr); // ExtendedEditor - void set_focus() override { QPlainTextEdit::setFocus(); } - QString text() const override { return QPlainTextEdit::toPlainText(); } - void set_text(const QString& text) override { QPlainTextEdit::setPlainText(text); } void set_enabled(bool enabled) override { QPlainTextEdit::setEnabled(enabled); } + void set_focus() override { QPlainTextEdit::setFocus(); } + + QVariant value() const override { return QPlainTextEdit::toPlainText(); } + void set_value(const QVariant &value) override { QPlainTextEdit::setPlainText(value.toString()); } + + public slots: + void clear() override { QPlainTextEdit::clear(); } protected: void paintEvent(QPaintEvent*) override; @@ -167,11 +180,44 @@ class SpinBox : public QSpinBox, public ExtendedEditor { QString textFromValue(int val) const override; // ExtendedEditor - bool is_empty() const override { return text().isEmpty() || text() == "0"; } - void set_focus() override { QSpinBox::setFocus(); } - QString text() const override { return QSpinBox::text(); } - void set_text(const QString& text) override { QSpinBox::setValue(text.toInt()); } void set_enabled(bool enabled) override { QSpinBox::setEnabled(enabled); } + void set_focus() override { QSpinBox::setFocus(); } + + QVariant value() const override { return QSpinBox::value(); } + void set_value(const QVariant &value) override { QSpinBox::setValue(value.toInt()); } + bool is_empty() const override { return text().isEmpty() || text() == "0"; } + + public slots: + void clear() override { QSpinBox::clear(); } + + protected: + void paintEvent(QPaintEvent*) override; + void resizeEvent(QResizeEvent*) override; + + signals: + void Reset(); +}; + +class CheckBox : public QCheckBox, public ExtendedEditor { + Q_OBJECT + Q_PROPERTY(QString hint READ hint WRITE set_hint) + Q_PROPERTY(bool has_clear_button READ has_clear_button WRITE set_clear_button) + Q_PROPERTY(bool has_reset_button READ has_reset_button WRITE set_reset_button) + + public: + explicit CheckBox(QWidget *parent = nullptr); + + // ExtendedEditor + void set_enabled(bool enabled) override { QCheckBox::setEnabled(enabled); } + void set_focus() override { QCheckBox::setFocus(); } + + bool is_empty() const override { return text().isEmpty() || text() == "0"; } + QVariant value() const override { return QCheckBox::isChecked(); } + void set_value(const QVariant &value) override { QCheckBox::setCheckState(value.toBool() ? Qt::Checked : Qt::Unchecked); } + void set_partially() override { QCheckBox::setCheckState(Qt::PartiallyChecked); } + + public slots: + void clear() override { QCheckBox::setChecked(false); } protected: void paintEvent(QPaintEvent*) override;