From 20e464356005e6f27d5885e090a28ebd666da85c Mon Sep 17 00:00:00 2001 From: Felix Geyer Date: Sat, 21 Jul 2012 22:17:48 +0200 Subject: [PATCH] Implement global auto-type dialog. It allows to select an entry when there are multiple entries that match the window title. --- src/CMakeLists.txt | 4 ++ src/autotype/AutoType.cpp | 41 +++++++++++--- src/autotype/AutoType.h | 8 ++- src/autotype/AutoTypeSelectDialog.cpp | 78 +++++++++++++++++++++++++++ src/autotype/AutoTypeSelectDialog.h | 50 +++++++++++++++++ src/autotype/AutoTypeSelectView.cpp | 50 +++++++++++++++++ src/autotype/AutoTypeSelectView.h | 38 +++++++++++++ 7 files changed, 260 insertions(+), 9 deletions(-) create mode 100644 src/autotype/AutoTypeSelectDialog.cpp create mode 100644 src/autotype/AutoTypeSelectDialog.h create mode 100644 src/autotype/AutoTypeSelectView.cpp create mode 100644 src/autotype/AutoTypeSelectView.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8887141e4..860b21575 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -20,6 +20,8 @@ configure_file(config-keepassx.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-keepas set(keepassx_SOURCES autotype/AutoType.cpp autotype/AutoTypeAction.cpp + autotype/AutoTypeSelectDialog.cpp + autotype/AutoTypeSelectView.cpp autotype/ShortcutWidget.cpp autotype/WindowSelectComboBox.cpp core/AutoTypeAssociations.cpp @@ -99,6 +101,8 @@ set(keepassx_SOURCES set(keepassx_MOC autotype/AutoType.h + autotype/AutoTypeSelectDialog.h + autotype/AutoTypeSelectView.h autotype/ShortcutWidget.h autotype/WindowSelectComboBox.h core/AutoTypeAssociations.h diff --git a/src/autotype/AutoType.cpp b/src/autotype/AutoType.cpp index e704aa296..9400f14c4 100644 --- a/src/autotype/AutoType.cpp +++ b/src/autotype/AutoType.cpp @@ -21,6 +21,7 @@ #include #include "autotype/AutoTypePlatformPlugin.h" +#include "autotype/AutoTypeSelectDialog.h" #include "core/Database.h" #include "core/Entry.h" #include "core/FilePath.h" @@ -88,7 +89,7 @@ QStringList AutoType::windowTitles() return m_plugin->windowTitles(); } -void AutoType::performAutoType(const Entry* entry, QWidget* hideWindow, const QString& customSequence) +void AutoType::performAutoType(const Entry* entry, QWidget* hideWindow, const QString& customSequence, WId window) { if (m_inAutoType || !m_plugin) { return; @@ -117,10 +118,12 @@ void AutoType::performAutoType(const Entry* entry, QWidget* hideWindow, const QS Tools::wait(500); - WId activeWindow = m_plugin->activeWindow(); + if (!window) { + window = m_plugin->activeWindow(); + } Q_FOREACH (AutoTypeAction* action, actions) { - if (m_plugin->activeWindow() != activeWindow) { + if (m_plugin->activeWindow() != window) { qWarning("Active window changed, interrupting auto-type."); break; } @@ -146,13 +149,15 @@ void AutoType::performGlobalAutoType(const QList& dbList) m_inAutoType = true; - QList > entryList; + QList entryList; + QHash sequenceHash; Q_FOREACH (Database* db, dbList) { Q_FOREACH (Entry* entry, db->rootGroup()->entriesRecursive()) { QString sequence = entry->autoTypeSequence(windowTitle); if (!sequence.isEmpty()) { - entryList << QPair(entry, sequence); + entryList << entry; + sequenceHash.insert(entry, sequence); } } } @@ -162,14 +167,34 @@ void AutoType::performGlobalAutoType(const QList& dbList) } else if (entryList.size() == 1) { m_inAutoType = false; - performAutoType(entryList.first().first, Q_NULLPTR, entryList.first().second); + performAutoType(entryList.first(), Q_NULLPTR, sequenceHash[entryList.first()]); } else { - // TODO: implement - m_inAutoType = false; + m_windowFromGlobal = m_plugin->activeWindow(); + AutoTypeSelectDialog* selectDialog = new AutoTypeSelectDialog(); + connect(selectDialog, SIGNAL(entryActivated(Entry*,QString)), + SLOT(performAutoTypeFromGlobal(Entry*,QString))); + connect(selectDialog, SIGNAL(rejected()), SLOT(resetInAutoType())); + selectDialog->setEntries(entryList, sequenceHash); + selectDialog->show(); } } +void AutoType::performAutoTypeFromGlobal(Entry* entry, const QString& sequence) +{ + Q_ASSERT(m_inAutoType); + + m_inAutoType = false; + performAutoType(entry, Q_NULLPTR, sequence, m_windowFromGlobal); +} + +void AutoType::resetInAutoType() +{ + Q_ASSERT(m_inAutoType); + + m_inAutoType = false; +} + bool AutoType::registerGlobalShortcut(Qt::Key key, Qt::KeyboardModifiers modifiers) { Q_ASSERT(key); diff --git a/src/autotype/AutoType.h b/src/autotype/AutoType.h index 3c2d729c5..0dcbb0fff 100644 --- a/src/autotype/AutoType.h +++ b/src/autotype/AutoType.h @@ -20,6 +20,7 @@ #include #include +#include #include "core/Global.h" @@ -37,7 +38,7 @@ class AutoType : public QObject public: QStringList windowTitles(); void performAutoType(const Entry* entry, QWidget* hideWindow = Q_NULLPTR, - const QString& customSequence = QString()); + const QString& customSequence = QString(), WId window = 0); bool registerGlobalShortcut(Qt::Key key, Qt::KeyboardModifiers modifiers); void unregisterGlobalShortcut(); int callEventFilter(void* event); @@ -54,6 +55,10 @@ public Q_SLOTS: Q_SIGNALS: void globalShortcutTriggered(); +private Q_SLOTS: + void performAutoTypeFromGlobal(Entry* entry, const QString& sequence); + void resetInAutoType(); + private: explicit AutoType(QObject* parent = Q_NULLPTR); ~AutoType(); @@ -67,6 +72,7 @@ private: QPluginLoader* m_pluginLoader; AutoTypePlatformInterface* m_plugin; AutoTypeExecutor* m_executor; + WId m_windowFromGlobal; static AutoType* m_instance; Q_DISABLE_COPY(AutoType) diff --git a/src/autotype/AutoTypeSelectDialog.cpp b/src/autotype/AutoTypeSelectDialog.cpp new file mode 100644 index 000000000..e27fc9dd2 --- /dev/null +++ b/src/autotype/AutoTypeSelectDialog.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2012 Felix Geyer + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "AutoTypeSelectDialog.h" + +#include +#include +#include +#include +#include + +#include "autotype/AutoTypeSelectView.h" +#include "core/FilePath.h" +#include "gui/entry/EntryModel.h" + +AutoTypeSelectDialog::AutoTypeSelectDialog(QWidget* parent) + : QDialog(parent) + , m_view(new AutoTypeSelectView(this)) + , m_entryActivatedEmitted(false) +{ + setAttribute(Qt::WA_DeleteOnClose); + setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint); + setWindowTitle(tr("Auto-Type - KeePassX")); + setWindowIcon(filePath()->applicationIcon()); + + QSize size(400, 250); + resize(size); + + // move dialog to the center of the screen + QPoint screenCenter = QApplication::desktop()->screenGeometry(QCursor::pos()).center(); + move(screenCenter.x() - (size.width() / 2), screenCenter.y() - (size.height() / 2)); + + QVBoxLayout* layout = new QVBoxLayout(this); + + QLabel* descriptionLabel = new QLabel(tr("Select entry to Auto-Type:"), this); + layout->addWidget(descriptionLabel); + + connect(m_view, SIGNAL(activated(QModelIndex)), SLOT(emitEntryActivated(QModelIndex))); + connect(m_view, SIGNAL(clicked(QModelIndex)), SLOT(emitEntryActivated(QModelIndex))); + layout->addWidget(m_view); + + QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Cancel, Qt::Horizontal, this); + connect(buttonBox, SIGNAL(rejected()), SLOT(reject())); + layout->addWidget(buttonBox); +} + +void AutoTypeSelectDialog::setEntries(const QList& entries, const QHash& sequences) +{ + m_sequences = sequences; + m_view->setEntryList(entries); +} + +void AutoTypeSelectDialog::emitEntryActivated(const QModelIndex& index) +{ + // make sure we don't emit the signal twice when both activated() and clicked() are triggered + if (m_entryActivatedEmitted) { + return; + } + m_entryActivatedEmitted = true; + + Entry* entry = m_view->entryFromIndex(index); + accept(); + Q_EMIT entryActivated(entry, m_sequences[entry]); +} diff --git a/src/autotype/AutoTypeSelectDialog.h b/src/autotype/AutoTypeSelectDialog.h new file mode 100644 index 000000000..79084d77c --- /dev/null +++ b/src/autotype/AutoTypeSelectDialog.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2012 Felix Geyer + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef KEEPASSX_AUTOTYPESELECTDIALOG_H +#define KEEPASSX_AUTOTYPESELECTDIALOG_H + +#include +#include +#include + +#include "core/Global.h" + +class AutoTypeSelectView; +class Entry; + +class AutoTypeSelectDialog : public QDialog +{ + Q_OBJECT + +public: + explicit AutoTypeSelectDialog(QWidget* parent = Q_NULLPTR); + void setEntries(const QList& entries, const QHash& sequences); + +Q_SIGNALS: + void entryActivated(Entry* entry, const QString& sequence); + +private Q_SLOTS: + void emitEntryActivated(const QModelIndex& index); + +private: + AutoTypeSelectView* const m_view; + QHash m_sequences; + bool m_entryActivatedEmitted; +}; + +#endif // KEEPASSX_AUTOTYPESELECTDIALOG_H diff --git a/src/autotype/AutoTypeSelectView.cpp b/src/autotype/AutoTypeSelectView.cpp new file mode 100644 index 000000000..054a351c4 --- /dev/null +++ b/src/autotype/AutoTypeSelectView.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2012 Felix Geyer + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "AutoTypeSelectView.h" + +#include + +AutoTypeSelectView::AutoTypeSelectView(QWidget* parent) + : EntryView(parent) +{ + hideColumn(3); + setMouseTracking(true); + setAllColumnsShowFocus(true); +} + +void AutoTypeSelectView::setEntryList(const QList& entries) +{ + EntryView::setEntryList(entries); + + setCurrentIndex(model()->index(0, 0)); +} + +void AutoTypeSelectView::mouseMoveEvent(QMouseEvent* event) +{ + QModelIndex index = indexAt(event->pos()); + + if (index.isValid()) { + setCurrentIndex(index); + setCursor(Qt::PointingHandCursor); + } + else { + unsetCursor(); + } + + EntryView::mouseMoveEvent(event); +} diff --git a/src/autotype/AutoTypeSelectView.h b/src/autotype/AutoTypeSelectView.h new file mode 100644 index 000000000..ee3aa5742 --- /dev/null +++ b/src/autotype/AutoTypeSelectView.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2012 Felix Geyer + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef KEEPASSX_AUTOTYPESELECTVIEW_H +#define KEEPASSX_AUTOTYPESELECTVIEW_H + +#include "core/Global.h" +#include "gui/entry/EntryView.h" + +class Entry; + +class AutoTypeSelectView : public EntryView +{ + Q_OBJECT + +public: + explicit AutoTypeSelectView(QWidget* parent = Q_NULLPTR); + void setEntryList(const QList& entries) Q_DECL_OVERRIDE; + +protected: + void mouseMoveEvent(QMouseEvent* event) Q_DECL_OVERRIDE; +}; + +#endif // KEEPASSX_AUTOTYPESELECTVIEW_H