mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2024-10-01 01:26:01 -04:00
Correct issues with apply button
* Don't show apply button when creating new entries or groups (Fix #2191) * Don't mark entry/group as dirty when first creating a new one (prevents unnecessary discard dialog on cancel) * Properly enable/disable apply button when changes are made to entries and groups * Don't show discard change warning when locking database unless their are actual changes made NOTE: Extra pages in the group edit widget are not watched for changes yet. Requires a major refactor.
This commit is contained in:
parent
71e375aff0
commit
4b1258f585
@ -261,12 +261,11 @@ bool DatabaseWidget::isSearchActive() const
|
||||
bool DatabaseWidget::isEditWidgetModified() const
|
||||
{
|
||||
if (currentWidget() == m_editEntryWidget) {
|
||||
return m_editEntryWidget->hasBeenModified();
|
||||
} else {
|
||||
// other edit widget don't have a hasBeenModified() method yet
|
||||
// assume that they already have been modified
|
||||
return true;
|
||||
return m_editEntryWidget->isModified();
|
||||
} else if (currentWidget() == m_editGroupWidget) {
|
||||
return m_editGroupWidget->isModified();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
QList<int> DatabaseWidget::mainSplitterSizes() const
|
||||
@ -1249,7 +1248,7 @@ bool DatabaseWidget::lock()
|
||||
|
||||
clipboard()->clearCopiedText();
|
||||
|
||||
if (currentMode() == DatabaseWidget::Mode::EditMode) {
|
||||
if (isEditWidgetModified()) {
|
||||
auto result = MessageBox::question(this,
|
||||
tr("Lock Database?"),
|
||||
tr("You are editing an entry. Discard changes and lock anyway?"),
|
||||
|
@ -30,6 +30,7 @@ EditWidget::EditWidget(QWidget* parent)
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
setReadOnly(false);
|
||||
setModified(false);
|
||||
|
||||
m_ui->messageWidget->setHidden(true);
|
||||
|
||||
@ -43,6 +44,7 @@ EditWidget::EditWidget(QWidget* parent)
|
||||
|
||||
connect(m_ui->buttonBox, SIGNAL(accepted()), SIGNAL(accepted()));
|
||||
connect(m_ui->buttonBox, SIGNAL(rejected()), SIGNAL(rejected()));
|
||||
connect(m_ui->buttonBox, SIGNAL(clicked(QAbstractButton*)), SLOT(buttonClicked(QAbstractButton*)));
|
||||
}
|
||||
|
||||
EditWidget::~EditWidget()
|
||||
@ -106,9 +108,6 @@ void EditWidget::setReadOnly(bool readOnly)
|
||||
m_ui->buttonBox->setStandardButtons(QDialogButtonBox::Close);
|
||||
} else {
|
||||
m_ui->buttonBox->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::Apply);
|
||||
// Find and connect the apply button
|
||||
QPushButton* applyButton = m_ui->buttonBox->button(QDialogButtonBox::Apply);
|
||||
connect(applyButton, SIGNAL(clicked()), SIGNAL(apply()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -117,6 +116,17 @@ bool EditWidget::readOnly() const
|
||||
return m_readOnly;
|
||||
}
|
||||
|
||||
void EditWidget::setModified(bool state)
|
||||
{
|
||||
m_modified = state;
|
||||
enableApplyButton(state);
|
||||
}
|
||||
|
||||
bool EditWidget::isModified() const
|
||||
{
|
||||
return m_modified;
|
||||
}
|
||||
|
||||
void EditWidget::enableApplyButton(bool enabled)
|
||||
{
|
||||
QPushButton* applyButton = m_ui->buttonBox->button(QDialogButtonBox::Apply);
|
||||
@ -125,6 +135,27 @@ void EditWidget::enableApplyButton(bool enabled)
|
||||
}
|
||||
}
|
||||
|
||||
void EditWidget::showApplyButton(bool state)
|
||||
{
|
||||
if (!m_readOnly) {
|
||||
auto buttons = m_ui->buttonBox->standardButtons();
|
||||
if (state) {
|
||||
buttons |= QDialogButtonBox::Apply;
|
||||
} else {
|
||||
buttons &= ~QDialogButtonBox::Apply;
|
||||
}
|
||||
m_ui->buttonBox->setStandardButtons(buttons);
|
||||
}
|
||||
}
|
||||
|
||||
void EditWidget::buttonClicked(QAbstractButton* button)
|
||||
{
|
||||
auto stdButton = m_ui->buttonBox->standardButton(button);
|
||||
if (stdButton == QDialogButtonBox::Apply) {
|
||||
emit apply();
|
||||
}
|
||||
}
|
||||
|
||||
void EditWidget::showMessage(const QString& text, MessageWidget::MessageType type)
|
||||
{
|
||||
// Show error messages for a longer time to make sure the user can read them
|
||||
|
@ -49,6 +49,8 @@ public:
|
||||
void setReadOnly(bool readOnly);
|
||||
bool readOnly() const;
|
||||
void enableApplyButton(bool enabled);
|
||||
void showApplyButton(bool state);
|
||||
virtual bool isModified() const;
|
||||
|
||||
signals:
|
||||
void apply();
|
||||
@ -58,10 +60,13 @@ signals:
|
||||
protected slots:
|
||||
void showMessage(const QString& text, MessageWidget::MessageType type);
|
||||
void hideMessage();
|
||||
void setModified(bool state = true);
|
||||
void buttonClicked(QAbstractButton* button);
|
||||
|
||||
private:
|
||||
const QScopedPointer<Ui::EditWidget> m_ui;
|
||||
bool m_readOnly;
|
||||
bool m_modified;
|
||||
|
||||
Q_DISABLE_COPY(EditWidget)
|
||||
};
|
||||
|
@ -276,55 +276,54 @@ void EditEntryWidget::setupHistory()
|
||||
void EditEntryWidget::setupEntryUpdate()
|
||||
{
|
||||
// Entry tab
|
||||
connect(m_mainUi->titleEdit, SIGNAL(textChanged(QString)), this, SLOT(setUnsavedChanges()));
|
||||
connect(m_mainUi->usernameEdit, SIGNAL(textChanged(QString)), this, SLOT(setUnsavedChanges()));
|
||||
connect(m_mainUi->passwordEdit, SIGNAL(textChanged(QString)), this, SLOT(setUnsavedChanges()));
|
||||
connect(m_mainUi->passwordRepeatEdit, SIGNAL(textChanged(QString)), this, SLOT(setUnsavedChanges()));
|
||||
connect(m_mainUi->urlEdit, SIGNAL(textChanged(QString)), this, SLOT(setUnsavedChanges()));
|
||||
connect(m_mainUi->titleEdit, SIGNAL(textChanged(QString)), this, SLOT(setModified()));
|
||||
connect(m_mainUi->usernameEdit, SIGNAL(textChanged(QString)), this, SLOT(setModified()));
|
||||
connect(m_mainUi->passwordEdit, SIGNAL(textChanged(QString)), this, SLOT(setModified()));
|
||||
connect(m_mainUi->passwordRepeatEdit, SIGNAL(textChanged(QString)), this, SLOT(setModified()));
|
||||
connect(m_mainUi->urlEdit, SIGNAL(textChanged(QString)), this, SLOT(setModified()));
|
||||
#ifdef WITH_XC_NETWORKING
|
||||
connect(m_mainUi->urlEdit, SIGNAL(textChanged(QString)), this, SLOT(updateFaviconButtonEnable(QString)));
|
||||
#endif
|
||||
connect(m_mainUi->expireCheck, SIGNAL(stateChanged(int)), this, SLOT(setUnsavedChanges()));
|
||||
connect(m_mainUi->notesEnabled, SIGNAL(stateChanged(int)), this, SLOT(setUnsavedChanges()));
|
||||
connect(m_mainUi->expireDatePicker, SIGNAL(dateTimeChanged(QDateTime)), this, SLOT(setUnsavedChanges()));
|
||||
connect(m_mainUi->notesEdit, SIGNAL(textChanged()), this, SLOT(setUnsavedChanges()));
|
||||
connect(m_mainUi->expireCheck, SIGNAL(stateChanged(int)), this, SLOT(setModified()));
|
||||
connect(m_mainUi->notesEnabled, SIGNAL(stateChanged(int)), this, SLOT(setModified()));
|
||||
connect(m_mainUi->expireDatePicker, SIGNAL(dateTimeChanged(QDateTime)), this, SLOT(setModified()));
|
||||
connect(m_mainUi->notesEdit, SIGNAL(textChanged()), this, SLOT(setModified()));
|
||||
|
||||
// Advanced tab
|
||||
connect(m_advancedUi->attributesEdit, SIGNAL(textChanged()), this, SLOT(setUnsavedChanges()));
|
||||
connect(m_advancedUi->protectAttributeButton, SIGNAL(stateChanged(int)), this, SLOT(setUnsavedChanges()));
|
||||
connect(m_advancedUi->fgColorCheckBox, SIGNAL(stateChanged(int)), this, SLOT(setUnsavedChanges()));
|
||||
connect(m_advancedUi->bgColorCheckBox, SIGNAL(stateChanged(int)), this, SLOT(setUnsavedChanges()));
|
||||
connect(m_advancedUi->attachmentsWidget, SIGNAL(widgetUpdated()), this, SLOT(setUnsavedChanges()));
|
||||
connect(m_advancedUi->attributesEdit, SIGNAL(textChanged()), this, SLOT(setModified()));
|
||||
connect(m_advancedUi->protectAttributeButton, SIGNAL(stateChanged(int)), this, SLOT(setModified()));
|
||||
connect(m_advancedUi->fgColorCheckBox, SIGNAL(stateChanged(int)), this, SLOT(setModified()));
|
||||
connect(m_advancedUi->bgColorCheckBox, SIGNAL(stateChanged(int)), this, SLOT(setModified()));
|
||||
connect(m_advancedUi->attachmentsWidget, SIGNAL(widgetUpdated()), this, SLOT(setModified()));
|
||||
|
||||
// Icon tab
|
||||
connect(m_iconsWidget, SIGNAL(widgetUpdated()), this, SLOT(setUnsavedChanges()));
|
||||
connect(m_iconsWidget, SIGNAL(widgetUpdated()), this, SLOT(setModified()));
|
||||
|
||||
// Auto-Type tab
|
||||
connect(m_autoTypeUi->enableButton, SIGNAL(stateChanged(int)), this, SLOT(setUnsavedChanges()));
|
||||
connect(m_autoTypeUi->customWindowSequenceButton, SIGNAL(stateChanged(int)), this, SLOT(setUnsavedChanges()));
|
||||
connect(m_autoTypeUi->inheritSequenceButton, SIGNAL(toggled(bool)), this, SLOT(setUnsavedChanges()));
|
||||
connect(m_autoTypeUi->customSequenceButton, SIGNAL(toggled(bool)), this, SLOT(setUnsavedChanges()));
|
||||
connect(m_autoTypeUi->windowSequenceEdit, SIGNAL(textChanged(QString)), this, SLOT(setUnsavedChanges()));
|
||||
connect(m_autoTypeUi->sequenceEdit, SIGNAL(textChanged(QString)), this, SLOT(setUnsavedChanges()));
|
||||
connect(m_autoTypeUi->windowTitleCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(setUnsavedChanges()));
|
||||
connect(m_autoTypeUi->windowTitleCombo, SIGNAL(editTextChanged(QString)), this, SLOT(setUnsavedChanges()));
|
||||
connect(m_autoTypeUi->enableButton, SIGNAL(stateChanged(int)), this, SLOT(setModified()));
|
||||
connect(m_autoTypeUi->customWindowSequenceButton, SIGNAL(stateChanged(int)), this, SLOT(setModified()));
|
||||
connect(m_autoTypeUi->inheritSequenceButton, SIGNAL(toggled(bool)), this, SLOT(setModified()));
|
||||
connect(m_autoTypeUi->customSequenceButton, SIGNAL(toggled(bool)), this, SLOT(setModified()));
|
||||
connect(m_autoTypeUi->windowSequenceEdit, SIGNAL(textChanged(QString)), this, SLOT(setModified()));
|
||||
connect(m_autoTypeUi->sequenceEdit, SIGNAL(textChanged(QString)), this, SLOT(setModified()));
|
||||
connect(m_autoTypeUi->windowTitleCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(setModified()));
|
||||
connect(m_autoTypeUi->windowTitleCombo, SIGNAL(editTextChanged(QString)), this, SLOT(setModified()));
|
||||
|
||||
// Properties and History tabs don't need extra connections
|
||||
|
||||
#ifdef WITH_XC_SSHAGENT
|
||||
// SSH Agent tab
|
||||
if (config()->get("SSHAgent", false).toBool()) {
|
||||
connect(m_sshAgentUi->attachmentRadioButton, SIGNAL(toggled(bool)), this, SLOT(setUnsavedChanges()));
|
||||
connect(m_sshAgentUi->externalFileRadioButton, SIGNAL(toggled(bool)), this, SLOT(setUnsavedChanges()));
|
||||
connect(m_sshAgentUi->attachmentComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(setUnsavedChanges()));
|
||||
connect(m_sshAgentUi->attachmentComboBox, SIGNAL(editTextChanged(QString)), this, SLOT(setUnsavedChanges()));
|
||||
connect(m_sshAgentUi->externalFileEdit, SIGNAL(textChanged(QString)), this, SLOT(setUnsavedChanges()));
|
||||
connect(m_sshAgentUi->addKeyToAgentCheckBox, SIGNAL(stateChanged(int)), this, SLOT(setUnsavedChanges()));
|
||||
connect(m_sshAgentUi->removeKeyFromAgentCheckBox, SIGNAL(stateChanged(int)), this, SLOT(setUnsavedChanges()));
|
||||
connect(
|
||||
m_sshAgentUi->requireUserConfirmationCheckBox, SIGNAL(stateChanged(int)), this, SLOT(setUnsavedChanges()));
|
||||
connect(m_sshAgentUi->lifetimeCheckBox, SIGNAL(stateChanged(int)), this, SLOT(setUnsavedChanges()));
|
||||
connect(m_sshAgentUi->lifetimeSpinBox, SIGNAL(valueChanged(int)), this, SLOT(setUnsavedChanges()));
|
||||
connect(m_sshAgentUi->attachmentRadioButton, SIGNAL(toggled(bool)), this, SLOT(setModified()));
|
||||
connect(m_sshAgentUi->externalFileRadioButton, SIGNAL(toggled(bool)), this, SLOT(setModified()));
|
||||
connect(m_sshAgentUi->attachmentComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(setModified()));
|
||||
connect(m_sshAgentUi->attachmentComboBox, SIGNAL(editTextChanged(QString)), this, SLOT(setModified()));
|
||||
connect(m_sshAgentUi->externalFileEdit, SIGNAL(textChanged(QString)), this, SLOT(setModified()));
|
||||
connect(m_sshAgentUi->addKeyToAgentCheckBox, SIGNAL(stateChanged(int)), this, SLOT(setModified()));
|
||||
connect(m_sshAgentUi->removeKeyFromAgentCheckBox, SIGNAL(stateChanged(int)), this, SLOT(setModified()));
|
||||
connect(m_sshAgentUi->requireUserConfirmationCheckBox, SIGNAL(stateChanged(int)), this, SLOT(setModified()));
|
||||
connect(m_sshAgentUi->lifetimeCheckBox, SIGNAL(stateChanged(int)), this, SLOT(setModified()));
|
||||
connect(m_sshAgentUi->lifetimeSpinBox, SIGNAL(valueChanged(int)), this, SLOT(setModified()));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -703,8 +702,10 @@ void EditEntryWidget::loadEntry(Entry* entry,
|
||||
setCurrentPage(0);
|
||||
setPageHidden(m_historyWidget, m_history || m_entry->historyItems().count() < 1);
|
||||
|
||||
// Force the user to Save/Apply/Discard new entries
|
||||
setUnsavedChanges(m_create);
|
||||
// Force the user to Save/Discard new entries
|
||||
showApplyButton(!m_create);
|
||||
|
||||
setModified(false);
|
||||
}
|
||||
|
||||
void EditEntryWidget::setForms(Entry* entry, bool restore)
|
||||
@ -881,7 +882,6 @@ bool EditEntryWidget::commitEntry()
|
||||
}
|
||||
|
||||
updateEntryData(m_entry);
|
||||
setUnsavedChanges(false);
|
||||
|
||||
if (!m_create) {
|
||||
m_entry->endUpdate();
|
||||
@ -896,6 +896,7 @@ bool EditEntryWidget::commitEntry()
|
||||
m_historyModel->setEntries(m_entry->historyItems());
|
||||
|
||||
showMessage(tr("Entry updated successfully."), MessageWidget::Positive);
|
||||
setModified(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -968,7 +969,7 @@ void EditEntryWidget::cancel()
|
||||
m_entry->setIcon(Entry::DefaultIconNumber);
|
||||
}
|
||||
|
||||
if (!m_saved) {
|
||||
if (isModified()) {
|
||||
auto result = MessageBox::question(this,
|
||||
QString(),
|
||||
tr("Entry has unsaved changes"),
|
||||
@ -980,13 +981,13 @@ void EditEntryWidget::cancel()
|
||||
}
|
||||
if (result == MessageBox::Save) {
|
||||
commitEntry();
|
||||
m_saved = true;
|
||||
setModified(false);
|
||||
}
|
||||
}
|
||||
|
||||
clear();
|
||||
|
||||
emit editFinished(m_saved);
|
||||
emit editFinished(!isModified());
|
||||
}
|
||||
|
||||
void EditEntryWidget::clear()
|
||||
@ -1008,22 +1009,6 @@ void EditEntryWidget::clear()
|
||||
hideMessage();
|
||||
}
|
||||
|
||||
bool EditEntryWidget::hasBeenModified() const
|
||||
{
|
||||
// entry has been modified if a history item is to be deleted
|
||||
if (!m_historyModel->deletedEntries().isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// check if updating the entry would modify it
|
||||
auto* entry = new Entry();
|
||||
entry->copyDataFrom(m_entry.data());
|
||||
|
||||
entry->beginUpdate();
|
||||
updateEntryData(entry);
|
||||
return entry->endUpdate();
|
||||
}
|
||||
|
||||
void EditEntryWidget::togglePasswordGeneratorButton(bool checked)
|
||||
{
|
||||
if (checked) {
|
||||
@ -1070,7 +1055,7 @@ void EditEntryWidget::insertAttribute()
|
||||
m_advancedUi->attributesView->setCurrentIndex(index);
|
||||
m_advancedUi->attributesView->edit(index);
|
||||
|
||||
setUnsavedChanges(true);
|
||||
setModified(true);
|
||||
}
|
||||
|
||||
void EditEntryWidget::editCurrentAttribute()
|
||||
@ -1081,7 +1066,7 @@ void EditEntryWidget::editCurrentAttribute()
|
||||
|
||||
if (index.isValid()) {
|
||||
m_advancedUi->attributesView->edit(index);
|
||||
setUnsavedChanges(true);
|
||||
setModified(true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1101,7 +1086,7 @@ void EditEntryWidget::removeCurrentAttribute()
|
||||
|
||||
if (result == MessageBox::Remove) {
|
||||
m_entryAttributes->remove(m_attributesModel->keyByIndex(index));
|
||||
setUnsavedChanges(true);
|
||||
setModified(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1223,7 +1208,7 @@ void EditEntryWidget::insertAutoTypeAssoc()
|
||||
m_autoTypeUi->assocView->setCurrentIndex(newIndex);
|
||||
loadCurrentAssoc(newIndex);
|
||||
m_autoTypeUi->windowTitleCombo->setFocus();
|
||||
setUnsavedChanges(true);
|
||||
setModified(true);
|
||||
}
|
||||
|
||||
void EditEntryWidget::removeAutoTypeAssoc()
|
||||
@ -1232,7 +1217,7 @@ void EditEntryWidget::removeAutoTypeAssoc()
|
||||
|
||||
if (currentIndex.isValid()) {
|
||||
m_autoTypeAssoc->remove(currentIndex.row());
|
||||
setUnsavedChanges(true);
|
||||
setModified(true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1295,7 +1280,7 @@ void EditEntryWidget::restoreHistoryEntry()
|
||||
QModelIndex index = m_sortModel->mapToSource(m_historyUi->historyView->currentIndex());
|
||||
if (index.isValid()) {
|
||||
setForms(m_historyModel->entryFromIndex(index), true);
|
||||
setUnsavedChanges(true);
|
||||
setModified(true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1309,7 +1294,7 @@ void EditEntryWidget::deleteHistoryEntry()
|
||||
} else {
|
||||
m_historyUi->deleteAllButton->setEnabled(false);
|
||||
}
|
||||
setUnsavedChanges(true);
|
||||
setModified(true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1317,7 +1302,7 @@ void EditEntryWidget::deleteAllHistoryEntries()
|
||||
{
|
||||
m_historyModel->deleteAll();
|
||||
m_historyUi->deleteAllButton->setEnabled(m_historyModel->rowCount() > 0);
|
||||
setUnsavedChanges(true);
|
||||
setModified(true);
|
||||
}
|
||||
|
||||
QMenu* EditEntryWidget::createPresetsMenu()
|
||||
@ -1370,12 +1355,6 @@ void EditEntryWidget::pickColor()
|
||||
QColor newColor = QColorDialog::getColor(oldColor);
|
||||
if (newColor.isValid()) {
|
||||
setupColorButton(isForeground, newColor);
|
||||
setUnsavedChanges(true);
|
||||
setModified(true);
|
||||
}
|
||||
}
|
||||
|
||||
void EditEntryWidget::setUnsavedChanges(bool hasUnsaved)
|
||||
{
|
||||
m_saved = !hasUnsaved;
|
||||
enableApplyButton(hasUnsaved);
|
||||
}
|
||||
|
@ -68,7 +68,6 @@ public:
|
||||
|
||||
QString entryTitle() const;
|
||||
void clear();
|
||||
bool hasBeenModified() const;
|
||||
|
||||
signals:
|
||||
void editFinished(bool accepted);
|
||||
@ -106,7 +105,6 @@ private slots:
|
||||
void useExpiryPreset(QAction* action);
|
||||
void toggleHideNotes(bool visible);
|
||||
void pickColor();
|
||||
void setUnsavedChanges(bool hasUnsaved = true);
|
||||
#ifdef WITH_XC_SSHAGENT
|
||||
void updateSSHAgent();
|
||||
void updateSSHAgentAttachment();
|
||||
@ -148,7 +146,6 @@ private:
|
||||
|
||||
bool m_create;
|
||||
bool m_history;
|
||||
bool m_saved;
|
||||
#ifdef WITH_XC_SSHAGENT
|
||||
bool m_sshAgentEnabled;
|
||||
KeeAgentSettings m_sshAgentSettings;
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "core/Metadata.h"
|
||||
#include "gui/EditWidgetIcons.h"
|
||||
#include "gui/EditWidgetProperties.h"
|
||||
#include "gui/MessageBox.h"
|
||||
|
||||
#if defined(WITH_XC_KEESHARE)
|
||||
#include "keeshare/group/EditGroupPageKeeShare.h"
|
||||
@ -46,6 +47,11 @@ public:
|
||||
editPage->assign(widget);
|
||||
}
|
||||
|
||||
QWidget* getWidget()
|
||||
{
|
||||
return widget;
|
||||
}
|
||||
|
||||
private:
|
||||
QSharedPointer<IEditGroupPage> editPage;
|
||||
QWidget* widget;
|
||||
@ -85,18 +91,38 @@ EditGroupWidget::EditGroupWidget(QWidget* parent)
|
||||
// clang-format on
|
||||
|
||||
connect(m_editGroupWidgetIcons, SIGNAL(messageEditEntryDismiss()), SLOT(hideMessage()));
|
||||
|
||||
setupModifiedTracking();
|
||||
}
|
||||
|
||||
EditGroupWidget::~EditGroupWidget()
|
||||
{
|
||||
}
|
||||
|
||||
void EditGroupWidget::setupModifiedTracking()
|
||||
{
|
||||
// Group tab
|
||||
connect(m_mainUi->editName, SIGNAL(textChanged(QString)), SLOT(setModified()));
|
||||
connect(m_mainUi->editNotes, SIGNAL(textChanged()), SLOT(setModified()));
|
||||
connect(m_mainUi->expireCheck, SIGNAL(stateChanged(int)), SLOT(setModified()));
|
||||
connect(m_mainUi->expireDatePicker, SIGNAL(dateTimeChanged(QDateTime)), SLOT(setModified()));
|
||||
connect(m_mainUi->searchComboBox, SIGNAL(currentIndexChanged(int)), SLOT(setModified()));
|
||||
connect(m_mainUi->autotypeComboBox, SIGNAL(currentIndexChanged(int)), SLOT(setModified()));
|
||||
connect(m_mainUi->autoTypeSequenceInherit, SIGNAL(toggled(bool)), SLOT(setModified()));
|
||||
connect(m_mainUi->autoTypeSequenceCustomRadio, SIGNAL(toggled(bool)), SLOT(setModified()));
|
||||
connect(m_mainUi->autoTypeSequenceCustomEdit, SIGNAL(textChanged(QString)), SLOT(setModified()));
|
||||
|
||||
// Icon tab
|
||||
connect(m_editGroupWidgetIcons, SIGNAL(widgetUpdated()), SLOT(setModified()));
|
||||
}
|
||||
|
||||
void EditGroupWidget::loadGroup(Group* group, bool create, const QSharedPointer<Database>& database)
|
||||
{
|
||||
m_group = group;
|
||||
m_db = database;
|
||||
|
||||
m_temporaryGroup.reset(group->clone(Entry::CloneNoFlags, Group::CloneNoFlags));
|
||||
connect(m_temporaryGroup->customData(), SIGNAL(customDataModified()), SLOT(setModified()));
|
||||
|
||||
if (create) {
|
||||
setHeadline(tr("Add group"));
|
||||
@ -139,6 +165,11 @@ void EditGroupWidget::loadGroup(Group* group, bool create, const QSharedPointer<
|
||||
setCurrentPage(0);
|
||||
|
||||
m_mainUi->editName->setFocus();
|
||||
|
||||
// Force the user to Save/Discard new groups
|
||||
showApplyButton(!create);
|
||||
|
||||
setModified(false);
|
||||
}
|
||||
|
||||
void EditGroupWidget::save()
|
||||
@ -180,6 +211,8 @@ void EditGroupWidget::apply()
|
||||
|
||||
// Icons add/remove are applied globally outside the transaction!
|
||||
m_group->copyDataFrom(m_temporaryGroup.data());
|
||||
|
||||
setModified(false);
|
||||
}
|
||||
|
||||
void EditGroupWidget::cancel()
|
||||
@ -188,6 +221,18 @@ void EditGroupWidget::cancel()
|
||||
m_group->setIcon(Entry::DefaultIconNumber);
|
||||
}
|
||||
|
||||
if (isModified()) {
|
||||
auto result = MessageBox::question(this,
|
||||
QString(),
|
||||
tr("Entry has unsaved changes"),
|
||||
MessageBox::Cancel | MessageBox::Save | MessageBox::Discard,
|
||||
MessageBox::Cancel);
|
||||
if (result == MessageBox::Save) {
|
||||
apply();
|
||||
setModified(false);
|
||||
}
|
||||
}
|
||||
|
||||
clear();
|
||||
emit editFinished(false);
|
||||
}
|
||||
|
@ -74,6 +74,7 @@ private:
|
||||
void addTriStateItems(QComboBox* comboBox, bool inheritValue);
|
||||
int indexFromTriState(Group::TriState triState);
|
||||
Group::TriState triStateFromIndex(int index);
|
||||
void setupModifiedTracking();
|
||||
|
||||
const QScopedPointer<Ui::EditGroupWidgetMain> m_mainUi;
|
||||
|
||||
|
@ -429,13 +429,20 @@ void TestGui::testEditEntry()
|
||||
auto* titleEdit = editEntryWidget->findChild<QLineEdit*>("titleEdit");
|
||||
QTest::keyClicks(titleEdit, "_test");
|
||||
|
||||
// Apply the edit
|
||||
auto* editEntryWidgetButtonBox = editEntryWidget->findChild<QDialogButtonBox*>("buttonBox");
|
||||
QVERIFY(editEntryWidgetButtonBox);
|
||||
QTest::mouseClick(editEntryWidgetButtonBox->button(QDialogButtonBox::Apply), Qt::LeftButton);
|
||||
auto* okButton = editEntryWidgetButtonBox->button(QDialogButtonBox::Ok);
|
||||
QVERIFY(okButton);
|
||||
auto* applyButton = editEntryWidgetButtonBox->button(QDialogButtonBox::Apply);
|
||||
QVERIFY(applyButton);
|
||||
|
||||
// Apply the edit
|
||||
QTRY_VERIFY(applyButton->isEnabled());
|
||||
QTest::mouseClick(applyButton, Qt::LeftButton);
|
||||
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode);
|
||||
QCOMPARE(entry->title(), QString("Sample Entry_test"));
|
||||
QCOMPARE(entry->historyItems().size(), ++editCount);
|
||||
QVERIFY(!applyButton->isEnabled());
|
||||
|
||||
// Test entry colors (simulate choosing a color)
|
||||
editEntryWidget->setCurrentPage(1);
|
||||
@ -451,7 +458,7 @@ void TestGui::testEditEntry()
|
||||
colorCheckBox = editEntryWidget->findChild<QCheckBox*>("bgColorCheckBox");
|
||||
colorButton->setProperty("color", bgColor);
|
||||
colorCheckBox->setChecked(true);
|
||||
QTest::mouseClick(editEntryWidgetButtonBox->button(QDialogButtonBox::Apply), Qt::LeftButton);
|
||||
QTest::mouseClick(applyButton, Qt::LeftButton);
|
||||
QCOMPARE(entry->historyItems().size(), ++editCount);
|
||||
|
||||
// Test protected attributes
|
||||
@ -471,7 +478,7 @@ void TestGui::testEditEntry()
|
||||
auto* passwordEdit = editEntryWidget->findChild<QLineEdit*>("passwordEdit");
|
||||
QString originalPassword = passwordEdit->text();
|
||||
passwordEdit->setText("newpass");
|
||||
QTest::mouseClick(editEntryWidgetButtonBox->button(QDialogButtonBox::Ok), Qt::LeftButton);
|
||||
QTest::mouseClick(okButton, Qt::LeftButton);
|
||||
auto* messageWiget = editEntryWidget->findChild<MessageWidget*>("messageWidget");
|
||||
QTRY_VERIFY(messageWiget->isVisible());
|
||||
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode);
|
||||
@ -479,7 +486,7 @@ void TestGui::testEditEntry()
|
||||
passwordEdit->setText(originalPassword);
|
||||
|
||||
// Save the edit (press OK)
|
||||
QTest::mouseClick(editEntryWidgetButtonBox->button(QDialogButtonBox::Ok), Qt::LeftButton);
|
||||
QTest::mouseClick(okButton, Qt::LeftButton);
|
||||
QApplication::processEvents();
|
||||
|
||||
// Confirm edit was made
|
||||
@ -496,13 +503,15 @@ void TestGui::testEditEntry()
|
||||
|
||||
// Test copy & paste newline sanitization
|
||||
QTest::mouseClick(entryEditWidget, Qt::LeftButton);
|
||||
okButton = editEntryWidgetButtonBox->button(QDialogButtonBox::Ok);
|
||||
QVERIFY(okButton);
|
||||
QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode);
|
||||
titleEdit->setText("multiline\ntitle");
|
||||
editEntryWidget->findChild<QLineEdit*>("usernameEdit")->setText("multiline\nusername");
|
||||
editEntryWidget->findChild<QLineEdit*>("passwordEdit")->setText("multiline\npassword");
|
||||
editEntryWidget->findChild<QLineEdit*>("passwordRepeatEdit")->setText("multiline\npassword");
|
||||
editEntryWidget->findChild<QLineEdit*>("urlEdit")->setText("multiline\nurl");
|
||||
QTest::mouseClick(editEntryWidgetButtonBox->button(QDialogButtonBox::Ok), Qt::LeftButton);
|
||||
QTest::mouseClick(okButton, Qt::LeftButton);
|
||||
|
||||
QCOMPARE(entry->title(), QString("multiline title"));
|
||||
QCOMPARE(entry->username(), QString("multiline username"));
|
||||
|
Loading…
Reference in New Issue
Block a user