aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Chris Xiong <chirs241097@gmail.com> 2022-10-02 02:04:05 -0400
committerGravatar Chris Xiong <chirs241097@gmail.com> 2022-10-02 02:04:05 -0400
commit64a4fc1fb07863f35289b2dc050d30ecc96aaac6 (patch)
treeb79ad5212b2125bdb1846be52064c615c370d8df
parent3afafef65bff7fc6ecb02c88bc20657e1bdc2fe4 (diff)
downloaddeduper-64a4fc1fb07863f35289b2dc050d30ecc96aaac6.tar.xz
Add shortcut settings for item actions.
Implement check for ambiguous shortcuts. Make preference dialog wider by default.
-rw-r--r--qdeduper/mingui.cpp4
-rw-r--r--qdeduper/preferencedialog.cpp178
-rw-r--r--qdeduper/preferencedialog.hpp19
3 files changed, 196 insertions, 5 deletions
diff --git a/qdeduper/mingui.cpp b/qdeduper/mingui.cpp
index caf0249..f599ba0 100644
--- a/qdeduper/mingui.cpp
+++ b/qdeduper/mingui.cpp
@@ -829,9 +829,9 @@ void DeduperMainWindow::apply_prefs()
size_t actt = i % ItemActionType::ACTION_MAX;
std::string iamt = "hotkey/item_action_mod_" + std::to_string(actt);
std::string iakt = "hotkey/item_" + std::to_string(actn) + "_action_key";
- int ik = sr->get_option_int(iakt);
int im = sr->get_option_int(iamt);
- QKeySequence ks = QKeySequence(static_cast<Qt::Key>(ik | im));
+ int ik = sr->get_option_int(iakt);
+ QKeySequence ks = ~im ? QKeySequence(static_cast<Qt::Key>(ik | im)) : QKeySequence();
act->setShortcut(ks);
}
}
diff --git a/qdeduper/preferencedialog.cpp b/qdeduper/preferencedialog.cpp
index 28ccbea..40d2aea 100644
--- a/qdeduper/preferencedialog.cpp
+++ b/qdeduper/preferencedialog.cpp
@@ -1,6 +1,8 @@
+#include <climits>
#include <functional>
#include <QDebug>
+#include <QKeyEvent>
#include <QLabel>
#include <QTabWidget>
#include <QGridLayout>
@@ -13,6 +15,8 @@
#include <QTableView>
#include <QStandardItemModel>
#include <QKeySequenceEdit>
+#include <QGroupBox>
+#include <QMessageBox>
#include "preferencedialog.hpp"
#include "settings.hpp"
@@ -23,6 +27,7 @@ PreferenceDialog::PreferenceDialog(SettingsRegistry *sr, QWidget *parent) : QDia
tw = new QTabWidget(this);
bb = new QDialogButtonBox(QDialogButtonBox::StandardButton::Ok | QDialogButtonBox::StandardButton::Cancel, this);
this->setWindowTitle("Preferences");
+ this->setMinimumWidth(480);
QVBoxLayout *l = new QVBoxLayout();
this->setLayout(l);
l->addWidget(tw);
@@ -40,6 +45,22 @@ void PreferenceDialog::open()
void PreferenceDialog::accept()
{
+ QKeySequence bks;
+ switch (verify_shortcuts(&bks))
+ {
+ case 0:
+ break;
+ case 1:
+ QMessageBox::critical(this, "Ambiguous shortcut found",
+ QString("Shortcut %1 is assigned to multiple actions.").arg(bks.toString()));
+ return;
+ case 2:
+ QMessageBox::critical(this, "Bad shortcut assignment",
+ QString("Shortcut %1 has more than one key and cannot be assigned to item actions.").arg(bks.toString()));
+ return;
+ default:
+ break;
+ }
save_widget_status();
QDialog::accept();
}
@@ -56,6 +77,7 @@ void PreferenceDialog::setup_widgets()
for (auto &k : sr->klist)
{
auto &p = sr->smap[k];
+ if (!p.desc.length()) continue;
QWidget *w = nullptr;
QGridLayout *l = p.tab < tabs.size() ? tabs[p.tab] : nullptr;
if (!l) continue;
@@ -117,6 +139,23 @@ void PreferenceDialog::set_hkactions(int tab, std::map<std::string, QKeySequence
this->hktv->setSortingEnabled(false);
this->hktv->setSelectionMode(QAbstractItemView::SelectionMode::NoSelection);
this->hktv->setItemDelegateForColumn(1, new ShortcutEditorDelegate);
+
+ QGroupBox *gb = new QGroupBox("Action Modifiers");
+ QGridLayout *l = new QGridLayout();
+ gb->setLayout(l);
+ this->tabs[tab]->addWidget(gb, 1, 0);
+
+ const QStringList llist = {"Mark/Unmark", "Mark All Except", "Maximize", "Open with System Viewer", "Open Containing Folder"};
+
+ for (int i = 0; i < llist.size(); ++i)
+ {
+ auto &lt = llist[i];
+ ModifierEdit *me = new ModifierEdit();
+ QLabel *lb = new QLabel(lt);
+ l->addWidget(lb, i, 0);
+ l->addWidget(me, i, 1);
+ mes.push_back(me);
+ }
}
void PreferenceDialog::load_widget_status()
@@ -162,7 +201,7 @@ void PreferenceDialog::load_widget_status()
continue;
QAction *act = this->actmap[actn];
QStandardItem *itma = new QStandardItem(act->text());
- QStandardItem *itmk = new QStandardItem(act->shortcut().toString());
+ QStandardItem *itmk = new QStandardItem(ks.toString());
itma->setIcon(act->icon());
itma->setEditable(false);
itma->setData(QString::fromStdString(actn), Qt::ItemDataRole::UserRole);
@@ -170,6 +209,24 @@ void PreferenceDialog::load_widget_status()
this->hkim->appendRow({itma, itmk});
}
this->hktv->resizeColumnsToContents();
+ for (size_t i = 0; i < 16; ++i)
+ {
+ std::string iakt = "item_" + std::to_string(i) + "_action_key";
+ int ik = sr->get_option_int("hotkey/" + iakt);
+ QKeySequence ks(ik);
+ QStandardItem *itma = new QStandardItem(QString("Item %1 Action Key").arg(i + 1));
+ QStandardItem *itmk = new QStandardItem(ks.toString());
+ itma->setEditable(false);
+ itma->setData(QString::fromStdString(iakt), Qt::ItemDataRole::UserRole);
+ itmk->setData(QVariant::fromValue<QKeySequence>(ks), Qt::ItemDataRole::UserRole);
+ this->hkim->appendRow({itma, itmk});
+ }
+ for (size_t i = 0; i < 5; ++i)
+ {
+ std::string iamt = "hotkey/item_action_mod_" + std::to_string(i);
+ int im = sr->get_option_int(iamt);
+ mes[i]->set_modifier(static_cast<Qt::Modifier>(im));
+ }
}
void PreferenceDialog::save_widget_status()
@@ -207,11 +264,49 @@ void PreferenceDialog::save_widget_status()
}
for (int i = 0; i < hkim->rowCount(); ++i)
{
- std::string actn = hkim->item(i, 0)->data(Qt::ItemDataRole::UserRole).toString().toStdString();
+ QString actn = hkim->item(i, 0)->data(Qt::ItemDataRole::UserRole).toString();
QKeySequence ks = hkim->item(i, 1)->data(Qt::ItemDataRole::UserRole).value<QKeySequence>();
- sr->set_option_keyseq("hotkey/" + actn, ks);
+ if (actn.endsWith("_action_key"))
+ sr->set_option_int("hotkey/" + actn.toStdString(), ks[0]);
+ else sr->set_option_keyseq("hotkey/" + actn.toStdString(), ks);
+ }
+ for (size_t i = 0; i < 5; ++i)
+ {
+ std::string iamt = "hotkey/item_action_mod_" + std::to_string(i);
+ sr->set_option_int(iamt, mes[i]->get_modifier());
}
}
+
+int PreferenceDialog::verify_shortcuts(QKeySequence *bks)
+{
+ QList<QKeySequence> ksl;
+ for (int i = 0; i < hkim->rowCount(); ++i)
+ {
+ QString actn = hkim->item(i, 0)->data(Qt::ItemDataRole::UserRole).toString();
+ QKeySequence ks = hkim->item(i, 1)->data(Qt::ItemDataRole::UserRole).value<QKeySequence>();
+ if (actn.endsWith("_action_key"))
+ {
+ if (ks.count() > 1)
+ {
+ *bks = ks;
+ return 2;
+ }
+ for (int j = 0;j < 5; ++j)
+ if (mes[j]->get_modifier() != INT_MAX)
+ ksl.push_back(QKeySequence(mes[j]->get_modifier() | ks[0]));
+ }
+ else ksl.push_back(hkim->item(i, 1)->data(Qt::ItemDataRole::UserRole).value<QKeySequence>());
+ }
+ for (int i = 0; i < ksl.size(); ++i)
+ for (int j = i + 1; j < ksl.size(); ++j)
+ if (!ksl[i].isEmpty() && ksl[i] == ksl[j])
+ {
+ *bks = ksl[i];
+ return 1;
+ }
+ return 0;
+}
+
QWidget* ShortcutEditorDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
Q_UNUSED(option);
@@ -236,3 +331,80 @@ void ShortcutEditorDelegate::setModelData(QWidget *editor, QAbstractItemModel *m
model->setData(index, QVariant::fromValue<QKeySequence>(kse->keySequence()), Qt::ItemDataRole::UserRole);
model->setData(index, kse->keySequence().toString(), Qt::ItemDataRole::DisplayRole);
}
+
+ModifierEdit::ModifierEdit(QWidget *par) : QPushButton(par)
+{
+ this->setCheckable(true);
+ this->setFocusPolicy(Qt::FocusPolicy::StrongFocus);
+ this->mod = static_cast<Qt::Modifier>(0);
+ QObject::connect(this, &QPushButton::toggled, [this](bool c) {
+ if (c)
+ {
+ if (int(this->mod) == INT_MAX)
+ this->set_modifier(static_cast<Qt::Modifier>(0));
+ this->setText("Input modifier...");
+ }
+ else
+ this->set_modifier(this->mod);
+ });
+}
+
+Qt::Modifier ModifierEdit::get_modifier()
+{
+ return this->mod;
+}
+
+void ModifierEdit::set_modifier(Qt::Modifier mod)
+{
+ this->mod = mod;
+ int imod = mod;
+ switch (imod)
+ {
+ case 0:
+ if (this->isChecked())
+ this->setText("Input modifier...");
+ else
+ this->setText("No modifier");
+ break;
+ case INT_MAX:
+ this->setText("Disabled");
+ break;
+ default:
+ QString kss = QKeySequence(mod).toString();
+ while (kss.length() > 0 && kss.back() == '+') kss.chop(1);
+ this->setText(kss);
+ }
+}
+
+void ModifierEdit::keyPressEvent(QKeyEvent *e)
+{
+ if (!this->isChecked()) return QPushButton::keyPressEvent(e);
+ switch (e->key())
+ {
+ case Qt::Key::Key_Enter:
+ case Qt::Key::Key_Return:
+ case Qt::Key::Key_Space:
+ this->set_modifier(static_cast<Qt::Modifier>(Qt::KeyboardModifiers::Int(e->modifiers())));
+ this->setChecked(false);
+ break;
+ case Qt::Key::Key_Escape:
+ this->set_modifier(static_cast<Qt::Modifier>(0));
+ this->setChecked(false);
+ break;
+ case Qt::Key::Key_Backspace:
+ case Qt::Key::Key_Delete:
+ this->set_modifier(static_cast<Qt::Modifier>(INT_MAX));
+ this->setChecked(false);
+ break;
+ }
+}
+
+bool ModifierEdit::event(QEvent *e)
+{
+ if (e->type() == QEvent::Type::ShortcutOverride)
+ {
+ e->accept();
+ return true;
+ }
+ return QPushButton::event(e);
+}
diff --git a/qdeduper/preferencedialog.hpp b/qdeduper/preferencedialog.hpp
index 8efefde..78e78c5 100644
--- a/qdeduper/preferencedialog.hpp
+++ b/qdeduper/preferencedialog.hpp
@@ -5,6 +5,7 @@
#include <map>
#include <string>
+#include <QPushButton>
#include <QDialog>
#include <QGridLayout>
#include <QStyledItemDelegate>
@@ -17,6 +18,20 @@ class QDialogButtonBox;
class QTableView;
class QStandardItemModel;
+class ModifierEdit : public QPushButton
+{
+ Q_OBJECT
+public:
+ ModifierEdit(QWidget *par = nullptr);
+ Qt::Modifier get_modifier();
+ void set_modifier(Qt::Modifier mod);
+ bool event(QEvent *e) override;
+protected:
+ void keyPressEvent(QKeyEvent *e) override;
+private:
+ Qt::Modifier mod;
+};
+
class PreferenceDialog : public QDialog
{
Q_OBJECT
@@ -27,9 +42,12 @@ public:
void load_widget_status();
void save_widget_status();
+public Q_SLOTS:
void open() override;
void accept() override;
private:
+ int verify_shortcuts(QKeySequence *bks);
+
SettingsRegistry *sr;
QTabWidget *tw;
std::vector<QGridLayout*> tabs;
@@ -38,6 +56,7 @@ private:
QStandardItemModel *hkim = nullptr;
std::map<std::string, QKeySequence> defmap;
std::map<std::string, QAction*> actmap;
+ std::vector<ModifierEdit*> mes;
};
class ShortcutEditorDelegate : public QStyledItemDelegate