Quick GUI: Hide entries and their children when deleted
This commit is contained in:
parent
55eddd3fed
commit
316f1ee2a7
|
@ -11,7 +11,7 @@ Kirigami.ScrollablePage {
|
||||||
property alias rootIndex: delegateModel.rootIndex
|
property alias rootIndex: delegateModel.rootIndex
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
title: "?"
|
title: entryModel.data(rootIndex)
|
||||||
actions {
|
actions {
|
||||||
main: Kirigami.Action {
|
main: Kirigami.Action {
|
||||||
iconName: "list-add"
|
iconName: "list-add"
|
||||||
|
|
44
qml/main.qml
44
qml/main.qml
|
@ -7,6 +7,8 @@ import org.kde.kirigami 2.4 as Kirigami
|
||||||
Kirigami.ApplicationWindow {
|
Kirigami.ApplicationWindow {
|
||||||
id: root
|
id: root
|
||||||
property alias showPasswordsOnFocus: showPasswordsOnFocusSwitch.checked
|
property alias showPasswordsOnFocus: showPasswordsOnFocusSwitch.checked
|
||||||
|
property var fieldsPage: undefined
|
||||||
|
property var lastEntriesPage: undefined
|
||||||
|
|
||||||
header: Kirigami.ApplicationHeader {
|
header: Kirigami.ApplicationHeader {
|
||||||
backButtonEnabled: false
|
backButtonEnabled: false
|
||||||
|
@ -220,6 +222,25 @@ Kirigami.ApplicationWindow {
|
||||||
onNewNotification: {
|
onNewNotification: {
|
||||||
showPassiveNotification(message)
|
showPassiveNotification(message)
|
||||||
}
|
}
|
||||||
|
onCurrentAccountChanged: {
|
||||||
|
// remove the fields page if the current account has been removed
|
||||||
|
if (!nativeInterface.hasCurrentAccount) {
|
||||||
|
pageStack.pop(lastEntriesPage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onEntryAboutToBeRemoved: {
|
||||||
|
// remove all possibly open stack pages of the removed entry and its children
|
||||||
|
for (var i = pageStack.depth - 1; i >= 0; --i) {
|
||||||
|
var stackPage = pageStack.get(i)
|
||||||
|
if (!stackPage) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if (stackPage.rootIndex === removedIndex) {
|
||||||
|
pageStack.pop(lastEntriesPage = pageStack.get(i - 1))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
|
@ -251,20 +272,27 @@ Kirigami.ApplicationWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearStack() {
|
function clearStack() {
|
||||||
pageStack.pop(root.pageStack.initialPage, Controls.StackView.Immediate)
|
pageStack.pop(lastEntriesPage = root.pageStack.initialPage,
|
||||||
|
Controls.StackView.Immediate)
|
||||||
}
|
}
|
||||||
|
|
||||||
function pushStackEntry(entryModel, rootIndex) {
|
function pushStackEntry(entryModel, rootIndex) {
|
||||||
pageStack.push(entriesComponent.createObject(root, {
|
pageStack.push(lastEntriesPage = entriesComponent.createObject(root, {
|
||||||
"entryModel": entryModel,
|
"entryModel": entryModel,
|
||||||
"rootIndex": rootIndex,
|
"rootIndex": rootIndex
|
||||||
"title": entryModel.data(
|
}))
|
||||||
rootIndex)
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function pushAccountEdit() {
|
function pushAccountEdit() {
|
||||||
pageStack.push(fieldsComponent.createObject(root))
|
// lazy-initialize fieldsPage
|
||||||
|
if (!fieldsPage) {
|
||||||
|
fieldsPage = fieldsComponent.createObject(root)
|
||||||
|
}
|
||||||
|
// remove fieldsPage if already shown to prevent warning
|
||||||
|
if (pageStack.get(pageStack.depth - 1) === fieldsPage) {
|
||||||
|
pageStack.pop(lastEntriesPage)
|
||||||
|
}
|
||||||
|
pageStack.push(fieldsPage)
|
||||||
}
|
}
|
||||||
|
|
||||||
function createFileActions(files) {
|
function createFileActions(files) {
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include <QStringBuilder>
|
#include <QStringBuilder>
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
@ -40,6 +41,7 @@ Controller::Controller(QSettings &settings, const QString &filePath, QObject *pa
|
||||||
, m_useNativeFileDialog(false)
|
, m_useNativeFileDialog(false)
|
||||||
{
|
{
|
||||||
m_entryFilterModel.setSourceModel(&m_entryModel);
|
m_entryFilterModel.setSourceModel(&m_entryModel);
|
||||||
|
connect(&m_entryModel, &QAbstractItemModel::rowsAboutToBeRemoved, this, &Controller::handleEntriesRemoved);
|
||||||
|
|
||||||
// share settings with main window
|
// share settings with main window
|
||||||
m_settings.beginGroup(QStringLiteral("mainwindow"));
|
m_settings.beginGroup(QStringLiteral("mainwindow"));
|
||||||
|
@ -258,6 +260,50 @@ void Controller::handleFileSelectionCanceled()
|
||||||
emit newNotification(tr("Canceled file selection"));
|
emit newNotification(tr("Canceled file selection"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Controller::handleEntriesRemoved(const QModelIndex &parentIndex, int first, int last)
|
||||||
|
{
|
||||||
|
// handle deletion of root (currently the view doesn't allow this)
|
||||||
|
const auto *const parentEntry = m_entryModel.entry(parentIndex);
|
||||||
|
if (!parentEntry) {
|
||||||
|
emit entryAboutToBeRemoved(m_entryModel.index(0, 0, QModelIndex()));
|
||||||
|
setCurrentAccount(nullptr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// assert arguments
|
||||||
|
assert(parentEntry->type() == EntryType::Node);
|
||||||
|
const auto &childEntries = static_cast<const NodeEntry *>(parentEntry)->children();
|
||||||
|
assert(first >= 0 && static_cast<size_t>(first) < childEntries.size());
|
||||||
|
assert(last >= 0 && static_cast<size_t>(last) < childEntries.size());
|
||||||
|
|
||||||
|
// iterate from first to last of the deleted entries
|
||||||
|
const auto *const currentAccount = this->currentAccount();
|
||||||
|
for (; first <= last; ++first) {
|
||||||
|
// inform view about deletion
|
||||||
|
emit entryAboutToBeRemoved(m_entryModel.index(first, 0, parentIndex));
|
||||||
|
|
||||||
|
// unset current account if it is under the deleted node
|
||||||
|
if (!currentAccount) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const auto *const childEntry = childEntries[static_cast<size_t>(first)];
|
||||||
|
switch (childEntry->type()) {
|
||||||
|
case EntryType::Account:
|
||||||
|
if (currentAccount == static_cast<const AccountEntry *>(childEntry)) {
|
||||||
|
setCurrentAccount(nullptr);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EntryType::Node:
|
||||||
|
// FIXME: remove const_cast in passwordfile v4
|
||||||
|
if (currentAccount->isIndirectChildOf(static_cast<NodeEntry *>(const_cast<Entry *>(childEntry)))) {
|
||||||
|
setCurrentAccount(nullptr);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QStringList Controller::pasteEntries(const QModelIndex &destinationParent, int row)
|
QStringList Controller::pasteEntries(const QModelIndex &destinationParent, int row)
|
||||||
{
|
{
|
||||||
if (m_cutEntries.isEmpty() || !m_entryModel.isNode(destinationParent)) {
|
if (m_cutEntries.isEmpty() || !m_entryModel.isNode(destinationParent)) {
|
||||||
|
|
|
@ -25,8 +25,10 @@ class Controller : public QObject {
|
||||||
Q_PROPERTY(EntryModel *entryModel READ entryModel NOTIFY entryModelChanged)
|
Q_PROPERTY(EntryModel *entryModel READ entryModel NOTIFY entryModelChanged)
|
||||||
Q_PROPERTY(EntryFilterModel *entryFilterModel READ entryFilterModel NOTIFY entryFilterModelChanged)
|
Q_PROPERTY(EntryFilterModel *entryFilterModel READ entryFilterModel NOTIFY entryFilterModelChanged)
|
||||||
Q_PROPERTY(FieldModel *fieldModel READ fieldModel NOTIFY fieldModelChanged)
|
Q_PROPERTY(FieldModel *fieldModel READ fieldModel NOTIFY fieldModelChanged)
|
||||||
|
Q_PROPERTY(Io::AccountEntry *currentAccount READ currentAccount WRITE setCurrentAccount NOTIFY currentAccountChanged)
|
||||||
Q_PROPERTY(QModelIndex currentAccountIndex READ currentAccountIndex WRITE setCurrentAccountIndex NOTIFY currentAccountChanged)
|
Q_PROPERTY(QModelIndex currentAccountIndex READ currentAccountIndex WRITE setCurrentAccountIndex NOTIFY currentAccountChanged)
|
||||||
Q_PROPERTY(QString currentAccountName READ currentAccountName NOTIFY currentAccountChanged)
|
Q_PROPERTY(QString currentAccountName READ currentAccountName NOTIFY currentAccountChanged)
|
||||||
|
Q_PROPERTY(bool hasCurrentAccount READ hasCurrentAccount NOTIFY currentAccountChanged)
|
||||||
Q_PROPERTY(QList<QPersistentModelIndex> cutEntries READ cutEntries WRITE setCutEntries NOTIFY cutEntriesChanged)
|
Q_PROPERTY(QList<QPersistentModelIndex> cutEntries READ cutEntries WRITE setCutEntries NOTIFY cutEntriesChanged)
|
||||||
Q_PROPERTY(bool canPaste READ canPaste NOTIFY cutEntriesChanged)
|
Q_PROPERTY(bool canPaste READ canPaste NOTIFY cutEntriesChanged)
|
||||||
Q_PROPERTY(QStringList recentFiles READ recentFiles NOTIFY recentFilesChanged)
|
Q_PROPERTY(QStringList recentFiles READ recentFiles NOTIFY recentFilesChanged)
|
||||||
|
@ -48,8 +50,11 @@ public:
|
||||||
EntryModel *entryModel();
|
EntryModel *entryModel();
|
||||||
EntryFilterModel *entryFilterModel();
|
EntryFilterModel *entryFilterModel();
|
||||||
FieldModel *fieldModel();
|
FieldModel *fieldModel();
|
||||||
|
Io::AccountEntry *currentAccount();
|
||||||
|
void setCurrentAccount(Io::AccountEntry *entry);
|
||||||
QModelIndex currentAccountIndex() const;
|
QModelIndex currentAccountIndex() const;
|
||||||
void setCurrentAccountIndex(const QModelIndex &accountIndex);
|
void setCurrentAccountIndex(const QModelIndex &accountIndex);
|
||||||
|
bool hasCurrentAccount() const;
|
||||||
const QList<QPersistentModelIndex> &cutEntries() const;
|
const QList<QPersistentModelIndex> &cutEntries() const;
|
||||||
void setCutEntries(const QList<QPersistentModelIndex> &cutEntries);
|
void setCutEntries(const QList<QPersistentModelIndex> &cutEntries);
|
||||||
QString currentAccountName() const;
|
QString currentAccountName() const;
|
||||||
|
@ -92,6 +97,10 @@ signals:
|
||||||
void newNotification(const QString &message);
|
void newNotification(const QString &message);
|
||||||
void useNativeFileDialogChanged(bool useNativeFileDialog);
|
void useNativeFileDialogChanged(bool useNativeFileDialog);
|
||||||
void supportsNativeFileDialogChanged();
|
void supportsNativeFileDialogChanged();
|
||||||
|
void entryAboutToBeRemoved(const QModelIndex &removedIndex);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void handleEntriesRemoved(const QModelIndex &parentIndex, int first, int last);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void resetFileStatus();
|
void resetFileStatus();
|
||||||
|
@ -166,6 +175,17 @@ inline FieldModel *Controller::fieldModel()
|
||||||
return &m_fieldModel;
|
return &m_fieldModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline Io::AccountEntry *Controller::currentAccount()
|
||||||
|
{
|
||||||
|
return m_fieldModel.accountEntry();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Controller::setCurrentAccount(Io::AccountEntry *entry)
|
||||||
|
{
|
||||||
|
m_fieldModel.setAccountEntry(entry);
|
||||||
|
emit currentAccountChanged();
|
||||||
|
}
|
||||||
|
|
||||||
inline QModelIndex Controller::currentAccountIndex() const
|
inline QModelIndex Controller::currentAccountIndex() const
|
||||||
{
|
{
|
||||||
return m_fieldModel.accountEntry() ? m_entryModel.index(const_cast<Io::AccountEntry *>(m_fieldModel.accountEntry())) : QModelIndex();
|
return m_fieldModel.accountEntry() ? m_entryModel.index(const_cast<Io::AccountEntry *>(m_fieldModel.accountEntry())) : QModelIndex();
|
||||||
|
@ -177,6 +197,11 @@ inline void Controller::setCurrentAccountIndex(const QModelIndex &accountIndex)
|
||||||
emit currentAccountChanged();
|
emit currentAccountChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool Controller::hasCurrentAccount() const
|
||||||
|
{
|
||||||
|
return m_fieldModel.accountEntry() != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
inline const QList<QPersistentModelIndex> &Controller::cutEntries() const
|
inline const QList<QPersistentModelIndex> &Controller::cutEntries() const
|
||||||
{
|
{
|
||||||
return m_cutEntries;
|
return m_cutEntries;
|
||||||
|
|
Loading…
Reference in New Issue