mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2025-09-27 20:01:28 -04:00
Add auto-save delay per database (#9100)
Add a new propery autosaveDelay in Metadata of the db. The property is saved in customData to not affect database structure as this setting is unique to keepasxc. The propery sets delay to wait since last modification before saving. Co-authored-by: jNullj <jNullj@users.noreply.github.com>
This commit is contained in:
parent
a0874a0d6d
commit
35baeaff79
10 changed files with 272 additions and 6 deletions
|
@ -28,10 +28,17 @@
|
|||
|
||||
const int Metadata::DefaultHistoryMaxItems = 10;
|
||||
const int Metadata::DefaultHistoryMaxSize = 6 * 1024 * 1024;
|
||||
const int Metadata::DefaultAutosaveDelayMin = 0;
|
||||
|
||||
// Fallback icon for return by reference
|
||||
static const Metadata::CustomIconData NULL_ICON{};
|
||||
|
||||
namespace customDataKeys
|
||||
{
|
||||
static const QString savedSearch = QStringLiteral("KPXC_SavedSearch");
|
||||
static const QString autosaveDelay = QStringLiteral("KPXC_autosaveDelayMin");
|
||||
}; // namespace customDataKeys
|
||||
|
||||
Metadata::Metadata(QObject* parent)
|
||||
: ModifiableObject(parent)
|
||||
, m_customData(new CustomData(this))
|
||||
|
@ -265,6 +272,19 @@ int Metadata::historyMaxSize() const
|
|||
return m_data.historyMaxSize;
|
||||
}
|
||||
|
||||
int Metadata::autosaveDelayMin() const
|
||||
{
|
||||
QString autosaveDelayMinStr = m_customData->value(customDataKeys::autosaveDelay);
|
||||
if (autosaveDelayMinStr.isNull()) {
|
||||
// data is not set yet, use default
|
||||
return Metadata::DefaultAutosaveDelayMin;
|
||||
}
|
||||
bool ok; // check for QString to int op failuer
|
||||
int autosaveDelayMin = autosaveDelayMinStr.toInt(&ok);
|
||||
Q_ASSERT(ok);
|
||||
return autosaveDelayMin;
|
||||
}
|
||||
|
||||
CustomData* Metadata::customData()
|
||||
{
|
||||
return m_customData;
|
||||
|
@ -478,6 +498,12 @@ void Metadata::setHistoryMaxSize(int value)
|
|||
set(m_data.historyMaxSize, value);
|
||||
}
|
||||
|
||||
void Metadata::setAutosaveDelayMin(int value)
|
||||
{
|
||||
Q_ASSERT(value >= 0 && value <= 420000000);
|
||||
m_customData->set(customDataKeys::autosaveDelay, QString::number(value));
|
||||
}
|
||||
|
||||
QDateTime Metadata::settingsChanged() const
|
||||
{
|
||||
return m_settingsChanged;
|
||||
|
@ -494,7 +520,7 @@ void Metadata::addSavedSearch(const QString& name, const QString& searchtext)
|
|||
auto searches = savedSearches();
|
||||
searches.insert(name, searchtext);
|
||||
auto json = QJsonDocument::fromVariant(searches);
|
||||
m_customData->set("KPXC_SavedSearch", json.toJson());
|
||||
m_customData->set(customDataKeys::savedSearch, json.toJson());
|
||||
}
|
||||
|
||||
void Metadata::deleteSavedSearch(const QString& name)
|
||||
|
@ -502,12 +528,12 @@ void Metadata::deleteSavedSearch(const QString& name)
|
|||
auto searches = savedSearches();
|
||||
searches.remove(name);
|
||||
auto json = QJsonDocument::fromVariant(searches);
|
||||
m_customData->set("KPXC_SavedSearch", json.toJson());
|
||||
m_customData->set(customDataKeys::savedSearch, json.toJson());
|
||||
}
|
||||
|
||||
QVariantMap Metadata::savedSearches()
|
||||
{
|
||||
auto searches = m_customData->value("KPXC_SavedSearch");
|
||||
auto searches = m_customData->value(customDataKeys::savedSearch);
|
||||
auto json = QJsonDocument::fromJson(searches.toUtf8());
|
||||
return json.toVariant().toMap();
|
||||
}
|
||||
|
|
|
@ -109,11 +109,13 @@ public:
|
|||
int databaseKeyChangeForce() const;
|
||||
int historyMaxItems() const;
|
||||
int historyMaxSize() const;
|
||||
int autosaveDelayMin() const;
|
||||
CustomData* customData();
|
||||
const CustomData* customData() const;
|
||||
|
||||
static const int DefaultHistoryMaxItems;
|
||||
static const int DefaultHistoryMaxSize;
|
||||
static const int DefaultAutosaveDelayMin;
|
||||
|
||||
void setGenerator(const QString& value);
|
||||
void setName(const QString& value);
|
||||
|
@ -150,6 +152,7 @@ public:
|
|||
void setMasterKeyChangeForce(int value);
|
||||
void setHistoryMaxItems(int value);
|
||||
void setHistoryMaxSize(int value);
|
||||
void setAutosaveDelayMin(int value);
|
||||
void setUpdateDatetime(bool value);
|
||||
void addSavedSearch(const QString& name, const QString& searchtext);
|
||||
void deleteSavedSearch(const QString& name);
|
||||
|
|
|
@ -222,6 +222,10 @@ DatabaseWidget::DatabaseWidget(QSharedPointer<Database> db, QWidget* parent)
|
|||
|
||||
m_blockAutoSave = false;
|
||||
|
||||
m_autosaveTimer = new QTimer(this);
|
||||
m_autosaveTimer->setSingleShot(true);
|
||||
connect(m_autosaveTimer, SIGNAL(timeout()), this, SLOT(onAutosaveDelayTimeout()));
|
||||
|
||||
m_searchLimitGroup = config()->get(Config::SearchLimitGroup).toBool();
|
||||
|
||||
#ifdef WITH_XC_KEESHARE
|
||||
|
@ -1528,13 +1532,42 @@ void DatabaseWidget::onGroupChanged()
|
|||
|
||||
void DatabaseWidget::onDatabaseModified()
|
||||
{
|
||||
if (!m_blockAutoSave && config()->get(Config::AutoSaveAfterEveryChange).toBool()) {
|
||||
refreshSearch();
|
||||
int autosaveDelayMs = m_db->metadata()->autosaveDelayMin() * 60 * 1000; // min to msec for QTimer
|
||||
bool autosaveAfterEveryChangeConfig = config()->get(Config::AutoSaveAfterEveryChange).toBool();
|
||||
if (autosaveDelayMs > 0 && autosaveAfterEveryChangeConfig) {
|
||||
// reset delay when modified
|
||||
m_autosaveTimer->start(autosaveDelayMs);
|
||||
return;
|
||||
}
|
||||
if (!m_blockAutoSave && autosaveAfterEveryChangeConfig) {
|
||||
save();
|
||||
} else {
|
||||
// Only block once, then reset
|
||||
m_blockAutoSave = false;
|
||||
}
|
||||
refreshSearch();
|
||||
}
|
||||
|
||||
void DatabaseWidget::onAutosaveDelayTimeout()
|
||||
{
|
||||
const bool isAutosaveDelayEnabled = m_db->metadata()->autosaveDelayMin() > 0;
|
||||
const bool autosaveAfterEveryChangeConfig = config()->get(Config::AutoSaveAfterEveryChange).toBool();
|
||||
if (!(isAutosaveDelayEnabled && autosaveAfterEveryChangeConfig)) {
|
||||
// User might disable the delay/autosave while the timer is running
|
||||
return;
|
||||
}
|
||||
if (!m_blockAutoSave) {
|
||||
save();
|
||||
} else {
|
||||
// Only block once, then reset
|
||||
m_blockAutoSave = false;
|
||||
}
|
||||
}
|
||||
|
||||
void DatabaseWidget::triggerAutosaveTimer()
|
||||
{
|
||||
m_autosaveTimer->stop();
|
||||
QMetaObject::invokeMethod(m_autosaveTimer, "timeout");
|
||||
}
|
||||
|
||||
QString DatabaseWidget::getCurrentSearch()
|
||||
|
@ -1986,6 +2019,7 @@ bool DatabaseWidget::save()
|
|||
if (performSave(errorMessage)) {
|
||||
m_saveAttempts = 0;
|
||||
m_blockAutoSave = false;
|
||||
m_autosaveTimer->stop(); // stop autosave delay to avoid triggering another save
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -233,6 +233,7 @@ public slots:
|
|||
int autoHideTimeout = MessageWidget::DefaultAutoHideTimeout);
|
||||
void showErrorMessage(const QString& errorMessage);
|
||||
void hideMessage();
|
||||
void triggerAutosaveTimer();
|
||||
|
||||
protected:
|
||||
void closeEvent(QCloseEvent* event) override;
|
||||
|
@ -251,6 +252,7 @@ private slots:
|
|||
void onEntryChanged(Entry* entry);
|
||||
void onGroupChanged();
|
||||
void onDatabaseModified();
|
||||
void onAutosaveDelayTimeout();
|
||||
void connectDatabaseSignals();
|
||||
void loadDatabase(bool accepted);
|
||||
void unlockDatabase(bool accepted);
|
||||
|
@ -309,6 +311,9 @@ private:
|
|||
// Autoreload
|
||||
bool m_blockAutoSave;
|
||||
|
||||
// Autosave delay
|
||||
QPointer<QTimer> m_autosaveTimer;
|
||||
|
||||
// Auto-Type related
|
||||
QString m_searchStringForAutoType;
|
||||
};
|
||||
|
|
|
@ -31,6 +31,7 @@ DatabaseSettingsWidgetGeneral::DatabaseSettingsWidgetGeneral(QWidget* parent)
|
|||
|
||||
connect(m_ui->historyMaxItemsCheckBox, SIGNAL(toggled(bool)), m_ui->historyMaxItemsSpinBox, SLOT(setEnabled(bool)));
|
||||
connect(m_ui->historyMaxSizeCheckBox, SIGNAL(toggled(bool)), m_ui->historyMaxSizeSpinBox, SLOT(setEnabled(bool)));
|
||||
connect(m_ui->autosaveDelayCheckBox, SIGNAL(toggled(bool)), m_ui->autosaveDelaySpinBox, SLOT(setEnabled(bool)));
|
||||
}
|
||||
|
||||
DatabaseSettingsWidgetGeneral::~DatabaseSettingsWidgetGeneral() = default;
|
||||
|
@ -62,6 +63,13 @@ void DatabaseSettingsWidgetGeneral::initialize()
|
|||
m_ui->historyMaxSizeSpinBox->setEnabled(false);
|
||||
m_ui->historyMaxSizeCheckBox->setChecked(false);
|
||||
}
|
||||
if (meta->autosaveDelayMin() > 0) {
|
||||
m_ui->autosaveDelaySpinBox->setValue(meta->autosaveDelayMin());
|
||||
m_ui->autosaveDelayCheckBox->setChecked(true);
|
||||
} else {
|
||||
m_ui->autosaveDelayCheckBox->setChecked(false);
|
||||
m_ui->autosaveDelaySpinBox->setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
void DatabaseSettingsWidgetGeneral::uninitialize()
|
||||
|
@ -132,6 +140,12 @@ bool DatabaseSettingsWidgetGeneral::save()
|
|||
truncate = true;
|
||||
}
|
||||
|
||||
int autosaveDelayMin = 0;
|
||||
if (m_ui->autosaveDelayCheckBox->isChecked()) {
|
||||
autosaveDelayMin = m_ui->autosaveDelaySpinBox->value();
|
||||
}
|
||||
meta->setAutosaveDelayMin(autosaveDelayMin);
|
||||
|
||||
if (truncate) {
|
||||
const QList<Entry*> allEntries = m_db->rootGroup()->entriesRecursive(false);
|
||||
for (Entry* entry : allEntries) {
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>453</width>
|
||||
<height>374</height>
|
||||
<height>394</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
|
@ -202,6 +202,58 @@ removed from the database.</string>
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="autosaveDelayCheckBox">
|
||||
<property name="toolTip">
|
||||
<string>Autosave delay since last change</string>
|
||||
</property>
|
||||
<property name="accessibleName">
|
||||
<string>Autosave delay since last change checkbox</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Autosave delay</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="autosaveDelaySpinBox">
|
||||
<property name="toolTip">
|
||||
<string>Autosave delay since last change in minutes</string>
|
||||
</property>
|
||||
<property name="accessibleName">
|
||||
<string>Autosave delay since last change in minutes</string>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string> min</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>420000000</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>5</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue