From fbefe34c306b9d2d8587e774eb586c83224be50f Mon Sep 17 00:00:00 2001 From: Chris Xiong Date: Mon, 26 Sep 2022 02:07:15 -0400 Subject: Add proper quit confirmation. --- qdeduper/mingui.cpp | 30 +++++++++++++++++++++++++----- qdeduper/mingui.hpp | 2 ++ qdeduper/sigdb_qt.cpp | 5 +++++ qdeduper/sigdb_qt.hpp | 1 + xsig/include/signature_db.hpp | 5 +++++ xsig/src/signature_db.cpp | 13 +++++++++++++ 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> paths) QObject::connect(fw, &QFutureWatcher::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::vectorsdb || !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 &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 &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 &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(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; } -- cgit v1.2.3