Allow locking fields

This commit is contained in:
Martchus 2019-05-28 23:59:38 +02:00
parent 53d4f50bfa
commit 833b96351e
3 changed files with 122 additions and 38 deletions

View File

@ -125,7 +125,11 @@ set(DOC_FILES README.md)
set(REQUIRED_ICONS set(REQUIRED_ICONS
window-close window-close
document-open document-open
edit-clear
edit-copy edit-copy
emblem-error
object-locked
object-unlocked
preferences-other preferences-other
view-preview view-preview
document-open-recent document-open-recent

View File

@ -71,6 +71,8 @@ TagFieldEdit::TagFieldEdit(const QList<TagParser::Tag *> &tags, TagParser::Known
, m_plainTextEdit(nullptr) , m_plainTextEdit(nullptr)
, m_descriptionLineEdit(nullptr) , m_descriptionLineEdit(nullptr)
, m_restoreButton(nullptr) , m_restoreButton(nullptr)
, m_lockButton(nullptr)
, m_isLocked(false)
{ {
m_layout->setContentsMargins(QMargins()); m_layout->setContentsMargins(QMargins());
setLayout(m_layout); setLayout(m_layout);
@ -214,6 +216,19 @@ bool TagFieldEdit::canApply(KnownField field) const
return false; return false;
} }
void TagFieldEdit::setLocked(bool locked)
{
if (locked == m_isLocked) {
return;
}
m_isLocked = locked;
if (m_lockButton) {
m_lockButton->setPixmap(QIcon::fromTheme(locked ? QStringLiteral("object-locked") : QStringLiteral("object-unlocked")).pixmap(16));
m_lockButton->setToolTip(
locked ? tr("Keep previous value only if not present in the next file") : tr("Keep previous value even if present in next file"));
}
}
/*! /*!
* \brief Sets whether the cover buttons are hidden. * \brief Sets whether the cover buttons are hidden.
*/ */
@ -309,7 +324,8 @@ ClearLineEdit *TagFieldEdit::setupLineEdit()
m_lineEdit = new ClearLineEdit(this); m_lineEdit = new ClearLineEdit(this);
m_lineEdit->setPlaceholderText(tr("empty")); m_lineEdit->setPlaceholderText(tr("empty"));
static_cast<ButtonOverlay *>(m_lineEdit)->setClearButtonEnabled(true); static_cast<ButtonOverlay *>(m_lineEdit)->setClearButtonEnabled(true);
m_lineEdit->insertCustomButton(0, setupRestoreButton()); m_lineEdit->insertCustomButton(0, setupLockButton());
m_lineEdit->insertCustomButton(1, setupRestoreButton());
m_lineEdit->installEventFilter(this); m_lineEdit->installEventFilter(this);
connect(m_lineEdit, &ClearLineEdit::textChanged, this, &TagFieldEdit::showRestoreButton); connect(m_lineEdit, &ClearLineEdit::textChanged, this, &TagFieldEdit::showRestoreButton);
m_layout->addWidget(m_lineEdit); m_layout->addWidget(m_lineEdit);
@ -324,7 +340,8 @@ ClearPlainTextEdit *TagFieldEdit::setupPlainTextEdit()
{ {
m_plainTextEdit = new ClearPlainTextEdit(this); m_plainTextEdit = new ClearPlainTextEdit(this);
m_plainTextEdit->setClearButtonEnabled(true); m_plainTextEdit->setClearButtonEnabled(true);
m_plainTextEdit->insertCustomButton(0, setupRestoreButton()); m_plainTextEdit->insertCustomButton(0, setupLockButton());
m_plainTextEdit->insertCustomButton(1, setupRestoreButton());
connect(m_plainTextEdit->document(), &QTextDocument::contentsChanged, this, &TagFieldEdit::showRestoreButton); connect(m_plainTextEdit->document(), &QTextDocument::contentsChanged, this, &TagFieldEdit::showRestoreButton);
m_layout->addWidget(m_plainTextEdit); m_layout->addWidget(m_plainTextEdit);
m_widgets << m_plainTextEdit; m_widgets << m_plainTextEdit;
@ -366,7 +383,8 @@ ClearComboBox *TagFieldEdit::setupGenreComboBox()
tr("Top 40"), tr("Trailer"), tr("Trance"), tr("Tribal"), tr("Trip-Hop"), tr("Trop Rock"), tr("Vocal"), tr("World Music") })); tr("Top 40"), tr("Trailer"), tr("Trance"), tr("Tribal"), tr("Trip-Hop"), tr("Trop Rock"), tr("Vocal"), tr("World Music") }));
m_comboBox->setCurrentIndex(0); m_comboBox->setCurrentIndex(0);
m_comboBox->setClearButtonEnabled(true); m_comboBox->setClearButtonEnabled(true);
m_comboBox->insertCustomButton(0, setupRestoreButton()); m_comboBox->insertCustomButton(0, setupLockButton());
m_comboBox->insertCustomButton(1, setupRestoreButton());
m_comboBox->installEventFilter(this); m_comboBox->installEventFilter(this);
m_comboBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); m_comboBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
connect(m_comboBox, &ClearComboBox::currentTextChanged, this, &TagFieldEdit::showRestoreButton); connect(m_comboBox, &ClearComboBox::currentTextChanged, this, &TagFieldEdit::showRestoreButton);
@ -385,7 +403,8 @@ ClearSpinBox *TagFieldEdit::setupSpinBox()
m_spinBoxes.first->setPlaceholderText(tr("empty")); m_spinBoxes.first->setPlaceholderText(tr("empty"));
m_spinBoxes.first->setMinimumHidden(true); m_spinBoxes.first->setMinimumHidden(true);
m_spinBoxes.first->setClearButtonEnabled(true); m_spinBoxes.first->setClearButtonEnabled(true);
m_spinBoxes.first->insertCustomButton(0, setupRestoreButton()); m_spinBoxes.first->insertCustomButton(0, setupLockButton());
m_spinBoxes.first->insertCustomButton(1, setupRestoreButton());
m_spinBoxes.first->installEventFilter(this); m_spinBoxes.first->installEventFilter(this);
m_spinBoxes.first->setMaximum(32766); m_spinBoxes.first->setMaximum(32766);
connect(m_spinBoxes.first, static_cast<void (ClearSpinBox::*)(int)>(&ClearSpinBox::valueChanged), this, &TagFieldEdit::showRestoreButton); connect(m_spinBoxes.first, static_cast<void (ClearSpinBox::*)(int)>(&ClearSpinBox::valueChanged), this, &TagFieldEdit::showRestoreButton);
@ -422,7 +441,8 @@ QPair<Widgets::ClearSpinBox *, Widgets::ClearSpinBox *> &TagFieldEdit::setupPosi
m_spinBoxes.second->setClearButtonEnabled(true); m_spinBoxes.second->setClearButtonEnabled(true);
m_spinBoxes.second->installEventFilter(this); m_spinBoxes.second->installEventFilter(this);
m_spinBoxes.second->setMaximum(32766); m_spinBoxes.second->setMaximum(32766);
m_spinBoxes.second->insertCustomButton(0, setupRestoreButton()); m_spinBoxes.second->insertCustomButton(0, setupLockButton());
m_spinBoxes.second->insertCustomButton(1, setupRestoreButton());
m_spinBoxes.second->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); m_spinBoxes.second->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
connect(m_spinBoxes.second, static_cast<void (ClearSpinBox::*)(int)>(&ClearSpinBox::valueChanged), this, &TagFieldEdit::showRestoreButton); connect(m_spinBoxes.second, static_cast<void (ClearSpinBox::*)(int)>(&ClearSpinBox::valueChanged), this, &TagFieldEdit::showRestoreButton);
subLayout->addWidget(m_spinBoxes.second); subLayout->addWidget(m_spinBoxes.second);
@ -555,7 +575,7 @@ void TagFieldEdit::updateValue(const TagValue &value, PreviousValueHandling prev
return QString(); return QString();
} }
}()); }());
if (previousValueHandling == PreviousValueHandling::Clear || !text.isEmpty()) { if ((!m_isLocked || text.isEmpty()) && (previousValueHandling == PreviousValueHandling::Clear || !text.isEmpty())) {
if (m_lineEdit && (previousValueHandling != PreviousValueHandling::Keep || m_lineEdit->isCleared())) { if (m_lineEdit && (previousValueHandling != PreviousValueHandling::Keep || m_lineEdit->isCleared())) {
m_lineEdit->setText(text); m_lineEdit->setText(text);
updated = true; updated = true;
@ -580,19 +600,23 @@ void TagFieldEdit::updateValue(const TagValue &value, PreviousValueHandling prev
return PositionInSet(); return PositionInSet();
} }
}()); }());
if (previousValueHandling == PreviousValueHandling::Clear || pos.position()) { if (!m_isLocked || !pos.position()) {
if (previousValueHandling != PreviousValueHandling::Keep || m_spinBoxes.first->isCleared()) { if (previousValueHandling == PreviousValueHandling::Clear || pos.position()) {
m_spinBoxes.first->setValue(pos.position()); if (previousValueHandling != PreviousValueHandling::Keep || m_spinBoxes.first->isCleared()) {
m_spinBoxes.first->setValue(pos.position());
updated = true;
}
} else if (previousValueHandling == PreviousValueHandling::IncrementUpdate && !m_spinBoxes.first->isCleared()) {
m_spinBoxes.first->setValue(m_spinBoxes.first->value() + 1);
updated = true; updated = true;
} }
} else if (previousValueHandling == PreviousValueHandling::IncrementUpdate && !m_spinBoxes.first->isCleared()) {
m_spinBoxes.first->setValue(m_spinBoxes.first->value() + 1);
updated = true;
} }
if (previousValueHandling == PreviousValueHandling::Clear || pos.total()) { if (!m_isLocked || !pos.total()) {
if (previousValueHandling != PreviousValueHandling::Keep || m_spinBoxes.second->isCleared()) { if (previousValueHandling == PreviousValueHandling::Clear || pos.total()) {
m_spinBoxes.second->setValue(pos.total()); if (previousValueHandling != PreviousValueHandling::Keep || m_spinBoxes.second->isCleared()) {
updated = true; m_spinBoxes.second->setValue(pos.total());
updated = true;
}
} }
} }
} else { } else {
@ -604,14 +628,16 @@ void TagFieldEdit::updateValue(const TagValue &value, PreviousValueHandling prev
return 0; return 0;
} }
}()); }());
if (previousValueHandling == PreviousValueHandling::Clear || num) { if (!m_isLocked || !num) {
if (previousValueHandling != PreviousValueHandling::Keep || m_spinBoxes.first->isCleared()) { if (previousValueHandling == PreviousValueHandling::Clear || num) {
m_spinBoxes.first->setValue(num); if (previousValueHandling != PreviousValueHandling::Keep || m_spinBoxes.first->isCleared()) {
m_spinBoxes.first->setValue(num);
updated = true;
}
} else if (previousValueHandling == PreviousValueHandling::IncrementUpdate && !m_spinBoxes.first->isCleared()) {
m_spinBoxes.first->setValue(m_spinBoxes.first->value() + 1);
updated = true; updated = true;
} }
} else if (previousValueHandling == PreviousValueHandling::IncrementUpdate && !m_spinBoxes.first->isCleared()) {
m_spinBoxes.first->setValue(m_spinBoxes.first->value() + 1);
updated = true;
} }
} }
} }
@ -627,10 +653,14 @@ void TagFieldEdit::updateValue(const TagValue &value, PreviousValueHandling prev
try { try {
auto desc = Utility::stringToQString(value.description(), value.descriptionEncoding()); auto desc = Utility::stringToQString(value.description(), value.descriptionEncoding());
applyAutoCorrection(desc); applyAutoCorrection(desc);
m_descriptionLineEdit->setText(desc); if (!m_isLocked || desc.isEmpty()) {
m_descriptionLineEdit->setText(desc);
}
} catch (const ConversionException &) { } catch (const ConversionException &) {
conversionError = true; conversionError = true;
m_descriptionLineEdit->clear(); if (!m_isLocked) {
m_descriptionLineEdit->clear();
}
} }
} }
} else if (m_descriptionLineEdit) { } else if (m_descriptionLineEdit) {
@ -640,6 +670,9 @@ void TagFieldEdit::updateValue(const TagValue &value, PreviousValueHandling prev
if (updateRestoreButton && m_restoreButton) { if (updateRestoreButton && m_restoreButton) {
m_restoreButton->setVisible((!updated && m_restoreButton->isVisible()) || m_tags->size() > 1); m_restoreButton->setVisible((!updated && m_restoreButton->isVisible()) || m_tags->size() > 1);
} }
if (updated) {
setLocked(false);
}
// setup info button // setup info button
const auto widgets = initializer_list<ButtonOverlay *>{ m_lineEdit, m_comboBox, m_spinBoxes.first, m_spinBoxes.second }; const auto widgets = initializer_list<ButtonOverlay *>{ m_lineEdit, m_comboBox, m_spinBoxes.first, m_spinBoxes.second };
@ -652,7 +685,9 @@ void TagFieldEdit::updateValue(const TagValue &value, PreviousValueHandling prev
} }
return; return;
} }
const auto pixmap(QIcon(QStringLiteral(":/qtutilities/icons/hicolor/48x48/actions/edit-error.png")).pixmap(16)); const auto pixmap(
QIcon::fromTheme(QStringLiteral("emblem-error"), QIcon(QStringLiteral(":/qtutilities/icons/hicolor/48x48/actions/edit-error.png")))
.pixmap(16));
const auto text([&] { const auto text([&] {
QString text; QString text;
if (conversionError) { if (conversionError) {
@ -678,19 +713,36 @@ void TagFieldEdit::updateValue(const TagValue &value, PreviousValueHandling prev
*/ */
IconButton *TagFieldEdit::setupRestoreButton() IconButton *TagFieldEdit::setupRestoreButton()
{ {
if (!m_restoreButton) { // setup restore button if (m_restoreButton) {
m_restoreButton = new IconButton(this); return m_restoreButton;
m_restoreButton->setPixmap(
/*QIcon::fromTheme(QStringLiteral("edit-undo"), */ QIcon(QStringLiteral(":/qtutilities/icons/hicolor/48x48/actions/edit-menu.png") /*)*/)
.pixmap(16));
m_restoreButton->setToolTip(tr("Restore value as it is currently present in the file"));
connect(m_restoreButton, &IconButton::clicked, this, &TagFieldEdit::handleRestoreButtonClicked);
// ownership might be transfered to a child widget/layout
connect(m_restoreButton, &IconButton::destroyed, this, &TagFieldEdit::handleRestoreButtonDestroyed);
} }
m_restoreButton = new IconButton(this);
m_restoreButton->setPixmap(
QIcon::fromTheme(QStringLiteral("edit-undo"), QIcon(QStringLiteral(":/qtutilities/icons/hicolor/48x48/actions/edit-menu.png"))).pixmap(16));
m_restoreButton->setToolTip(tr("Restore value as it is currently present in the file"));
connect(m_restoreButton, &IconButton::clicked, this, &TagFieldEdit::handleRestoreButtonClicked);
// ownership might be transfered to a child widget/layout
connect(m_restoreButton, &IconButton::destroyed, this, &TagFieldEdit::handleRestoreButtonDestroyed);
return m_restoreButton; return m_restoreButton;
} }
/*!
* \brief Internally called by the other setup methods to create the "lock button".
*/
IconButton *TagFieldEdit::setupLockButton()
{
if (m_lockButton) {
return m_lockButton;
}
m_isLocked = !m_isLocked;
m_lockButton = new IconButton(this);
setLocked(!m_isLocked);
connect(m_lockButton, &IconButton::clicked, this, &TagFieldEdit::toggleLocked);
// ownership might be transfered to a child widget/layout
connect(m_lockButton, &IconButton::destroyed, this, &TagFieldEdit::handleLockButtonDestroyed);
return m_lockButton;
}
/*! /*!
* \brief Internally called to show the restore button (if there is one and at least one tag is assigned). * \brief Internally called to show the restore button (if there is one and at least one tag is assigned).
*/ */
@ -850,11 +902,12 @@ void TagFieldEdit::handleRestoreButtonClicked()
} }
QMenu menu; QMenu menu;
int i = 0; int i = 0;
for (Tag *const tag : tags()) { for (auto *const tag : tags()) {
const auto *const action = menu.addAction(tr("restore to value from %1 (%2)").arg(tag->typeName()).arg(++i)); const auto *const action = menu.addAction(tr("restore to value from %1 (%2)").arg(tag->typeName()).arg(++i));
connect(action, &QAction::triggered, connect(action, &QAction::triggered, [this, tag] {
std::bind(static_cast<void (TagFieldEdit::*)(Tag *, PreviousValueHandling)>(&TagFieldEdit::updateValue), this, tag, setLocked(false);
PreviousValueHandling::Clear)); updateValue(tag, PreviousValueHandling::Clear);
});
} }
menu.exec(QCursor::pos()); menu.exec(QCursor::pos());
} }
@ -869,4 +922,14 @@ void TagFieldEdit::handleRestoreButtonDestroyed(QObject *obj)
} }
} }
/*!
* \brief Sets m_lockButton to nullptr when the restore button has been destroyed.
*/
void TagFieldEdit::handleLockButtonDestroyed(QObject *obj)
{
if (obj == m_lockButton) {
m_lockButton = nullptr;
}
}
} // namespace QtGui } // namespace QtGui

