aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Chris Xiong <chirs241097@gmail.com> 2022-09-26 02:07:15 -0400
committerGravatar Chris Xiong <chirs241097@gmail.com> 2022-09-26 02:07:15 -0400
commitfbefe34c306b9d2d8587e774eb586c83224be50f (patch)
treea9632e4cf69107dc645527105426155346dcaf01
parent109a9c0130a024030a651aec7979fed283ec5bb7 (diff)
downloaddeduper-fbefe34c306b9d2d8587e774eb586c83224be50f.tar.xz
Add proper quit confirmation.
-rw-r--r--qdeduper/mingui.cpp30
-rw-r--r--qdeduper/mingui.hpp2
-rw-r--r--qdeduper/sigdb_qt.cpp5
-rw-r--r--qdeduper/sigdb_qt.hpp1
-rw-r--r--xsig/include/signature_db.hpp5
-rw-r--r--xsig/src/signature_db.cpp13
6 files changed, 51 insertions, 5 deletions
diff --git a/qdeduper/mingui.cpp b/qdeduper/mingui.cpp
index f17374e..2d38a24 100644
--- a/qdeduper/mingui.cpp
+++ b/qdeduper/mingui.cpp
@@ -226,6 +226,7 @@ void DeduperMainWindow::setup_menu()
}
curgroup = 0;
show_group(0);
+ this->markschanged = false;
fw->deleteLater();
}, Qt::ConnectionType::QueuedConnection);
}
@@ -265,7 +266,11 @@ void DeduperMainWindow::setup_menu()
menuact["search_image"] = search_img;
file->addSeparator();
file->addAction("Preferences...");
- file->addAction("Exit");
+ QAction *exita = file->addAction("Exit");
+ QObject::connect(exita, &QAction::triggered, [this] {
+ if (this->quit_check()) qApp->quit();
+ });
+ menuact["exit"] = exita;
QAction *nxtgrp = view->addAction("Next Group");
nxtgrp->setIcon(this->style()->standardIcon(QStyle::StandardPixmap::SP_ArrowRight));
@@ -577,6 +582,7 @@ void DeduperMainWindow::save_list()
for (auto &x : this->marked)
fst << x.native() << std::endl;
fst.close();
+ this->markschanged = false;
}
void DeduperMainWindow::load_list()
@@ -603,6 +609,7 @@ void DeduperMainWindow::load_list()
im->item(i)->setCheckState(marked.find(p) != marked.end() ? Qt::CheckState::Checked : Qt::CheckState::Unchecked);
}
marked_update();
+ this->markschanged = false;
}
void DeduperMainWindow::create_new()
@@ -678,6 +685,7 @@ void DeduperMainWindow::scan_dirs(std::vector<std::pair<fs::path, bool>> paths)
QObject::connect(fw, &QFutureWatcher<void>::finished, this, [this, fw] {
this->pd->reset();
this->pd->close();
+ this->markschanged = false;
this->curgroup = 0;
this->vm = ViewMode::view_normal;
this->show_group(this->curgroup);
@@ -741,6 +749,7 @@ void DeduperMainWindow::mark_toggle(size_t x)
im->item(x)->setCheckState(ckst);
}
marked_update();
+ this->markschanged = true;
}
void DeduperMainWindow::mark_all_but(size_t x)
@@ -760,6 +769,7 @@ void DeduperMainWindow::mark_all_but(size_t x)
}
}
marked_update();
+ this->markschanged = true;
}
void DeduperMainWindow::mark_all()
@@ -773,6 +783,7 @@ void DeduperMainWindow::mark_all()
for (int i = 0; i < im->rowCount(); ++i)
im->item(i)->setCheckState(Qt::CheckState::Checked);
marked_update();
+ this->markschanged = true;
}
void DeduperMainWindow::mark_none(bool msg)
@@ -780,6 +791,7 @@ void DeduperMainWindow::mark_none(bool msg)
for (int i = 0; i < im->rowCount(); ++i)
im->item(i)->setCheckState(Qt::CheckState::Unchecked);
marked_update(msg);
+ this->markschanged = true;
}
void DeduperMainWindow::marked_update(bool update_msg)
@@ -823,12 +835,20 @@ fs::path::string_type DeduperMainWindow::common_prefix(const std::vector<fs::pat
return ret;
}
+bool DeduperMainWindow::quit_check()
+{
+ if (!this->sdb || !this->sdb->valid()) return true;
+ if (this->markschanged || this->sdb->is_dirty())
+ return QMessageBox::StandardButton::Yes ==
+ QMessageBox::question(this, "Confirmation", "You have unsaved files list or database. Really quit?",
+ QMessageBox::StandardButton::Yes | QMessageBox::StandardButton::No,
+ QMessageBox::StandardButton::No);
+ return true;
+}
+
void DeduperMainWindow::closeEvent(QCloseEvent *e)
{
- if (QMessageBox::StandardButton::Yes ==
- QMessageBox::question(this, "Confirmation", "Really quit?",
- QMessageBox::StandardButton::Yes | QMessageBox::StandardButton::No,
- QMessageBox::StandardButton::No))
+ if (quit_check())
e->accept();
else
e->ignore();
diff --git a/qdeduper/mingui.hpp b/qdeduper/mingui.hpp
index abc514d..3803eb7 100644
--- a/qdeduper/mingui.hpp
+++ b/qdeduper/mingui.hpp
@@ -59,6 +59,7 @@ private:
fs::path searched_image;
ViewMode vm;
bool nohotkeywarn;
+ bool markschanged;
void mark_toggle(size_t x);
void mark_all_but(size_t x);
@@ -66,6 +67,7 @@ private:
void mark_none(bool msg = true);
void marked_update(bool update_msg = true);
fs::path::string_type common_prefix(const std::vector<fs::path> &fns);
+ bool quit_check();
protected:
void closeEvent(QCloseEvent *e) override;
bool eventFilter(QObject *obj, QEvent *ev) override;
diff --git a/qdeduper/sigdb_qt.cpp b/qdeduper/sigdb_qt.cpp
index 4609245..a67f330 100644
--- a/qdeduper/sigdb_qt.cpp
+++ b/qdeduper/sigdb_qt.cpp
@@ -77,6 +77,11 @@ bool SignatureDB::valid()
return sdb->valid();
}
+bool SignatureDB::is_dirty()
+{
+ return sdb->is_dirty();
+}
+
void SignatureDB::scan_files(const std::vector<fs::path> &files, int njobs)
{
populate_cfg_t pcfg = {
diff --git a/qdeduper/sigdb_qt.hpp b/qdeduper/sigdb_qt.hpp
index 66159fd..1672915 100644
--- a/qdeduper/sigdb_qt.hpp
+++ b/qdeduper/sigdb_qt.hpp
@@ -30,6 +30,7 @@ public:
~SignatureDB();
bool valid();
+ bool is_dirty();
void scan_files(const std::vector<fs::path> &files, int njobs);
void interrupt_scan();
diff --git a/xsig/include/signature_db.hpp b/xsig/include/signature_db.hpp
index 9b14fbb..23e3aae 100644
--- a/xsig/include/signature_db.hpp
+++ b/xsig/include/signature_db.hpp
@@ -45,7 +45,12 @@ public:
signature_db(const fs::path &dbpath = fs::path());
~signature_db();
+ //true if db is valid, false if not.
+ //only useful when opening an existing db file
bool valid();
+ //true if db has changes that are not written to disk, false otherwise
+ //always true if db is not in RAM.
+ bool is_dirty();
//insert image signature into database
//if id is omitted, it's assigned automatically and returned
diff --git a/xsig/src/signature_db.cpp b/xsig/src/signature_db.cpp
index 5396d1d..3c4187b 100644
--- a/xsig/src/signature_db.cpp
+++ b/xsig/src/signature_db.cpp
@@ -30,6 +30,9 @@ struct signature_db_priv
sqlite3_stmt *bst[batch_status::BATCH_STATUS_MAX];
thread_pool *tp;
+ bool dirty;
+ bool ramdb;
+
void init_db();
bool verify_db();
@@ -38,6 +41,7 @@ struct signature_db_priv
void signature_db_priv::init_db()
{
+ dirty = true;
sqlite3_exec(db, R"sql(
create table sigdbinfo(
version int
@@ -110,6 +114,7 @@ signature_db::signature_db(const fs::path &dbpath)
{
sqlite3_open(":memory:", &p->db);
p->init_db();
+ p->ramdb = true;
}
else
{
@@ -120,6 +125,7 @@ signature_db::signature_db(const fs::path &dbpath)
sqlite3_open(dbpath.c_str(), &p->db);
#endif
if (need_init) p->init_db();
+ p->ramdb = false;
}
p->mtx = sqlite3_db_mutex(p->db);
@@ -151,10 +157,13 @@ signature_db::~signature_db()
bool signature_db::valid()
{ return static_cast<bool>(p->db); }
+bool signature_db::is_dirty()
+{ return p->ramdb && p->dirty; }
size_t signature_db::put_signature(const fs::path &path, const signature &sig,size_t id)
{
if (!p->db) [[ unlikely ]] return ~size_t(0);
+ p->dirty = true;
sqlite3_stmt *st;
std::string sigs = sig.to_string();
sqlite3_prepare_v2(p->db, "insert into images (id, path, signature) values(?, ?, ?);", -1, &st, 0);
@@ -242,6 +251,7 @@ void signature_db::batch_put_subslice_begin()
void signature_db::put_subslice(size_t id, size_t slice, const signature &slicesig)
{
if (!p->db) [[ unlikely ]] return;
+ p->dirty = true;
sqlite3_stmt *st = nullptr;
if (p->bst[batch_status::putsub])
st = p->bst[batch_status::putsub];
@@ -305,6 +315,7 @@ void signature_db::batch_find_subslice_end()
void signature_db::put_dupe_pair(size_t ida, size_t idb, double dist)
{
if (!p->db) [[ unlikely ]] return;
+ p->dirty = true;
sqlite3_stmt *st = nullptr;
sqlite3_prepare_v2(p->db, "insert into dupes (id1, id2, dist) values(?, ?, ?);", -1, &st, 0);
sqlite3_bind_int(st, 1, ida);
@@ -366,6 +377,7 @@ bool signature_db::to_db_file(const fs::path &path)
}
ret &= (SQLITE_OK == sqlite3_backup_finish(bk));
ret &= (SQLITE_OK == sqlite3_close(dest));
+ if (ret) p->dirty = false;
return ret;
}
bool signature_db::from_db_file(const fs::path &path)
@@ -390,6 +402,7 @@ bool signature_db::from_db_file(const fs::path &path)
}
ret &= (SQLITE_OK == sqlite3_backup_finish(bk));
ret &= (SQLITE_OK == sqlite3_close(src));
+ if (ret) p->dirty = false;
return ret;
}