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
window-close
document-open
edit-clear
edit-copy
emblem-error
object-locked
object-unlocked
preferences-other
view-preview
document-open-recent

View File

@ -71,6 +71,8 @@ TagFieldEdit::TagFieldEdit(const QList<TagParser::Tag *> &tags, TagParser::Known
, m_plainTextEdit(nullptr)
, m_descriptionLineEdit(nullptr)
, m_restoreButton(nullptr)
, m_lockButton(nullptr)
, m_isLocked(false)
{
m_layout->setContentsMargins(QMargins());
setLayout(m_layout);
@ -214,6 +216,19 @@ bool TagFieldEdit::canApply(KnownField field) const
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.
*/
@ -309,7 +324,8 @@ ClearLineEdit *TagFieldEdit::setupLineEdit()
m_lineEdit = new ClearLineEdit(this);
m_lineEdit->setPlaceholderText(tr("empty"));
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);
connect(m_lineEdit, &ClearLineEdit::textChanged, this, &TagFieldEdit::showRestoreButton);
m_layout->addWidget(m_lineEdit);
@ -324,7 +340,8 @@ ClearPlainTextEdit *TagFieldEdit::setupPlainTextEdit()
{
m_plainTextEdit = new ClearPlainTextEdit(this);
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);
m_layout->addWidget(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") }));
m_comboBox->setCurrentIndex(0);
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->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
connect(m_comboBox, &ClearComboBox::currentTextChanged, this, &TagFieldEdit::showRestoreButton);
@ -385,7 +403,8 @@ ClearSpinBox *TagFieldEdit::setupSpinBox()
m_spinBoxes.first->setPlaceholderText(tr("empty"));
m_spinBoxes.first->setMinimumHidden(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->setMaximum(32766);
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->installEventFilter(this);
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);
connect(m_spinBoxes.second, static_cast<void (ClearSpinBox::*)(int)>(&ClearSpinBox::valueChanged), this, &TagFieldEdit::showRestoreButton);
subLayout->addWidget(m_spinBoxes.second);
@ -555,7 +575,7 @@ void TagFieldEdit::updateValue(const TagValue &value, PreviousValueHandling prev
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())) {
m_lineEdit->setText(text);
updated = true;
@ -580,19 +600,23 @@ void TagFieldEdit::updateValue(const TagValue &value, PreviousValueHandling prev
return PositionInSet();
}
}());
if (previousValueHandling == PreviousValueHandling::Clear || pos.position()) {
if (previousValueHandling != PreviousValueHandling::Keep || m_spinBoxes.first->isCleared()) {
m_spinBoxes.first->setValue(pos.position());
if (!m_isLocked || !pos.position()) {
if (previousValueHandling == PreviousValueHandling::Clear || 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;
}
} 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 (previousValueHandling != PreviousValueHandling::Keep || m_spinBoxes.second->isCleared()) {
m_spinBoxes.second->setValue(pos.total());
updated = true;
if (!m_isLocked || !pos.total()) {
if (previousValueHandling == PreviousValueHandling::Clear || pos.total()) {
if (previousValueHandling != PreviousValueHandling::Keep || m_spinBoxes.second->isCleared()) {
m_spinBoxes.second->setValue(pos.total());
updated = true;
}
}
}
} else {
@ -604,14 +628,16 @@ void TagFieldEdit::updateValue(const TagValue &value, PreviousValueHandling prev
return 0;
}
}());
if (previousValueHandling == PreviousValueHandling::Clear || num) {
if (previousValueHandling != PreviousValueHandling::Keep || m_spinBoxes.first->isCleared()) {
m_spinBoxes.first->setValue(num);
if (!m_isLocked || !num) {
if (previousValueHandling == PreviousValueHandling::Clear || 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;
}
} 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 {
auto desc = Utility::stringToQString(value.description(), value.descriptionEncoding());
applyAutoCorrection(desc);
m_descriptionLineEdit->setText(desc);
if (!m_isLocked || desc.isEmpty()) {
m_descriptionLineEdit->setText(desc);
}
} catch (const ConversionException &) {
conversionError = true;
m_descriptionLineEdit->clear();
if (!m_isLocked) {
m_descriptionLineEdit->clear();
}
}
}
} else if (m_descriptionLineEdit) {
@ -640,6 +670,9 @@ void TagFieldEdit::updateValue(const TagValue &value, PreviousValueHandling prev
if (updateRestoreButton && m_restoreButton) {
m_restoreButton->setVisible((!updated && m_restoreButton->isVisible()) || m_tags->size() > 1);
}
if (updated) {
setLocked(false);
}
// setup info button
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;
}
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([&] {
QString text;
if (conversionError) {
@ -678,19 +713,36 @@ void TagFieldEdit::updateValue(const TagValue &value, PreviousValueHandling prev
*/
IconButton *TagFieldEdit::setupRestoreButton()
{
if (!m_restoreButton) { // setup restore button
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);
if (m_restoreButton) {
return m_restoreButton;
}
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;
}
/*!
* \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).
*/
@ -850,11 +902,12 @@ void TagFieldEdit::handleRestoreButtonClicked()
}
QMenu menu;
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));
connect(action, &QAction::triggered,
std::bind(static_cast<void (TagFieldEdit::*)(Tag *, PreviousValueHandling)>(&TagFieldEdit::updateValue), this, tag,
PreviousValueHandling::Clear));
connect(action, &QAction::triggered, [this, tag] {
setLocked(false);
updateValue(tag, PreviousValueHandling::Clear);
});
}
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

View File

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