mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2025-10-12 21:40:54 -04:00
Improve Auto-Type Select Dialog
Significant improvements to the Auto-Type select dialog. Reduce stale and unnecessary code paths. * Close select dialog when databases are locked. * Close open modal dialogs prior to showing the Auto-Type select dialog to prevent interference. * Never perform Auto-Type on the KeePassXC window. * Only filter match list based on Group, Title, and Username column data (ie, ignore sequence column) * Always show the sequence column (revert feature) * Show selection dialog if there are no matches to allow for a database search * Close #3630 - Allow typing {USERNAME} and {PASSWORD} from selection dialog (right-click menu). * Close #429 - Ability to search open databases for an entry from the Auto-Type selection dialog. * Fix #5361 - Default size of selection dialog doesn't cut off matches
This commit is contained in:
parent
7ce35f81de
commit
d9ae449f04
38 changed files with 830 additions and 1047 deletions
|
@ -57,8 +57,8 @@ DatabaseTabWidget::DatabaseTabWidget(QWidget* parent)
|
|||
|
||||
// clang-format off
|
||||
connect(this, SIGNAL(tabCloseRequested(int)), SLOT(closeDatabaseTab(int)));
|
||||
connect(this, SIGNAL(currentChanged(int)), SLOT(emitActivateDatabaseChanged()));
|
||||
connect(this, SIGNAL(activateDatabaseChanged(DatabaseWidget*)),
|
||||
connect(this, SIGNAL(currentChanged(int)), SLOT(emitActiveDatabaseChanged()));
|
||||
connect(this, SIGNAL(activeDatabaseChanged(DatabaseWidget*)),
|
||||
m_dbWidgetStateSync, SLOT(setActive(DatabaseWidget*)));
|
||||
connect(autoType(), SIGNAL(globalAutoTypeTriggered()), SLOT(performGlobalAutoType()));
|
||||
connect(autoType(), SIGNAL(autotypePerformed()), SLOT(relockPendingDatabase()));
|
||||
|
@ -715,9 +715,9 @@ void DatabaseTabWidget::updateLastDatabases(const QString& filename)
|
|||
}
|
||||
}
|
||||
|
||||
void DatabaseTabWidget::emitActivateDatabaseChanged()
|
||||
void DatabaseTabWidget::emitActiveDatabaseChanged()
|
||||
{
|
||||
emit activateDatabaseChanged(currentDatabaseWidget());
|
||||
emit activeDatabaseChanged(currentDatabaseWidget());
|
||||
}
|
||||
|
||||
void DatabaseTabWidget::emitDatabaseLockChanged()
|
||||
|
|
|
@ -89,7 +89,7 @@ signals:
|
|||
void databaseClosed(const QString& filePath);
|
||||
void databaseUnlocked(DatabaseWidget* dbWidget);
|
||||
void databaseLocked(DatabaseWidget* dbWidget);
|
||||
void activateDatabaseChanged(DatabaseWidget* dbWidget);
|
||||
void activeDatabaseChanged(DatabaseWidget* dbWidget);
|
||||
void tabNameChanged();
|
||||
void tabVisibilityChanged(bool tabsVisible);
|
||||
void messageGlobal(const QString&, MessageWidget::MessageType type);
|
||||
|
@ -98,7 +98,7 @@ signals:
|
|||
|
||||
private slots:
|
||||
void toggleTabbar();
|
||||
void emitActivateDatabaseChanged();
|
||||
void emitActiveDatabaseChanged();
|
||||
void emitDatabaseLockChanged();
|
||||
|
||||
private:
|
||||
|
|
|
@ -160,14 +160,13 @@ MainWindow::MainWindow()
|
|||
|
||||
restoreGeometry(config()->get(Config::GUI_MainWindowGeometry).toByteArray());
|
||||
restoreState(config()->get(Config::GUI_MainWindowState).toByteArray());
|
||||
|
||||
connect(m_ui->tabWidget, &DatabaseTabWidget::databaseLocked, this, &MainWindow::databaseLocked);
|
||||
connect(m_ui->tabWidget, &DatabaseTabWidget::databaseUnlocked, this, &MainWindow::databaseUnlocked);
|
||||
connect(m_ui->tabWidget, &DatabaseTabWidget::activeDatabaseChanged, this, &MainWindow::activeDatabaseChanged);
|
||||
|
||||
#ifdef WITH_XC_BROWSER
|
||||
m_ui->settingsWidget->addSettingsPage(new BrowserSettingsPage());
|
||||
connect(m_ui->tabWidget, &DatabaseTabWidget::databaseLocked, browserService(), &BrowserService::databaseLocked);
|
||||
connect(m_ui->tabWidget, &DatabaseTabWidget::databaseUnlocked, browserService(), &BrowserService::databaseUnlocked);
|
||||
connect(m_ui->tabWidget,
|
||||
&DatabaseTabWidget::activateDatabaseChanged,
|
||||
browserService(),
|
||||
&BrowserService::activeDatabaseChanged);
|
||||
connect(
|
||||
browserService(), &BrowserService::requestUnlock, m_ui->tabWidget, &DatabaseTabWidget::performBrowserUnlock);
|
||||
#endif
|
||||
|
@ -411,7 +410,7 @@ MainWindow::MainWindow()
|
|||
|
||||
// Notify search when the active database changes or gets locked
|
||||
connect(m_ui->tabWidget,
|
||||
SIGNAL(activateDatabaseChanged(DatabaseWidget*)),
|
||||
SIGNAL(activeDatabaseChanged(DatabaseWidget*)),
|
||||
m_searchWidget,
|
||||
SLOT(databaseChanged(DatabaseWidget*)));
|
||||
connect(m_ui->tabWidget, SIGNAL(databaseLocked(DatabaseWidget*)), m_searchWidget, SLOT(databaseChanged()));
|
||||
|
|
|
@ -60,6 +60,11 @@ public:
|
|||
PasswordGeneratorScreen = 3
|
||||
};
|
||||
|
||||
signals:
|
||||
void databaseUnlocked(DatabaseWidget* dbWidget);
|
||||
void databaseLocked(DatabaseWidget* dbWidget);
|
||||
void activeDatabaseChanged(DatabaseWidget* dbWidget);
|
||||
|
||||
public slots:
|
||||
void openDatabase(const QString& filePath, const QString& password = {}, const QString& keyfile = {});
|
||||
void appExit();
|
||||
|
@ -136,8 +141,6 @@ private slots:
|
|||
void obtainContextFocusLock();
|
||||
void releaseContextFocusLock();
|
||||
void agentEnabled(bool enabled);
|
||||
|
||||
private slots:
|
||||
void updateTrayIcon();
|
||||
|
||||
private:
|
||||
|
|
|
@ -118,7 +118,7 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_16">
|
||||
<widget class="QLabel" name="label_25">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>10</width>
|
||||
|
|
|
@ -51,8 +51,8 @@ SearchWidget::SearchWidget(QWidget* parent)
|
|||
connect(m_clearSearchTimer, SIGNAL(timeout()), m_ui->searchEdit, SLOT(clear()));
|
||||
connect(this, SIGNAL(escapePressed()), m_ui->searchEdit, SLOT(clear()));
|
||||
|
||||
new QShortcut(QKeySequence::Find, this, SLOT(searchFocus()), nullptr, Qt::ApplicationShortcut);
|
||||
new QShortcut(Qt::Key_Escape, m_ui->searchEdit, SLOT(clear()), nullptr, Qt::ApplicationShortcut);
|
||||
new QShortcut(QKeySequence::Find, this, SLOT(searchFocus()));
|
||||
new QShortcut(Qt::Key_Escape, m_ui->searchEdit, SLOT(clear()));
|
||||
|
||||
m_ui->searchEdit->setPlaceholderText(tr("Search (%1)…", "Search placeholder text, %1 is the keyboard shortcut")
|
||||
.arg(QKeySequence(QKeySequence::Find).toString(QKeySequence::NativeText)));
|
||||
|
|
|
@ -1,195 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2015 David Wu <lightvector@gmail.com>
|
||||
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "AutoTypeMatchModel.h"
|
||||
|
||||
#include <QFont>
|
||||
|
||||
#include "core/DatabaseIcons.h"
|
||||
#include "core/Entry.h"
|
||||
#include "core/Global.h"
|
||||
#include "core/Group.h"
|
||||
#include "core/Metadata.h"
|
||||
|
||||
AutoTypeMatchModel::AutoTypeMatchModel(QObject* parent)
|
||||
: QAbstractTableModel(parent)
|
||||
{
|
||||
}
|
||||
|
||||
AutoTypeMatch AutoTypeMatchModel::matchFromIndex(const QModelIndex& index) const
|
||||
{
|
||||
Q_ASSERT(index.isValid() && index.row() < m_matches.size());
|
||||
return m_matches.at(index.row());
|
||||
}
|
||||
|
||||
QModelIndex AutoTypeMatchModel::indexFromMatch(const AutoTypeMatch& match) const
|
||||
{
|
||||
int row = m_matches.indexOf(match);
|
||||
Q_ASSERT(row != -1);
|
||||
return index(row, 1);
|
||||
}
|
||||
|
||||
void AutoTypeMatchModel::setMatchList(const QList<AutoTypeMatch>& matches)
|
||||
{
|
||||
beginResetModel();
|
||||
|
||||
severConnections();
|
||||
|
||||
m_allGroups.clear();
|
||||
m_matches = matches;
|
||||
|
||||
QSet<Database*> databases;
|
||||
|
||||
for (AutoTypeMatch& match : m_matches) {
|
||||
databases.insert(match.entry->group()->database());
|
||||
}
|
||||
|
||||
for (Database* db : asConst(databases)) {
|
||||
Q_ASSERT(db);
|
||||
for (const Group* group : db->rootGroup()->groupsRecursive(true)) {
|
||||
m_allGroups.append(group);
|
||||
}
|
||||
|
||||
if (db->metadata()->recycleBin()) {
|
||||
m_allGroups.removeOne(db->metadata()->recycleBin());
|
||||
}
|
||||
}
|
||||
|
||||
for (const Group* group : asConst(m_allGroups)) {
|
||||
makeConnections(group);
|
||||
}
|
||||
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
int AutoTypeMatchModel::rowCount(const QModelIndex& parent) const
|
||||
{
|
||||
if (parent.isValid()) {
|
||||
return 0;
|
||||
}
|
||||
return m_matches.size();
|
||||
}
|
||||
|
||||
int AutoTypeMatchModel::columnCount(const QModelIndex& parent) const
|
||||
{
|
||||
Q_UNUSED(parent);
|
||||
|
||||
return 4;
|
||||
}
|
||||
|
||||
QVariant AutoTypeMatchModel::data(const QModelIndex& index, int role) const
|
||||
{
|
||||
if (!index.isValid()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
AutoTypeMatch match = matchFromIndex(index);
|
||||
|
||||
if (role == Qt::DisplayRole) {
|
||||
switch (index.column()) {
|
||||
case ParentGroup:
|
||||
if (match.entry->group()) {
|
||||
return match.entry->group()->name();
|
||||
}
|
||||
break;
|
||||
case Title:
|
||||
return match.entry->resolveMultiplePlaceholders(match.entry->title());
|
||||
case Username:
|
||||
return match.entry->resolveMultiplePlaceholders(match.entry->username());
|
||||
case Sequence:
|
||||
return match.sequence;
|
||||
}
|
||||
} else if (role == Qt::DecorationRole) {
|
||||
switch (index.column()) {
|
||||
case ParentGroup:
|
||||
if (match.entry->group()) {
|
||||
return match.entry->group()->iconPixmap();
|
||||
}
|
||||
break;
|
||||
case Title:
|
||||
return match.entry->iconPixmap();
|
||||
}
|
||||
} else if (role == Qt::FontRole) {
|
||||
QFont font;
|
||||
if (match.entry->isExpired()) {
|
||||
font.setStrikeOut(true);
|
||||
}
|
||||
return font;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
QVariant AutoTypeMatchModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
|
||||
switch (section) {
|
||||
case ParentGroup:
|
||||
return tr("Group");
|
||||
case Title:
|
||||
return tr("Title");
|
||||
case Username:
|
||||
return tr("Username");
|
||||
case Sequence:
|
||||
return tr("Sequence");
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void AutoTypeMatchModel::entryDataChanged(Entry* entry)
|
||||
{
|
||||
for (int row = 0; row < m_matches.size(); ++row) {
|
||||
AutoTypeMatch match = m_matches[row];
|
||||
if (match.entry == entry) {
|
||||
emit dataChanged(index(row, 0), index(row, columnCount() - 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AutoTypeMatchModel::entryAboutToRemove(Entry* entry)
|
||||
{
|
||||
for (int row = 0; row < m_matches.size(); ++row) {
|
||||
AutoTypeMatch match = m_matches[row];
|
||||
if (match.entry == entry) {
|
||||
beginRemoveRows(QModelIndex(), row, row);
|
||||
m_matches.removeAt(row);
|
||||
endRemoveRows();
|
||||
--row;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AutoTypeMatchModel::entryRemoved()
|
||||
{
|
||||
}
|
||||
|
||||
void AutoTypeMatchModel::severConnections()
|
||||
{
|
||||
for (const Group* group : asConst(m_allGroups)) {
|
||||
disconnect(group, nullptr, this, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void AutoTypeMatchModel::makeConnections(const Group* group)
|
||||
{
|
||||
connect(group, SIGNAL(entryAboutToRemove(Entry*)), SLOT(entryAboutToRemove(Entry*)));
|
||||
connect(group, SIGNAL(entryRemoved(Entry*)), SLOT(entryRemoved()));
|
||||
connect(group, SIGNAL(entryDataChanged(Entry*)), SLOT(entryDataChanged(Entry*)));
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2015 David Wu <lightvector@gmail.com>
|
||||
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef KEEPASSX_AUTOTYPEMATCHMODEL_H
|
||||
#define KEEPASSX_AUTOTYPEMATCHMODEL_H
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
|
||||
#include "core/AutoTypeMatch.h"
|
||||
|
||||
class Entry;
|
||||
class Group;
|
||||
|
||||
class AutoTypeMatchModel : public QAbstractTableModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum ModelColumn
|
||||
{
|
||||
ParentGroup = 0,
|
||||
Title = 1,
|
||||
Username = 2,
|
||||
Sequence = 3
|
||||
};
|
||||
|
||||
explicit AutoTypeMatchModel(QObject* parent = nullptr);
|
||||
AutoTypeMatch matchFromIndex(const QModelIndex& index) const;
|
||||
QModelIndex indexFromMatch(const AutoTypeMatch& match) const;
|
||||
|
||||
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||
int columnCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
||||
|
||||
void setMatchList(const QList<AutoTypeMatch>& matches);
|
||||
|
||||
private slots:
|
||||
void entryAboutToRemove(Entry* entry);
|
||||
void entryRemoved();
|
||||
void entryDataChanged(Entry* entry);
|
||||
|
||||
private:
|
||||
void severConnections();
|
||||
void makeConnections(const Group* group);
|
||||
|
||||
QList<AutoTypeMatch> m_matches;
|
||||
QList<const Group*> m_allGroups;
|
||||
};
|
||||
|
||||
#endif // KEEPASSX_AUTOTYPEMATCHMODEL_H
|
|
@ -1,154 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2015 David Wu <lightvector@gmail.com>
|
||||
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "AutoTypeMatchView.h"
|
||||
|
||||
#include "core/Entry.h"
|
||||
#include "gui/Clipboard.h"
|
||||
#include "gui/SortFilterHideProxyModel.h"
|
||||
|
||||
#include <QAction>
|
||||
#include <QHeaderView>
|
||||
#include <QKeyEvent>
|
||||
|
||||
AutoTypeMatchView::AutoTypeMatchView(QWidget* parent)
|
||||
: QTreeView(parent)
|
||||
, m_model(new AutoTypeMatchModel(this))
|
||||
, m_sortModel(new SortFilterHideProxyModel(this))
|
||||
{
|
||||
m_sortModel->setSourceModel(m_model);
|
||||
m_sortModel->setDynamicSortFilter(true);
|
||||
m_sortModel->setSortLocaleAware(true);
|
||||
m_sortModel->setSortCaseSensitivity(Qt::CaseInsensitive);
|
||||
setModel(m_sortModel);
|
||||
|
||||
setUniformRowHeights(true);
|
||||
setRootIsDecorated(false);
|
||||
setAlternatingRowColors(true);
|
||||
setDragEnabled(false);
|
||||
setSortingEnabled(true);
|
||||
setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
header()->setDefaultSectionSize(150);
|
||||
|
||||
setContextMenuPolicy(Qt::ActionsContextMenu);
|
||||
auto* copyUserNameAction = new QAction(tr("Copy &username"), this);
|
||||
auto* copyPasswordAction = new QAction(tr("Copy &password"), this);
|
||||
addAction(copyUserNameAction);
|
||||
addAction(copyPasswordAction);
|
||||
|
||||
connect(copyUserNameAction, SIGNAL(triggered()), this, SLOT(userNameCopied()));
|
||||
connect(copyPasswordAction, SIGNAL(triggered()), this, SLOT(passwordCopied()));
|
||||
|
||||
connect(this, SIGNAL(doubleClicked(QModelIndex)), SLOT(emitMatchActivated(QModelIndex)));
|
||||
// clang-format off
|
||||
connect(selectionModel(),
|
||||
SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
|
||||
SIGNAL(matchSelectionChanged()));
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
void AutoTypeMatchView::userNameCopied()
|
||||
{
|
||||
clipboard()->setText(currentMatch().entry->username());
|
||||
emit matchTextCopied();
|
||||
}
|
||||
|
||||
void AutoTypeMatchView::passwordCopied()
|
||||
{
|
||||
clipboard()->setText(currentMatch().entry->password());
|
||||
emit matchTextCopied();
|
||||
}
|
||||
|
||||
void AutoTypeMatchView::keyPressEvent(QKeyEvent* event)
|
||||
{
|
||||
if ((event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) && currentIndex().isValid()) {
|
||||
emitMatchActivated(currentIndex());
|
||||
#ifdef Q_OS_MACOS
|
||||
// Pressing return does not emit the QTreeView::activated signal on mac os
|
||||
emit activated(currentIndex());
|
||||
#endif
|
||||
}
|
||||
|
||||
QTreeView::keyPressEvent(event);
|
||||
}
|
||||
|
||||
void AutoTypeMatchView::setMatchList(const QList<AutoTypeMatch>& matches)
|
||||
{
|
||||
m_model->setMatchList(matches);
|
||||
|
||||
bool sameSequences = true;
|
||||
if (matches.count() > 1) {
|
||||
QString sequenceTest = matches[0].sequence;
|
||||
for (const auto& match : matches) {
|
||||
if (match.sequence != sequenceTest) {
|
||||
sameSequences = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
setColumnHidden(AutoTypeMatchModel::Sequence, sameSequences);
|
||||
|
||||
for (int i = 0; i < m_model->columnCount(); ++i) {
|
||||
resizeColumnToContents(i);
|
||||
if (columnWidth(i) > 250) {
|
||||
setColumnWidth(i, 250);
|
||||
}
|
||||
}
|
||||
|
||||
setFirstMatchActive();
|
||||
}
|
||||
|
||||
void AutoTypeMatchView::setFirstMatchActive()
|
||||
{
|
||||
if (m_model->rowCount() > 0) {
|
||||
QModelIndex index = m_sortModel->mapToSource(m_sortModel->index(0, 0));
|
||||
setCurrentMatch(m_model->matchFromIndex(index));
|
||||
} else {
|
||||
emit matchSelectionChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void AutoTypeMatchView::emitMatchActivated(const QModelIndex& index)
|
||||
{
|
||||
AutoTypeMatch match = matchFromIndex(index);
|
||||
|
||||
emit matchActivated(match);
|
||||
}
|
||||
|
||||
AutoTypeMatch AutoTypeMatchView::currentMatch()
|
||||
{
|
||||
QModelIndexList list = selectionModel()->selectedRows();
|
||||
if (list.size() == 1) {
|
||||
return m_model->matchFromIndex(m_sortModel->mapToSource(list.first()));
|
||||
}
|
||||
return AutoTypeMatch();
|
||||
}
|
||||
|
||||
void AutoTypeMatchView::setCurrentMatch(const AutoTypeMatch& match)
|
||||
{
|
||||
selectionModel()->setCurrentIndex(m_sortModel->mapFromSource(m_model->indexFromMatch(match)),
|
||||
QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
|
||||
}
|
||||
|
||||
AutoTypeMatch AutoTypeMatchView::matchFromIndex(const QModelIndex& index)
|
||||
{
|
||||
if (index.isValid()) {
|
||||
return m_model->matchFromIndex(m_sortModel->mapToSource(index));
|
||||
}
|
||||
return AutoTypeMatch();
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2015 David Wu <lightvector@gmail.com>
|
||||
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef KEEPASSX_AUTOTYPEMATCHVIEW_H
|
||||
#define KEEPASSX_AUTOTYPEMATCHVIEW_H
|
||||
|
||||
#include <QTreeView>
|
||||
|
||||
#include "core/AutoTypeMatch.h"
|
||||
|
||||
#include "gui/entry/AutoTypeMatchModel.h"
|
||||
|
||||
class SortFilterHideProxyModel;
|
||||
|
||||
class AutoTypeMatchView : public QTreeView
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AutoTypeMatchView(QWidget* parent = nullptr);
|
||||
AutoTypeMatch currentMatch();
|
||||
void setCurrentMatch(const AutoTypeMatch& match);
|
||||
AutoTypeMatch matchFromIndex(const QModelIndex& index);
|
||||
void setMatchList(const QList<AutoTypeMatch>& matches);
|
||||
void setFirstMatchActive();
|
||||
|
||||
signals:
|
||||
void matchActivated(AutoTypeMatch match);
|
||||
void matchSelectionChanged();
|
||||
void matchTextCopied();
|
||||
|
||||
protected:
|
||||
void keyPressEvent(QKeyEvent* event) override;
|
||||
|
||||
private slots:
|
||||
void emitMatchActivated(const QModelIndex& index);
|
||||
void userNameCopied();
|
||||
void passwordCopied();
|
||||
|
||||
private:
|
||||
AutoTypeMatchModel* const m_model;
|
||||
SortFilterHideProxyModel* const m_sortModel;
|
||||
};
|
||||
|
||||
#endif // KEEPASSX_AUTOTYPEMATCHVIEW_H
|
Loading…
Add table
Add a link
Reference in a new issue