mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2024-10-01 01:26:01 -04:00
parent
f836629dda
commit
6b6c109903
@ -465,8 +465,9 @@ void Entry::setGroup(Group* group)
|
||||
}
|
||||
}
|
||||
|
||||
group->addEntry(this);
|
||||
m_group = group;
|
||||
group->addEntry(this);
|
||||
|
||||
QObject::setParent(group);
|
||||
|
||||
if (m_updateTimeinfo) {
|
||||
@ -488,3 +489,11 @@ const Database* Entry::database() const
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool Entry::match(const QString& searchTerm, Qt::CaseSensitivity caseSensitivity)
|
||||
{
|
||||
return title().contains(searchTerm, caseSensitivity) ||
|
||||
username().contains(searchTerm, caseSensitivity) ||
|
||||
url().contains(searchTerm, caseSensitivity) ||
|
||||
notes().contains(searchTerm, caseSensitivity);
|
||||
}
|
||||
|
@ -126,6 +126,7 @@ public:
|
||||
void setGroup(Group* group);
|
||||
|
||||
void setUpdateTimeinfo(bool value);
|
||||
bool match(const QString &searchTerm, Qt::CaseSensitivity caseSensitivity);
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
|
@ -487,3 +487,45 @@ void Group::recCreateDelObjects()
|
||||
m_db->addDeletedObject(m_uuid);
|
||||
}
|
||||
}
|
||||
|
||||
QList<Entry*> Group::search(const QString& searchTerm, Qt::CaseSensitivity caseSensitivity,
|
||||
bool resolveInherit)
|
||||
{
|
||||
QList<Entry*> searchResult;
|
||||
if (includeInSearch(resolveInherit)) {
|
||||
Q_FOREACH (Entry* entry, m_entries) {
|
||||
if (entry->match(searchTerm, caseSensitivity)) {
|
||||
searchResult.append(entry);
|
||||
}
|
||||
}
|
||||
Q_FOREACH (Group* group, m_children) {
|
||||
searchResult.append(group->search(searchTerm, caseSensitivity, false));
|
||||
}
|
||||
}
|
||||
return searchResult;
|
||||
}
|
||||
|
||||
bool Group::includeInSearch(bool resolveInherit)
|
||||
{
|
||||
switch (m_searchingEnabled) {
|
||||
case Inherit:
|
||||
if (!m_parent) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
if (resolveInherit) {
|
||||
return m_parent->includeInSearch(true);
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
case Enable:
|
||||
return true;
|
||||
case Disable:
|
||||
return false;
|
||||
default:
|
||||
Q_ASSERT(false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -76,8 +76,10 @@ public:
|
||||
QList<Entry*> entries();
|
||||
const QList<Entry*>& entries() const;
|
||||
QList<Entry*> entriesRecursive(bool includeHistoryItems = false) const;
|
||||
QList<const Group *> groupsRecursive(bool includeSelf) const;
|
||||
QList<const Group*> groupsRecursive(bool includeSelf) const;
|
||||
|
||||
QList<Entry*> search(const QString& searchTerm, Qt::CaseSensitivity caseSensitivity,
|
||||
bool resolveInherit = true);
|
||||
|
||||
Q_SIGNALS:
|
||||
void dataChanged(Group* group);
|
||||
@ -136,6 +138,8 @@ private:
|
||||
friend void Database::setRootGroup(Group* group);
|
||||
friend Entry::~Entry();
|
||||
friend void Entry::setGroup(Group* group);
|
||||
|
||||
bool includeInSearch(bool resolveInherit);
|
||||
};
|
||||
|
||||
#endif // KEEPASSX_GROUP_H
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <QtGui/QHBoxLayout>
|
||||
#include <QtGui/QLabel>
|
||||
#include <QtGui/QSplitter>
|
||||
#include <QtGui/QLineEdit>
|
||||
#include <QtGui/QMessageBox>
|
||||
|
||||
#include "core/Metadata.h"
|
||||
@ -53,12 +54,22 @@ DatabaseWidget::DatabaseWidget(Database* db, QWidget* parent)
|
||||
policy.setHorizontalStretch(30);
|
||||
m_groupView->setSizePolicy(policy);
|
||||
|
||||
policy = m_entryView->sizePolicy();
|
||||
QWidget* widget = new QWidget();
|
||||
policy = widget->sizePolicy();
|
||||
policy.setHorizontalStretch(70);
|
||||
m_entryView->setSizePolicy(policy);
|
||||
widget->setSizePolicy(policy);
|
||||
|
||||
splitter->addWidget(m_groupView);
|
||||
splitter->addWidget(m_entryView);
|
||||
|
||||
QVBoxLayout* vLayout = new QVBoxLayout();
|
||||
QHBoxLayout* hLayout = new QHBoxLayout();
|
||||
hLayout->addWidget(new QLabel("Find:"));
|
||||
m_searchEdit = new QLineEdit();
|
||||
hLayout->addWidget(m_searchEdit);
|
||||
vLayout->addLayout(hLayout);
|
||||
vLayout->addWidget(m_entryView);
|
||||
widget->setLayout(vLayout);
|
||||
splitter->addWidget(widget);
|
||||
|
||||
layout->addWidget(splitter);
|
||||
m_mainWidget->setLayout(layout);
|
||||
@ -87,6 +98,7 @@ DatabaseWidget::DatabaseWidget(Database* db, QWidget* parent)
|
||||
connect(m_changeMasterKeyWidget, SIGNAL(editFinished(bool)), SLOT(updateMasterKey(bool)));
|
||||
connect(m_databaseSettingsWidget, SIGNAL(editFinished(bool)), SLOT(updateSettings(bool)));
|
||||
connect(this, SIGNAL(currentChanged(int)), this, SLOT(emitCurrentModeChanged()));
|
||||
connect(m_searchEdit, SIGNAL(returnPressed()), this, SLOT(search()));
|
||||
|
||||
setCurrentIndex(0);
|
||||
}
|
||||
@ -311,6 +323,15 @@ void DatabaseWidget::switchToDatabaseSettings()
|
||||
setCurrentIndex(4);
|
||||
}
|
||||
|
||||
void DatabaseWidget::search()
|
||||
{
|
||||
Group* searchGroup = m_db->rootGroup();
|
||||
QList<Entry*> searchResult = searchGroup->search(m_searchEdit->text(), Qt::CaseInsensitive);
|
||||
|
||||
m_groupView->setCurrentIndex(QModelIndex());
|
||||
m_entryView->search(searchResult);
|
||||
}
|
||||
|
||||
bool DatabaseWidget::dbHasKey()
|
||||
{
|
||||
return m_db->hasKey();
|
||||
|
@ -20,6 +20,8 @@
|
||||
|
||||
#include <QtGui/QStackedWidget>
|
||||
|
||||
class QLineEdit;
|
||||
|
||||
class ChangeMasterKeyWidget;
|
||||
class DatabaseSettingsWidget;
|
||||
class Database;
|
||||
@ -64,6 +66,7 @@ public Q_SLOTS:
|
||||
void switchToGroupEdit();
|
||||
void switchToMasterKeyChange();
|
||||
void switchToDatabaseSettings();
|
||||
void search();
|
||||
|
||||
private Q_SLOTS:
|
||||
void switchToView(bool accepted);
|
||||
@ -86,6 +89,7 @@ private:
|
||||
Group* m_newGroup;
|
||||
Entry* m_newEntry;
|
||||
Group* m_newParent;
|
||||
QLineEdit* m_searchEdit;
|
||||
};
|
||||
|
||||
#endif // KEEPASSX_DATABASEWIDGET_H
|
||||
|
@ -31,45 +31,67 @@ EntryModel::EntryModel(QObject* parent)
|
||||
|
||||
Entry* EntryModel::entryFromIndex(const QModelIndex& index) const
|
||||
{
|
||||
Q_ASSERT(index.isValid() && index.row() < m_group->entries().size());
|
||||
return m_group->entries().at(index.row());
|
||||
Q_ASSERT(index.isValid() && index.row() < m_entries.size());
|
||||
return m_entries.at(index.row());
|
||||
}
|
||||
|
||||
QModelIndex EntryModel::indexFromEntry(Entry* entry) const
|
||||
{
|
||||
int row = m_group->entries().indexOf(entry);
|
||||
int row = m_entries.indexOf(entry);
|
||||
Q_ASSERT(row != -1);
|
||||
return index(row, 0);
|
||||
}
|
||||
|
||||
void EntryModel::setGroup(Group* group)
|
||||
{
|
||||
if (group == m_group) {
|
||||
if (!group || group == m_group) {
|
||||
return;
|
||||
}
|
||||
|
||||
beginResetModel();
|
||||
|
||||
if (m_group) {
|
||||
disconnect(m_group, 0, this, 0);
|
||||
}
|
||||
severConnections();
|
||||
|
||||
m_group = group;
|
||||
connect(group, SIGNAL(entryAboutToAdd(Entry*)), SLOT(entryAboutToAdd(Entry*)));
|
||||
connect(group, SIGNAL(entryAdded()), SLOT(entryAdded()));
|
||||
connect(group, SIGNAL(entryAboutToRemove(Entry*)), SLOT(entryAboutToRemove(Entry*)));
|
||||
connect(group, SIGNAL(entryRemoved()), SLOT(entryRemoved()));
|
||||
connect(group, SIGNAL(entryDataChanged(Entry*)), SLOT(entryDataChanged(Entry*)));
|
||||
m_entries = group->entries();
|
||||
|
||||
makeConnections(group);
|
||||
|
||||
endResetModel();
|
||||
Q_EMIT switchedToView();
|
||||
}
|
||||
|
||||
void EntryModel::setEntries(QList<Entry*> entries)
|
||||
{
|
||||
beginResetModel();
|
||||
|
||||
severConnections();
|
||||
|
||||
m_group = 0;
|
||||
m_allGroups.clear();
|
||||
m_entries = entries;
|
||||
|
||||
if (entries.count() > 0) {
|
||||
m_allGroups = entries.at(0)->group()->database()->rootGroup()->groupsRecursive(true);
|
||||
}
|
||||
|
||||
QListIterator<const Group*> iGroups(m_allGroups);
|
||||
while (iGroups.hasNext()) {
|
||||
const Group* group = iGroups.next();
|
||||
makeConnections(group);
|
||||
}
|
||||
|
||||
endResetModel();
|
||||
Q_EMIT switchedToSearch();
|
||||
}
|
||||
|
||||
int EntryModel::rowCount(const QModelIndex& parent) const
|
||||
{
|
||||
if (!m_group || parent.isValid()) {
|
||||
if (parent.isValid()) {
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
return m_group->entries().size();
|
||||
return m_entries.size();
|
||||
}
|
||||
}
|
||||
|
||||
@ -77,7 +99,7 @@ int EntryModel::columnCount(const QModelIndex& parent) const
|
||||
{
|
||||
Q_UNUSED(parent);
|
||||
|
||||
return 3;
|
||||
return 4;
|
||||
}
|
||||
|
||||
QVariant EntryModel::data(const QModelIndex& index, int role) const
|
||||
@ -91,15 +113,26 @@ QVariant EntryModel::data(const QModelIndex& index, int role) const
|
||||
if (role == Qt::DisplayRole) {
|
||||
switch (index.column()) {
|
||||
case 0:
|
||||
return entry->title();
|
||||
if (entry->group()) {
|
||||
return entry->group()->name();
|
||||
}
|
||||
case 1:
|
||||
return entry->username();
|
||||
return entry->title();
|
||||
case 2:
|
||||
return entry->username();
|
||||
case 3:
|
||||
return entry->url();
|
||||
}
|
||||
}
|
||||
else if ((role == Qt::DecorationRole) && (index.column() == 0)) {
|
||||
return entry->iconPixmap();
|
||||
else if (role == Qt::DecorationRole) {
|
||||
switch (index.column()) {
|
||||
case 0:
|
||||
if (entry->group()) {
|
||||
return entry->group()->iconPixmap();
|
||||
}
|
||||
case 1:
|
||||
return entry->iconPixmap();
|
||||
}
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
@ -109,10 +142,12 @@ QVariant EntryModel::headerData(int section, Qt::Orientation orientation, int ro
|
||||
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
|
||||
switch (section) {
|
||||
case 0:
|
||||
return tr("Title");
|
||||
return tr("Group");
|
||||
case 1:
|
||||
return tr("Username");
|
||||
return tr("Title");
|
||||
case 2:
|
||||
return tr("Username");
|
||||
case 3:
|
||||
return tr("URL");
|
||||
}
|
||||
}
|
||||
@ -156,7 +191,8 @@ QMimeData* EntryModel::mimeData(const QModelIndexList& indexes) const
|
||||
if (!indexes[i].isValid()) {
|
||||
continue;
|
||||
}
|
||||
stream << m_group->database()->uuid() << entryFromIndex(indexes[i])->uuid();
|
||||
Entry* entry = entryFromIndex(indexes[i]);
|
||||
stream << entry->group()->database()->uuid() << entry->uuid();
|
||||
}
|
||||
|
||||
data->setData(mimeTypes().first(), encoded);
|
||||
@ -167,26 +203,61 @@ void EntryModel::entryAboutToAdd(Entry* entry)
|
||||
{
|
||||
Q_UNUSED(entry);
|
||||
|
||||
beginInsertRows(QModelIndex(), m_group->entries().size(), m_group->entries().size());
|
||||
beginInsertRows(QModelIndex(), m_entries.size(), m_entries.size());
|
||||
if (!m_group) {
|
||||
m_entries.append(entry);
|
||||
}
|
||||
}
|
||||
|
||||
void EntryModel::entryAdded()
|
||||
{
|
||||
if (m_group) {
|
||||
m_entries = m_group->entries();
|
||||
}
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
void EntryModel::entryAboutToRemove(Entry* entry)
|
||||
{
|
||||
beginRemoveRows(QModelIndex(), m_group->entries().indexOf(entry), m_group->entries().indexOf(entry));
|
||||
beginRemoveRows(QModelIndex(), m_entries.indexOf(entry), m_entries.indexOf(entry));
|
||||
if (!m_group) {
|
||||
m_entries.removeAll(entry);
|
||||
}
|
||||
}
|
||||
|
||||
void EntryModel::entryRemoved()
|
||||
{
|
||||
if (m_group) {
|
||||
m_entries = m_group->entries();
|
||||
}
|
||||
|
||||
endRemoveRows();
|
||||
}
|
||||
|
||||
void EntryModel::entryDataChanged(Entry* entry)
|
||||
{
|
||||
int row = m_group->entries().indexOf(entry);
|
||||
int row = m_entries.indexOf(entry);
|
||||
Q_EMIT dataChanged(index(row, 0), index(row, columnCount()-1));
|
||||
}
|
||||
|
||||
void EntryModel::severConnections()
|
||||
{
|
||||
if (m_group) {
|
||||
disconnect(m_group, 0, this, 0);
|
||||
}
|
||||
|
||||
QListIterator<const Group*> i(m_allGroups);
|
||||
while (i.hasNext()) {
|
||||
const Group* group = i.next();
|
||||
disconnect(group, 0, this, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void EntryModel::makeConnections(const Group *group)
|
||||
{
|
||||
connect(group, SIGNAL(entryAboutToAdd(Entry*)), SLOT(entryAboutToAdd(Entry*)));
|
||||
connect(group, SIGNAL(entryAdded()), SLOT(entryAdded()));
|
||||
connect(group, SIGNAL(entryAboutToRemove(Entry*)), SLOT(entryAboutToRemove(Entry*)));
|
||||
connect(group, SIGNAL(entryRemoved()), SLOT(entryRemoved()));
|
||||
connect(group, SIGNAL(entryDataChanged(Entry*)), SLOT(entryDataChanged(Entry*)));
|
||||
}
|
||||
|
@ -41,6 +41,12 @@ public:
|
||||
QStringList mimeTypes() const;
|
||||
QMimeData* mimeData(const QModelIndexList& indexes) const;
|
||||
|
||||
void setEntries(QList<Entry*> entries);
|
||||
|
||||
Q_SIGNALS:
|
||||
void switchedToSearch();
|
||||
void switchedToView();
|
||||
|
||||
public Q_SLOTS:
|
||||
void setGroup(Group* group);
|
||||
|
||||
@ -53,6 +59,11 @@ private Q_SLOTS:
|
||||
|
||||
private:
|
||||
Group* m_group;
|
||||
QList<Entry*> m_entries;
|
||||
QList<const Group*> m_allGroups;
|
||||
|
||||
void severConnections();
|
||||
void makeConnections(const Group* group);
|
||||
};
|
||||
|
||||
#endif // KEEPASSX_ENTRYMODEL_H
|
||||
|
@ -40,6 +40,8 @@ EntryView::EntryView(QWidget* parent)
|
||||
|
||||
connect(this, SIGNAL(activated(const QModelIndex&)), SLOT(emitEntryActivated(const QModelIndex&)));
|
||||
connect(selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SIGNAL(entrySelectionChanged()));
|
||||
connect(m_model, SIGNAL(switchedToSearch()), this, SLOT(switchToSearch()));
|
||||
connect(m_model, SIGNAL(switchedToView()), this, SLOT(switchToView()));
|
||||
|
||||
sortByColumn(0, Qt::AscendingOrder);
|
||||
}
|
||||
@ -50,6 +52,12 @@ void EntryView::setGroup(Group* group)
|
||||
Q_EMIT entrySelectionChanged();
|
||||
}
|
||||
|
||||
void EntryView::search(QList<Entry*> entries)
|
||||
{
|
||||
m_model->setEntries(entries);
|
||||
Q_EMIT entrySelectionChanged();
|
||||
}
|
||||
|
||||
void EntryView::emitEntryActivated(const QModelIndex& index)
|
||||
{
|
||||
Q_EMIT entryActivated(entryFromIndex(index));
|
||||
@ -86,3 +94,13 @@ Entry* EntryView::entryFromIndex(const QModelIndex& index)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void EntryView::switchToSearch()
|
||||
{
|
||||
showColumn(0);
|
||||
}
|
||||
|
||||
void EntryView::switchToView()
|
||||
{
|
||||
hideColumn(0);
|
||||
}
|
||||
|
@ -36,12 +36,15 @@ public:
|
||||
bool isSingleEntrySelected();
|
||||
void setCurrentEntry(Entry* entry);
|
||||
Entry* entryFromIndex(const QModelIndex& index);
|
||||
void search(QList<Entry *> entries);
|
||||
|
||||
public Q_SLOTS:
|
||||
void setGroup(Group* group);
|
||||
|
||||
private Q_SLOTS:
|
||||
void emitEntryActivated(const QModelIndex& index);
|
||||
void switchToSearch();
|
||||
void switchToView();
|
||||
|
||||
Q_SIGNALS:
|
||||
void entryActivated(Entry* entry);
|
||||
|
@ -63,7 +63,12 @@ void GroupView::dragMoveEvent(QDragMoveEvent* event)
|
||||
|
||||
Group* GroupView::currentGroup()
|
||||
{
|
||||
return m_model->groupFromIndex(currentIndex());
|
||||
if (currentIndex() == QModelIndex()) {
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
return m_model->groupFromIndex(currentIndex());
|
||||
}
|
||||
}
|
||||
|
||||
void GroupView::expandedChanged(const QModelIndex& index)
|
||||
|
@ -62,8 +62,8 @@ void TestEntryModel::test()
|
||||
entry1->setTitle("changed");
|
||||
QCOMPARE(spyDataChanged.count(), 1);
|
||||
|
||||
QModelIndex index1 = model->index(0, 0);
|
||||
QModelIndex index2 = model->index(1, 0);
|
||||
QModelIndex index1 = model->index(0, 1);
|
||||
QModelIndex index2 = model->index(1, 1);
|
||||
|
||||
QCOMPARE(model->data(index1).toString(), entry1->title());
|
||||
QCOMPARE(model->data(index2).toString(), entry2->title());
|
||||
|
@ -74,7 +74,7 @@ void TestGui::testEditEntry()
|
||||
DatabaseTabWidget* tabWidget = m_mainWindow->findChild<DatabaseTabWidget*>("tabWidget");
|
||||
DatabaseWidget* dbWidget = tabWidget->currentDatabaseWidget();
|
||||
EntryView* entryView = dbWidget->findChild<EntryView*>("entryView");
|
||||
QModelIndex item = entryView->model()->index(0, 0);
|
||||
QModelIndex item = entryView->model()->index(0, 1);
|
||||
QRect itemRect = entryView->visualRect(item);
|
||||
QTest::mouseClick(entryView->viewport(), Qt::LeftButton, Qt::NoModifier, itemRect.center());
|
||||
QTest::qWait(20);
|
||||
@ -126,7 +126,7 @@ void TestGui::testAddEntry()
|
||||
QTest::qWait(20);
|
||||
|
||||
QCOMPARE(dbWidget->currentMode(), DatabaseWidget::ViewMode);
|
||||
QModelIndex item = entryView->model()->index(1, 0);
|
||||
QModelIndex item = entryView->model()->index(1, 1);
|
||||
Entry* entry = entryView->entryFromIndex(item);
|
||||
|
||||
QCOMPARE(entry->title(), QString("test"));
|
||||
|
Loading…
Reference in New Issue
Block a user