333 lines
6.7 KiB
C++
333 lines
6.7 KiB
C++
#include "shortcuts.h"
|
|
|
|
#include <QAction>
|
|
#include <QHeaderView>
|
|
#include <QKeyEvent>
|
|
#include <QMainWindow>
|
|
#include <QMenu>
|
|
#include <QPainter>
|
|
#include <QScrollBar>
|
|
#include <QShortcut>
|
|
#include <QToolBar>
|
|
#include <QWidgetAction>
|
|
|
|
|
|
/// ShortcutEdit
|
|
|
|
ShortcutEdit::ShortcutEdit(QWidget * parent): CLineEdit(parent) {
|
|
ti = nullptr;
|
|
ca = nullptr;
|
|
connect(this, &CLineEdit::textChanged, this, &ShortcutEdit::textChangedSlot);
|
|
}
|
|
|
|
|
|
void ShortcutEdit::keyPressEvent(QKeyEvent * e) {
|
|
Qt::KeyboardModifiers km = e->modifiers();
|
|
km &= ~Qt::KeypadModifier;
|
|
km &= ~Qt::GroupSwitchModifier;
|
|
if (e->key() != Qt::Key_Control && e->key() != Qt::Key_Shift && e->key() != Qt::Key_Alt && e->key() != Qt::Key_Meta) {
|
|
setText(QKeySequence(km | e->key()).toString());
|
|
}
|
|
}
|
|
|
|
|
|
void ShortcutEdit::assignAction(QAction * a) {
|
|
clear();
|
|
ca = a;
|
|
reset();
|
|
}
|
|
|
|
|
|
QAction * ShortcutEdit::action() const {
|
|
return ca;
|
|
}
|
|
|
|
|
|
bool ShortcutEdit::isEmpty() const {
|
|
return text().isEmpty();
|
|
}
|
|
|
|
|
|
void ShortcutEdit::commit() {
|
|
if (!ca) {
|
|
return;
|
|
}
|
|
ca->setShortcut(QKeySequence(text()));
|
|
}
|
|
|
|
|
|
void ShortcutEdit::reset() {
|
|
if (!ca) {
|
|
return;
|
|
}
|
|
setText(ca->shortcut().toString());
|
|
}
|
|
|
|
|
|
void ShortcutEdit::textChangedSlot(QString t) {
|
|
if (ti) {
|
|
ti->setText(1, t);
|
|
}
|
|
}
|
|
|
|
|
|
/// Shortcuts
|
|
|
|
Shortcuts::Shortcuts(QWidget * parent, bool on): QTreeWidget(parent) {
|
|
aw = nullptr;
|
|
QImage ti(QSize(16, 16), QImage::Format_ARGB32_Premultiplied);
|
|
QPainter p(&ti);
|
|
p.setCompositionMode(QPainter::CompositionMode_Clear);
|
|
p.eraseRect(ti.rect());
|
|
p.end();
|
|
empty_icon = QPixmap::fromImage(ti);
|
|
bfont = font();
|
|
bfont.setWeight(QFont::Bold);
|
|
active = on;
|
|
setColumnCount(2);
|
|
#if QT_VERSION < 0x050000
|
|
header()->setResizeMode(0, QHeaderView::ResizeToContents);
|
|
header()->setResizeMode(1, QHeaderView::ResizeToContents);
|
|
#else
|
|
header()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
|
|
header()->setSectionResizeMode(1, QHeaderView::ResizeToContents);
|
|
#endif
|
|
header()->setStretchLastSection(true);
|
|
setColumnWidth(1, 200);
|
|
setSortingEnabled(true);
|
|
QStringList l;
|
|
l << tr("Command") << tr("Shortcut");
|
|
setHeaderLabels(l);
|
|
assignWindow(parent);
|
|
}
|
|
|
|
|
|
Shortcuts::~Shortcuts() {
|
|
for (ShortcutEdit * i: edits) {
|
|
delete i;
|
|
}
|
|
edits.clear();
|
|
}
|
|
|
|
|
|
void Shortcuts::changeEvent(QEvent * e) {
|
|
QTreeWidget::changeEvent(e);
|
|
if (e->type() == QEvent::LanguageChange) {
|
|
QStringList l;
|
|
l << tr("Command") << tr("Shortcut");
|
|
setHeaderLabels(l);
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
void Shortcuts::assignWindow(QWidget * w) {
|
|
if (!w) {
|
|
return;
|
|
}
|
|
while (!(qobject_cast<QMainWindow *>(w)) && (w->parentWidget())) {
|
|
w = w->parentWidget();
|
|
}
|
|
aw = qobject_cast<QMainWindow *>(w);
|
|
updateShortcuts();
|
|
}
|
|
|
|
|
|
QStringList Shortcuts::actionTree(QAction * a) {
|
|
QStringList tree;
|
|
QList<QWidget *> aw = a->associatedWidgets();
|
|
if (aw.size() == 0) {
|
|
return tree;
|
|
}
|
|
for (QWidget * i: aw) {
|
|
auto tm = qobject_cast<QMenu *>(i);
|
|
if (!tm) {
|
|
continue;
|
|
}
|
|
auto cw = i;
|
|
while (cw) {
|
|
tm = qobject_cast<QMenu *>(cw);
|
|
if (tm) {
|
|
if (!tm->title().isEmpty()) {
|
|
tree.push_front(tm->title());
|
|
}
|
|
cw = cw->parentWidget();
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
if (!tree.isEmpty()) {
|
|
return tree;
|
|
}
|
|
}
|
|
for (QWidget * i: aw) {
|
|
auto tt = qobject_cast<QToolBar *>(i);
|
|
if (!tt) {
|
|
continue;
|
|
}
|
|
if (!tt->windowTitle().isEmpty()) {
|
|
tree.push_front(tt->windowTitle());
|
|
}
|
|
break;
|
|
}
|
|
return tree;
|
|
}
|
|
|
|
|
|
QList<QPair<QString, QKeySequence>> Shortcuts::shortcuts() {
|
|
QList<QPair<QString, QKeySequence>> l;
|
|
for (const ShortcutEdit * i: edits) {
|
|
if (i->action()->objectName().isEmpty()) {
|
|
continue;
|
|
}
|
|
l << QPair<QString, QKeySequence>(i->action()->objectName(), i->text());
|
|
}
|
|
return l;
|
|
}
|
|
|
|
|
|
void Shortcuts::clear() {
|
|
foreach(ShortcutEdit * i, edits)
|
|
delete i;
|
|
edits.clear();
|
|
hide();
|
|
QList<QTreeWidgetItem *> tl = findItems("", Qt::MatchContains);
|
|
foreach(QTreeWidgetItem * i, tl)
|
|
delete i;
|
|
show();
|
|
}
|
|
|
|
|
|
bool Shortcuts::checkAction(QAction * a) {
|
|
if (a->menu() || a->isSeparator() || a->text().isEmpty()) {
|
|
return false;
|
|
}
|
|
if (a->associatedWidgets().isEmpty()) {
|
|
return false;
|
|
}
|
|
if (QString(a->metaObject()->className()) != "QAction") {
|
|
return false;
|
|
}
|
|
if (qobject_cast<QWidgetAction *>(a)) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
void Shortcuts::updateShortcuts() {
|
|
if (!aw || !active) {
|
|
return;
|
|
}
|
|
hide();
|
|
int cpos = verticalScrollBar()->value();
|
|
clear();
|
|
#if QT_VERSION < 0x050000
|
|
header()->setResizeMode(0, QHeaderView::Fixed);
|
|
#else
|
|
header()->setSectionResizeMode(0, QHeaderView::Fixed);
|
|
#endif
|
|
QList<QAction *> al = aw->findChildren<QAction *>();
|
|
QTreeWidgetItem *pi, *ci;
|
|
QStringList tree;
|
|
bool s = isSortingEnabled(), isFound;
|
|
setSortingEnabled(false);
|
|
for (QAction * i: al) {
|
|
if (!checkAction(i)) continue;
|
|
edits.push_back(new ShortcutEdit());
|
|
tree = actionTree(i);
|
|
pi = invisibleRootItem();
|
|
for (const QString & t: tree) {
|
|
isFound = false;
|
|
for (int j = 0; j < pi->childCount(); ++j) {
|
|
if (pi->child(j)->text(0) == t) {
|
|
pi = pi->child(j);
|
|
isFound = true;
|
|
break;
|
|
}
|
|
}
|
|
if (isFound) continue;
|
|
ci = new QTreeWidgetItem(pi);
|
|
ci->setText(0, t);
|
|
ci->setToolTip(0, t);
|
|
ci->setFont(0, bfont);
|
|
pi->addChild(ci);
|
|
pi = ci;
|
|
}
|
|
ci = new QTreeWidgetItem(pi);
|
|
ci->setText(0, i->text());
|
|
ci->setToolTip(0, i->text());
|
|
if (i->icon().isNull())
|
|
ci->setIcon(0, empty_icon);
|
|
else
|
|
ci->setIcon(0, i->icon());
|
|
edits.back()->ti = ci;
|
|
edits.back()->assignAction(i);
|
|
pi->addChild(ci);
|
|
// qDebug() << "set widget" << edits.back();
|
|
setItemWidget(ci, 1, edits.back());
|
|
}
|
|
setSortingEnabled(s);
|
|
#if QT_VERSION < 0x050000
|
|
header()->setResizeMode(0, QHeaderView::ResizeToContents);
|
|
#else
|
|
header()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
|
|
#endif
|
|
expandAll();
|
|
verticalScrollBar()->setValue(cpos);
|
|
show();
|
|
}
|
|
|
|
|
|
void Shortcuts::commit() {
|
|
for (ShortcutEdit * i: edits) {
|
|
i->commit();
|
|
}
|
|
}
|
|
|
|
|
|
void Shortcuts::resetShortcuts() {
|
|
for (ShortcutEdit * i: edits) {
|
|
i->reset();
|
|
}
|
|
updateShortcuts();
|
|
}
|
|
|
|
|
|
void Shortcuts::filter(const QString & what) {
|
|
hide();
|
|
for (int i = 0; i < topLevelItemCount(); ++i) {
|
|
filterTree(topLevelItem(i), what);
|
|
}
|
|
show();
|
|
}
|
|
|
|
|
|
bool Shortcuts::filterTree(QTreeWidgetItem * ti, QString f) {
|
|
if (f.isEmpty()) {
|
|
for (int i = 0; i < ti->childCount(); ++i) {
|
|
filterTree(ti->child(i), f);
|
|
}
|
|
ti->setHidden(false);
|
|
return true;
|
|
}
|
|
bool isFound = false;
|
|
for (int i = 0; i < ti->childCount(); ++i) {
|
|
if (filterTree(ti->child(i), f)) {
|
|
isFound = true;
|
|
}
|
|
}
|
|
if (ti->text(0).indexOf(f, 0, Qt::CaseInsensitive) >= 0 || ti->text(1).indexOf(f, 0, Qt::CaseInsensitive) >= 0) {
|
|
isFound = true;
|
|
}
|
|
ti->setHidden(!isFound);
|
|
return isFound;
|
|
}
|
|
|
|
|
|
void Shortcuts::updateEditorGeometries() {
|
|
for (ShortcutEdit * i: edits) {
|
|
i->setGeometry(visualRect(indexFromItem(i->ti, 1)));
|
|
}
|
|
}
|