View File

@ -46,6 +46,9 @@ public:
bool setValue(const TagParser::TagValue &value, PreviousValueHandling previousValueHandling = PreviousValueHandling::Clear); bool setValue(const TagParser::TagValue &value, PreviousValueHandling previousValueHandling = PreviousValueHandling::Clear);
bool hasDescription() const; bool hasDescription() const;
bool canApply(TagParser::KnownField field) const; bool canApply(TagParser::KnownField field) const;
bool isLocked() const;
void setLocked(bool locked);
void toggleLocked();
public slots: public slots:
void clear(); void clear();
@ -62,6 +65,7 @@ protected:
private slots: private slots:
void handleRestoreButtonClicked(); void handleRestoreButtonClicked();
void handleRestoreButtonDestroyed(QObject *obj = nullptr); void handleRestoreButtonDestroyed(QObject *obj = nullptr);
void handleLockButtonDestroyed(QObject *obj = nullptr);
private: private:
TagParser::TagDataType determineDataType(); TagParser::TagDataType determineDataType();
@ -80,6 +84,7 @@ private:
void updateValue( void updateValue(
const TagParser::TagValue &value, PreviousValueHandling previousValueHandling = PreviousValueHandling::Clear, bool resetRestoreButton = true); const TagParser::TagValue &value, PreviousValueHandling previousValueHandling = PreviousValueHandling::Clear, bool resetRestoreButton = true);
Widgets::IconButton *setupRestoreButton(); Widgets::IconButton *setupRestoreButton();
Widgets::IconButton *setupLockButton();
void showRestoreButton(); void showRestoreButton();
void applyAutoCorrection(QString &textValue); void applyAutoCorrection(QString &textValue);
void concretizePreviousValueHandling(PreviousValueHandling &previousValueHandling); void concretizePreviousValueHandling(PreviousValueHandling &previousValueHandling);
@ -96,6 +101,8 @@ private:
Widgets::ClearPlainTextEdit *m_plainTextEdit; Widgets::ClearPlainTextEdit *m_plainTextEdit;
Widgets::ClearLineEdit *m_descriptionLineEdit; Widgets::ClearLineEdit *m_descriptionLineEdit;
Widgets::IconButton *m_restoreButton; Widgets::IconButton *m_restoreButton;
Widgets::IconButton *m_lockButton;
bool m_isLocked;
}; };
inline const QList<TagParser::Tag *> &TagFieldEdit::tags() const inline const QList<TagParser::Tag *> &TagFieldEdit::tags() const
@ -108,6 +115,16 @@ inline TagParser::KnownField TagFieldEdit::field() const
return m_field; return m_field;
} }
inline bool TagFieldEdit::isLocked() const
{
return m_isLocked;
}
inline void TagFieldEdit::toggleLocked()
{
setLocked(!isLocked());
}
} // namespace QtGui } // namespace QtGui
#endif // QTGUI_TAGFIELDLINEEDIT_H #endif // QTGUI_TAGFIELDLINEEDIT_H