keepassxc/src/gui/entry/EditEntryWidget.h
Daniel Wilches 78ef6f0d04 Grey out Apply button when there are no changes
Resolves #1313

What this commit does:
* Whenever the Apply button is pressed, and if the save was successful, then the Apply button is disabled.
* Each subwidget used by EditEntryWidget has now a signal called `widgetUpdated` that is emitted when the widgets' internal content changes. The EditEntryWidget subscribes to that signal to know when to enable the Apply button (by calling `entryUpdated()`).
* There are some views that are not isolated in their own widgets (`m_advancedUi`, for example) so in those cases I invoked `entryUpdated()` directly whenever I detected an update:
  * some updates occur directly in a Qt widget like when editing the text of a QLineItem, so in that case I connected the widget's signals directly to the `entryUpdated()` slot.
  * some updates occur in EditEntryWidget, so in those cases the invocation to `entryUpdated()` is made as soon as the change is detected (for example when the user has confirmed an action in a dialog).

A known problem: there are some situations when the Apply button will get enabled even if there are no changes, this is because the app changes the value of a field by itself so it's considered an update (for example, clicking on the "Reveal" button changes the text shown in a text field).
The solution to this can be a bit complicated: disabling temporarily the `entryUpdated()` whenever the app is going to do an action with such side-effects.
So I preferred to let the Apply button get enabled in those cases.
2018-03-29 18:35:08 -07:00

175 lines
5.4 KiB
C++

/*
* Copyright (C) 2010 Felix Geyer <debfx@fobos.de>
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 or (at your option)
* version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef KEEPASSX_EDITENTRYWIDGET_H
#define KEEPASSX_EDITENTRYWIDGET_H
#include <QModelIndex>
#include <QScopedPointer>
#include "gui/EditWidget.h"
#include "config-keepassx.h"
class AutoTypeAssociations;
class AutoTypeAssociationsModel;
class Database;
class EditWidgetIcons;
class EditWidgetProperties;
class Entry;
class EntryAttributes;
class EntryAttributesModel;
class EntryHistoryModel;
class QButtonGroup;
class QMenu;
class QSortFilterProxyModel;
class QStackedLayout;
#ifdef WITH_XC_SSHAGENT
#include "sshagent/KeeAgentSettings.h"
class OpenSSHKey;
#endif
namespace Ui {
class EditEntryWidgetAdvanced;
class EditEntryWidgetAutoType;
class EditEntryWidgetSSHAgent;
class EditEntryWidgetMain;
class EditEntryWidgetHistory;
class EditWidget;
}
class EditEntryWidget : public EditWidget
{
Q_OBJECT
public:
explicit EditEntryWidget(QWidget* parent = nullptr);
~EditEntryWidget();
void loadEntry(Entry* entry, bool create, bool history, const QString& parentName,
Database* database);
void createPresetsMenu(QMenu* expirePresetsMenu);
QString entryTitle() const;
void clear();
bool hasBeenModified() const;
signals:
void editFinished(bool accepted);
void historyEntryActivated(Entry* entry);
private slots:
void acceptEntry();
bool commitEntry();
void cancel();
void togglePasswordGeneratorButton(bool checked);
void setGeneratedPassword(const QString& password);
void insertAttribute();
void editCurrentAttribute();
void removeCurrentAttribute();
void updateCurrentAttribute();
void protectCurrentAttribute(bool state);
void revealCurrentAttribute();
void updateAutoTypeEnabled();
void insertAutoTypeAssoc();
void removeAutoTypeAssoc();
void loadCurrentAssoc(const QModelIndex& current);
void clearCurrentAssoc();
void applyCurrentAssoc();
void showHistoryEntry();
void restoreHistoryEntry();
void deleteHistoryEntry();
void deleteAllHistoryEntries();
void emitHistoryEntryActivated(const QModelIndex& index);
void histEntryActivated(const QModelIndex& index);
void updateHistoryButtons(const QModelIndex& current, const QModelIndex& previous);
void useExpiryPreset(QAction* action);
void toggleHideNotes(bool visible);
void pickColor();
void setUnsavedChanges(bool hasUnsaved = true);
#ifdef WITH_XC_SSHAGENT
void updateSSHAgent();
void updateSSHAgentAttachment();
void updateSSHAgentAttachments();
void updateSSHAgentKeyInfo();
void browsePrivateKey();
void addKeyToAgent();
void removeKeyFromAgent();
void decryptPrivateKey();
void copyPublicKey();
#endif
private:
void setupMain();
void setupAdvanced();
void setupIcon();
void setupAutoType();
#ifdef WITH_XC_SSHAGENT
void setupSSHAgent();
#endif
void setupProperties();
void setupHistory();
void setupEntryUpdate();
void setupColorButton(bool foreground, const QColor& color);
bool passwordsEqual();
void setForms(const Entry* entry, bool restore = false);
QMenu* createPresetsMenu();
void updateEntryData(Entry* entry) const;
#ifdef WITH_XC_SSHAGENT
bool getOpenSSHKey(OpenSSHKey& key, bool decrypt = false);
void saveSSHAgentConfig();
#endif
void displayAttribute(QModelIndex index, bool showProtected);
Entry* m_entry;
Database* m_database;
bool m_create;
bool m_history;
bool m_saved;
#ifdef WITH_XC_SSHAGENT
bool m_sshAgentEnabled;
KeeAgentSettings m_sshAgentSettings;
#endif
const QScopedPointer<Ui::EditEntryWidgetMain> m_mainUi;
const QScopedPointer<Ui::EditEntryWidgetAdvanced> m_advancedUi;
const QScopedPointer<Ui::EditEntryWidgetAutoType> m_autoTypeUi;
const QScopedPointer<Ui::EditEntryWidgetSSHAgent> m_sshAgentUi;
const QScopedPointer<Ui::EditEntryWidgetHistory> m_historyUi;
QWidget* const m_mainWidget;
QWidget* const m_advancedWidget;
EditWidgetIcons* const m_iconsWidget;
QWidget* const m_autoTypeWidget;
QWidget* const m_sshAgentWidget;
EditWidgetProperties* const m_editWidgetProperties;
QWidget* const m_historyWidget;
EntryAttributes* const m_entryAttributes;
EntryAttributesModel* const m_attributesModel;
EntryHistoryModel* const m_historyModel;
QSortFilterProxyModel* const m_sortModel;
QPersistentModelIndex m_currentAttribute;
AutoTypeAssociations* const m_autoTypeAssoc;
AutoTypeAssociationsModel* const m_autoTypeAssocModel;
QButtonGroup* const m_autoTypeDefaultSequenceGroup;
QButtonGroup* const m_autoTypeWindowSequenceGroup;
Q_DISABLE_COPY(EditEntryWidget)
};
#endif // KEEPASSX_EDITENTRYWIDGET_H