From a9318910a6d21747d7f8d85bdb08ec78611ca904 Mon Sep 17 00:00:00 2001 From: Chris Xiong Date: Sun, 25 Sep 2022 19:05:48 -0400 Subject: Add sorting. --- qdeduper/imageitem.cpp | 6 +++ qdeduper/imageitem.hpp | 4 +- qdeduper/mingui.cpp | 129 ++++++++++++++++++++++++++++++++++++++--------- qdeduper/mingui.hpp | 9 +++- qdeduper/pathchooser.cpp | 4 -- 5 files changed, 120 insertions(+), 32 deletions(-) diff --git a/qdeduper/imageitem.cpp b/qdeduper/imageitem.cpp index f53783a..cb1c76e 100644 --- a/qdeduper/imageitem.cpp +++ b/qdeduper/imageitem.cpp @@ -25,6 +25,7 @@ ImageItem::ImageItem(QString fn, QString dispn, QKeySequence hotkey, size_t dbid this->setData(pm, Qt::ItemDataRole::DecorationRole); this->setData(QVariant::fromValue(dbid), ImageItemRoles::database_id_role); this->setData(QVariant::fromValue(ord), ImageItemRoles::default_order_role); + this->setData(QVariant::fromValue(1ULL * pm.size().width() * pm.size().height()), ImageItemRoles::pixelcnt_role); } QString ImageItem::path() const @@ -47,6 +48,11 @@ QKeySequence ImageItem::hotkey() const return this->data(ImageItemRoles::hotkey_role).value(); } +void ImageItem::set_hotkey(QKeySequence hk) +{ + this->setData(hk, ImageItemRoles::hotkey_role); +} + void ImageItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QRect imr = option.rect; diff --git a/qdeduper/imageitem.hpp b/qdeduper/imageitem.hpp index 2d90644..5b1a1f3 100644 --- a/qdeduper/imageitem.hpp +++ b/qdeduper/imageitem.hpp @@ -17,7 +17,8 @@ public: file_size_role, hotkey_role, database_id_role, - default_order_role + default_order_role, + pixelcnt_role }; ImageItem(QString fn, QString dispn, QKeySequence hotkey, size_t dbid, size_t ord, double pxratio = 1.0); @@ -25,6 +26,7 @@ public: size_t database_id() const; size_t default_order() const; QKeySequence hotkey() const; + void set_hotkey(QKeySequence hk); }; class ImageItemDelegate : public QAbstractItemDelegate diff --git a/qdeduper/mingui.cpp b/qdeduper/mingui.cpp index 80a83dc..cbdc9b7 100644 --- a/qdeduper/mingui.cpp +++ b/qdeduper/mingui.cpp @@ -12,11 +12,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -73,8 +75,7 @@ Q_DECLARE_METATYPE(fs::path) DeduperMainWindow::DeduperMainWindow() { qRegisterMetaType(); - this->setFont(QFontDatabase::systemFont(QFontDatabase::SystemFont::FixedFont)); - this->setWindowTitle("deduper"); + this->setWindowTitle("QDeduper"); this->setup_menu(); this->update_actions(); sb = this->statusBar(); @@ -113,7 +114,6 @@ DeduperMainWindow::DeduperMainWindow() pd->setAutoReset(false); pd->setAutoClose(false); pd->setWindowTitle("Progress"); - pd->setFont(this->font()); QLabel *pdlb = new QLabel(pd); pdlb->setMaximumWidth(500); pdlb->setAlignment(Qt::AlignmentFlag::AlignLeft | Qt::AlignmentFlag::AlignVCenter); @@ -123,6 +123,10 @@ DeduperMainWindow::DeduperMainWindow() pd->setMaximumHeight(120); pd->setMinimumHeight(120); pd->close(); + QFont fnt = QFontDatabase::systemFont(QFontDatabase::SystemFont::FixedFont); + lv->setFont(fnt); + infopanel->setFont(fnt); + pd->setFont(fnt); for (size_t i = 0; i < keys.size(); ++i) { @@ -179,6 +183,8 @@ DeduperMainWindow::DeduperMainWindow() infopanel->setText("bleh"); infopanel->setSizePolicy(QSizePolicy::Policy::Minimum, QSizePolicy::Policy::Minimum); nohotkeywarn = false; + sort_role = ImageItem::ImageItemRoles::default_order_role; + sort_order = Qt::SortOrder::AscendingOrder; } void DeduperMainWindow::setup_menu() @@ -250,27 +256,11 @@ void DeduperMainWindow::setup_menu() file->addSeparator(); QAction *search_img = file->addAction("Search for Image..."); - QObject::connect(search_img, &QAction::triggered, [this]{ + QObject::connect(search_img, &QAction::triggered, [this] { QString fpath = QFileDialog::getOpenFileName(this, "Select Image", QString(), "Image file"); if (fpath.isNull()) return; - auto sim = this->sdb->search_file(qstring_to_path(fpath)); - if (sim.empty()) - { - this->sb->showMessage("No similar image found.", 2000); - return; - } - this->vm = ViewMode::view_searchresult; - std::vector ps; - std::map, double> dm; - for (auto &s : sim) - { - ps.push_back(s.first); - dm[std::make_pair(0, s.first)] = s.second; - } - this->show_images(ps); - this->update_distances(dm); - this->sb->showMessage("Use next group / previous group to go back."); - this->permamsg->setText("Viewing image search result"); + searched_image = qstring_to_path(fpath); + search_image(searched_image); }); menuact["search_image"] = search_img; file->addSeparator(); @@ -324,9 +314,62 @@ void DeduperMainWindow::setup_menu() view->addSeparator(); QMenu *sort = view->addMenu("Sort by"); - sort->addAction("File size"); - sort->addAction("Image dimension"); - sort->addAction("File path"); + QMenu *tbsort = new QMenu(this); + QAction *sfsz = new QAction("File size"); + QAction *simd = new QAction("Image dimension"); + QAction *sfpt = new QAction("File path"); + QAction *snon = new QAction("Default"); + QList skeya = {sfsz, simd, sfpt, snon}; + QList skeyr = { + ImageItem::ImageItemRoles::file_size_role, + ImageItem::ImageItemRoles::pixelcnt_role, + ImageItem::ImageItemRoles::path_role, + ImageItem::ImageItemRoles::database_id_role, + }; + QActionGroup *skeyg = new QActionGroup(sort); + for (int i = 0; i < skeya.size(); ++i) + { + auto a = skeya[i]; + sort->addAction(a); + tbsort->addAction(a); + skeyg->addAction(a); + a->setCheckable(true); + ImageItem::ImageItemRoles sr = skeyr[i]; + QObject::connect(a, &QAction::triggered, [this, sr] { + this->sort_role = sr; + if (this->vm == ViewMode::view_normal) + this->show_group(this->curgroup); + else + this->search_image(this->searched_image); + }); + } + snon->setChecked(true); + skeyg->setExclusionPolicy(QActionGroup::ExclusionPolicy::Exclusive); + sort->addSeparator(); + tbsort->addSeparator(); + QAction *sasc = new QAction("Ascending"); + QAction *sdec = new QAction("Descending"); + QActionGroup *sordg = new QActionGroup(sort); + QList sorda = {sasc, sdec}; + QList sordv = {Qt::SortOrder::AscendingOrder, Qt::SortOrder::DescendingOrder}; + for (int i = 0; i < sorda.size(); ++i) + { + auto a = sorda[i]; + sort->addAction(a); + tbsort->addAction(a); + sordg->addAction(a); + a->setCheckable(true); + Qt::SortOrder so = sordv[i]; + QObject::connect(a, &QAction::triggered, [this, so] { + this->sort_order = so; + if (this->vm == ViewMode::view_normal) + this->show_group(this->curgroup); + else + this->search_image(this->searched_image); + }); + } + sasc->setChecked(true); + sordg->setExclusionPolicy(QActionGroup::ExclusionPolicy::Exclusive); QAction *mall = mark->addAction("Mark All"); mall->setShortcut(QKeySequence(Qt::Key::Key_X)); @@ -356,6 +399,10 @@ void DeduperMainWindow::setup_menu() tb->addAction(prvgrp); tb->addAction(nxtgrp); tb->addAction(skip); + QAction *tbsorta = tb->addAction("Sort by"); + QToolButton *tbsortb = qobject_cast(tb->widgetForAction(tbsorta)); + tbsortb->setPopupMode(QToolButton::ToolButtonPopupMode::InstantPopup); + tbsorta->setMenu(tbsort); tb->setToolButtonStyle(Qt::ToolButtonStyle::ToolButtonTextBesideIcon); } void DeduperMainWindow::update_actions() @@ -385,6 +432,29 @@ void DeduperMainWindow::update_actions() } } +void DeduperMainWindow::search_image(const fs::path &path) +{ + auto sim = this->sdb->search_file(path); + if (sim.empty()) + { + this->sb->showMessage("No similar image found.", 2000); + return; + } + this->vm = ViewMode::view_searchresult; + std::vector ps; + std::map, double> dm; + for (auto &s : sim) + { + ps.push_back(s.first); + dm[std::make_pair(0, s.first)] = s.second; + } + this->show_images(ps); + this->sort_reassign_hotkeys(); + this->update_distances(dm); + this->sb->showMessage("Use next group / previous group to go back."); + this->permamsg->setText("Viewing image search result"); +} + void DeduperMainWindow::show_images(const std::vector &ids) { im->clear(); @@ -572,11 +642,20 @@ void DeduperMainWindow::show_group(size_t gid) this->vm = ViewMode::view_normal; auto g = sdb->get_group(gid); this->show_images(g); + this->sort_reassign_hotkeys(); this->update_distances(sdb->group_distances(gid)); this->update_viewstatus(gid, sdb->num_groups()); this->update_actions(); } +void DeduperMainWindow::sort_reassign_hotkeys() +{ + im->setSortRole(this->sort_role); + im->sort(0, this->sort_order); + for (int i = 0; i < im->rowCount(); ++i) + static_cast(im->item(i))->set_hotkey(i < keys.size() ? keys[i] : QKeySequence()); +} + void DeduperMainWindow::mark_toggle(size_t x) { if (vm == ViewMode::view_searchresult) diff --git a/qdeduper/mingui.hpp b/qdeduper/mingui.hpp index 8812f32..29332d7 100644 --- a/qdeduper/mingui.hpp +++ b/qdeduper/mingui.hpp @@ -51,17 +51,20 @@ private: QProgressDialog *pd = nullptr; SignatureDB *sdb = nullptr; FileScanner *fsc = nullptr; - + std::unordered_set marked; + int sort_role; + Qt::SortOrder sort_order; size_t curgroup; + fs::path searched_image; ViewMode vm; bool nohotkeywarn; + void mark_toggle(size_t x); void mark_all_but(size_t x); void mark_all(); void mark_none(bool msg = true); void marked_update(bool update_msg = true); fs::path::string_type common_prefix(const std::vector &fns); - std::unordered_set marked; protected: void closeEvent(QCloseEvent *e) override; bool eventFilter(QObject *obj, QEvent *ev) override; @@ -69,6 +72,8 @@ public: DeduperMainWindow(); void setup_menu(); + void sort_reassign_hotkeys(); + void search_image(const fs::path &path); void show_images(const std::vector &ids); void update_distances(const std::map, double> &d); void update_viewstatus(size_t cur, size_t size); diff --git a/qdeduper/pathchooser.cpp b/qdeduper/pathchooser.cpp index c08199f..75c829d 100644 --- a/qdeduper/pathchooser.cpp +++ b/qdeduper/pathchooser.cpp @@ -8,10 +8,6 @@ #include #include #include -#include -#include -#include -#include PathChooser::PathChooser(QWidget *parent) : QDialog(parent) { -- cgit v1.2.3