Update state syncer to account for new features

Update state syncer (class DatabaseWidgetStateSync) to account for new
features:
- properly sync view state when switching tabs
- properly read/write view state from/to config

Update classes EntryModel and EntryView to consistenly name list/search
modes. Before, both classes defined list mode as 'group mode' and search
mode as 'entry list mode', which differed from naming in other classes
such as DatabaseWidget.
This commit is contained in:
Fonic 2017-12-23 08:40:00 +01:00
parent 18be1a0254
commit e3a5a22b84
9 changed files with 408 additions and 111 deletions

View File

@ -138,6 +138,13 @@ void Config::init(const QString& fileName)
m_defaults.insert("GUI/DarkTrayIcon", false); m_defaults.insert("GUI/DarkTrayIcon", false);
m_defaults.insert("GUI/MinimizeToTray", false); m_defaults.insert("GUI/MinimizeToTray", false);
m_defaults.insert("GUI/MinimizeOnClose", false); m_defaults.insert("GUI/MinimizeOnClose", false);
/**
* @author Fonic <https://github.com/fonic>
* Set defaults for state of 'Hide Usernames'/'Hide Passwords' settings
* of entry view
*/
m_defaults.insert("GUI/EntryHideUsernames", false);
m_defaults.insert("GUI/EntryHidePasswords", true);
} }
Config* Config::instance() Config* Config::instance()

View File

@ -181,7 +181,13 @@ DatabaseWidget::DatabaseWidget(Database* db, QWidget* parent)
connect(m_mainSplitter, SIGNAL(splitterMoved(int,int)), SIGNAL(mainSplitterSizesChanged())); connect(m_mainSplitter, SIGNAL(splitterMoved(int,int)), SIGNAL(mainSplitterSizesChanged()));
connect(m_detailSplitter, SIGNAL(splitterMoved(int,int)), SIGNAL(detailSplitterSizesChanged())); connect(m_detailSplitter, SIGNAL(splitterMoved(int,int)), SIGNAL(detailSplitterSizesChanged()));
connect(m_entryView->header(), SIGNAL(sectionResized(int,int,int)), SIGNAL(entryColumnSizesChanged()));
/**
* @author Fonic <https://github.com/fonic>
* Connect signal to pass through state changes of entry view view
*/
connect(m_entryView, SIGNAL(viewStateChanged()), SIGNAL(entryViewStateChanged()));
connect(m_groupView, SIGNAL(groupChanged(Group*)), this, SLOT(onGroupChanged(Group*))); connect(m_groupView, SIGNAL(groupChanged(Group*)), this, SLOT(onGroupChanged(Group*)));
connect(m_groupView, SIGNAL(groupChanged(Group*)), SIGNAL(groupChanged())); connect(m_groupView, SIGNAL(groupChanged(Group*)), SIGNAL(groupChanged()));
connect(m_entryView, SIGNAL(entryActivated(Entry*, EntryModel::ModelColumn)), connect(m_entryView, SIGNAL(entryActivated(Entry*, EntryModel::ModelColumn)),
@ -290,28 +296,58 @@ void DatabaseWidget::setDetailSplitterSizes(const QList<int> &sizes)
m_detailSplitter->setSizes(sizes); m_detailSplitter->setSizes(sizes);
} }
QList<int> DatabaseWidget::entryHeaderViewSizes() const /**
* @author Fonic <https://github.com/fonic>
* Get current state of entry view 'Hide Usernames' setting
*/
bool DatabaseWidget::entryViewHideUsernames() const
{ {
QList<int> sizes; return m_entryView->hideUsernames();
for (int i = 0; i < m_entryView->header()->count(); i++) {
sizes.append(m_entryView->header()->sectionSize(i));
}
return sizes;
} }
void DatabaseWidget::setEntryViewHeaderSizes(const QList<int>& sizes) /**
* @author Fonic <https://github.com/fonic>
* Set state of entry view 'Hide Usernames' setting
*/
void DatabaseWidget::setEntryViewHideUsernames(const bool hide)
{ {
const bool enoughSizes = sizes.size() == m_entryView->header()->count(); m_entryView->setHideUsernames(hide);
Q_ASSERT(enoughSizes); }
if (!enoughSizes) {
return;
}
for (int i = 0; i < sizes.size(); i++) { /**
m_entryView->header()->resizeSection(i, sizes[i]); * @author Fonic <https://github.com/fonic>
} * Get current state of entry view 'Hide Passwords' setting
*/
bool DatabaseWidget::entryViewHidePasswords() const
{
return m_entryView->hidePasswords();
}
/**
* @author Fonic <https://github.com/fonic>
* Set state of entry view 'Hide Passwords' setting
*/
void DatabaseWidget::setEntryViewHidePasswords(const bool hide)
{
m_entryView->setHidePasswords(hide);
}
/**
* @author Fonic <https://github.com/fonic>
* Get current state of entry view view
*/
QByteArray DatabaseWidget::entryViewViewState() const
{
return m_entryView->viewState();
}
/**
* @author Fonic <https://github.com/fonic>
* Set state of entry view view
*/
bool DatabaseWidget::setEntryViewViewState(const QByteArray& state) const
{
return m_entryView->setViewState(state);
} }
void DatabaseWidget::clearAllWidgets() void DatabaseWidget::clearAllWidgets()
@ -1178,7 +1214,7 @@ bool DatabaseWidget::canDeleteCurrentGroup() const
bool DatabaseWidget::isInSearchMode() const bool DatabaseWidget::isInSearchMode() const
{ {
return m_entryView->inEntryListMode(); return m_entryView->inSearchMode();
} }
Group* DatabaseWidget::currentGroup() const Group* DatabaseWidget::currentGroup() const

View File

@ -92,8 +92,23 @@ public:
void setMainSplitterSizes(const QList<int>& sizes); void setMainSplitterSizes(const QList<int>& sizes);
QList<int> detailSplitterSizes() const; QList<int> detailSplitterSizes() const;
void setDetailSplitterSizes(const QList<int>& sizes); void setDetailSplitterSizes(const QList<int>& sizes);
QList<int> entryHeaderViewSizes() const;
void setEntryViewHeaderSizes(const QList<int>& sizes); /**
* @author Fonic <https://github.com/fonic>
* Methods to get/set state of entry view 'Hide Usernames'/'Hide
* Passwords' settings
*/
bool entryViewHideUsernames() const;
void setEntryViewHideUsernames(const bool hide);
bool entryViewHidePasswords() const;
void setEntryViewHidePasswords(const bool hide);
/**
* @author Fonic <https://github.com/fonic>
* Methods to get/set state of entry view view state
*/
QByteArray entryViewViewState() const;
bool setEntryViewViewState(const QByteArray& state) const;
void clearAllWidgets(); void clearAllWidgets();
bool currentEntryHasTitle(); bool currentEntryHasTitle();
bool currentEntryHasUsername(); bool currentEntryHasUsername();
@ -127,7 +142,13 @@ signals:
void searchModeActivated(); void searchModeActivated();
void mainSplitterSizesChanged(); void mainSplitterSizesChanged();
void detailSplitterSizesChanged(); void detailSplitterSizesChanged();
void entryColumnSizesChanged();
/**
* @author Fonic <https://github.com/fonic>
* Signal to notify about state changes entry view view
*/
void entryViewStateChanged();
void updateSearch(QString text); void updateSearch(QString text);
public slots: public slots:

View File

@ -27,16 +27,40 @@ DatabaseWidgetStateSync::DatabaseWidgetStateSync(QObject* parent)
{ {
m_mainSplitterSizes = variantToIntList(config()->get("GUI/SplitterState")); m_mainSplitterSizes = variantToIntList(config()->get("GUI/SplitterState"));
m_detailSplitterSizes = variantToIntList(config()->get("GUI/DetailSplitterState")); m_detailSplitterSizes = variantToIntList(config()->get("GUI/DetailSplitterState"));
m_columnSizesList = variantToIntList(config()->get("GUI/EntryListColumnSizes"));
m_columnSizesSearch = variantToIntList(config()->get("GUI/EntrySearchColumnSizes")); /**
* @author Fonic <https://github.com/fonic>
* Load state of entry view 'Hide Usernames'/'Hide Passwords' settings
*/
m_entryHideUsernames = config()->get("GUI/EntryHideUsernames").toBool();
m_entryHidePasswords = config()->get("GUI/EntryHidePasswords").toBool();
/**
* @author Fonic <https://github.com/fonic>
* Load states of entry view list/search view
*/
m_entryListViewState = config()->get("GUI/EntryListViewState").toByteArray();
m_entrySearchViewState = config()->get("GUI/EntrySearchViewState").toByteArray();
} }
DatabaseWidgetStateSync::~DatabaseWidgetStateSync() DatabaseWidgetStateSync::~DatabaseWidgetStateSync()
{ {
config()->set("GUI/SplitterState", intListToVariant(m_mainSplitterSizes)); config()->set("GUI/SplitterState", intListToVariant(m_mainSplitterSizes));
config()->set("GUI/DetailSplitterState", intListToVariant(m_detailSplitterSizes)); config()->set("GUI/DetailSplitterState", intListToVariant(m_detailSplitterSizes));
config()->set("GUI/EntryListColumnSizes", intListToVariant(m_columnSizesList));
config()->set("GUI/EntrySearchColumnSizes", intListToVariant(m_columnSizesSearch)); /**
* @author Fonic <https://github.com/fonic>
* Save state of entry view 'Hide Usernames'/'Hide Passwords' settings
*/
config()->set("GUI/EntryHideUsernames", m_entryHideUsernames);
config()->set("GUI/EntryHidePasswords", m_entryHidePasswords);
/**
* @author Fonic <https://github.com/fonic>
* Save states of entry view list/search view
*/
config()->set("GUI/EntryListViewState", m_entryListViewState);
config()->set("GUI/EntrySearchViewState", m_entrySearchViewState);
} }
void DatabaseWidgetStateSync::setActive(DatabaseWidget* dbWidget) void DatabaseWidgetStateSync::setActive(DatabaseWidget* dbWidget)
@ -70,8 +94,14 @@ void DatabaseWidgetStateSync::setActive(DatabaseWidget* dbWidget)
SLOT(updateSplitterSizes())); SLOT(updateSplitterSizes()));
connect(m_activeDbWidget, SIGNAL(detailSplitterSizesChanged()), connect(m_activeDbWidget, SIGNAL(detailSplitterSizesChanged()),
SLOT(updateSplitterSizes())); SLOT(updateSplitterSizes()));
connect(m_activeDbWidget, SIGNAL(entryColumnSizesChanged()),
SLOT(updateColumnSizes())); /**
* @author Fonic <https://github.com/fonic>
* Connect signal to receive state changes of entry view view
*/
connect(m_activeDbWidget, SIGNAL(entryViewStateChanged()),
SLOT(updateViewState()));
connect(m_activeDbWidget, SIGNAL(listModeActivated()), connect(m_activeDbWidget, SIGNAL(listModeActivated()),
SLOT(restoreListView())); SLOT(restoreListView()));
connect(m_activeDbWidget, SIGNAL(searchModeActivated()), connect(m_activeDbWidget, SIGNAL(searchModeActivated()),
@ -83,19 +113,59 @@ void DatabaseWidgetStateSync::setActive(DatabaseWidget* dbWidget)
} }
} }
/**
* @author Fonic <https://github.com/fonic>
* Restore entry view list view state
*
* NOTE:
* States of entry view 'Hide Usernames'/'Hide Passwords' settings are considered
* 'global', i.e. they are the same for both list and search mode
*
* NOTE:
* If m_entryListViewState is empty, it is the first time after clean/invalid
* config that list view is activated. Thus, save its current state. Without
* this, m_entryListViewState would remain empty until there is an actual view
* state change (e.g. column is resized)
*/
void DatabaseWidgetStateSync::restoreListView() void DatabaseWidgetStateSync::restoreListView()
{ {
if (!m_columnSizesList.isEmpty()) { m_activeDbWidget->setEntryViewHideUsernames(m_entryHideUsernames);
m_activeDbWidget->setEntryViewHeaderSizes(m_columnSizesList); m_activeDbWidget->setEntryViewHidePasswords(m_entryHidePasswords);
if (!m_entryListViewState.isEmpty()) {
m_activeDbWidget->setEntryViewViewState(m_entryListViewState);
}
else {
m_entryListViewState = m_activeDbWidget->entryViewViewState();
} }
m_blockUpdates = false; m_blockUpdates = false;
} }
/**
* @author Fonic <https://github.com/fonic>
* Restore entry view search view state
*
* NOTE:
* States of entry view 'Hide Usernames'/'Hide Passwords' settings are considered
* 'global', i.e. they are the same for both list and search mode
*
* NOTE:
* If m_entrySearchViewState is empty, it is the first time after clean/invalid
* config that search view is activated. Thus, save its current state. Without
* this, m_entrySearchViewState would remain empty until there is an actual view
* state change (e.g. column is resized)
*/
void DatabaseWidgetStateSync::restoreSearchView() void DatabaseWidgetStateSync::restoreSearchView()
{ {
if (!m_columnSizesSearch.isEmpty()) { m_activeDbWidget->setEntryViewHideUsernames(m_entryHideUsernames);
m_activeDbWidget->setEntryViewHeaderSizes(m_columnSizesSearch); m_activeDbWidget->setEntryViewHidePasswords(m_entryHidePasswords);
if (!m_entrySearchViewState.isEmpty()) {
m_activeDbWidget->setEntryViewViewState(m_entrySearchViewState);
}
else {
m_entrySearchViewState = m_activeDbWidget->entryViewViewState();
} }
m_blockUpdates = false; m_blockUpdates = false;
@ -116,17 +186,26 @@ void DatabaseWidgetStateSync::updateSplitterSizes()
m_detailSplitterSizes = m_activeDbWidget->detailSplitterSizes(); m_detailSplitterSizes = m_activeDbWidget->detailSplitterSizes();
} }
void DatabaseWidgetStateSync::updateColumnSizes() /**
* @author Fonic <https://github.com/fonic>
* Update entry view list/search view state (NOTE: states of entry view
* 'Hide Usernames'/'Hide Passwords' settings are considered 'global',
* i.e. they are the same for both list and search mode)
*/
void DatabaseWidgetStateSync::updateViewState()
{ {
if (m_blockUpdates) { if (m_blockUpdates) {
return; return;
} }
if (m_activeDbWidget->isGroupSelected()) { m_entryHideUsernames = m_activeDbWidget->entryViewHideUsernames();
m_columnSizesList = m_activeDbWidget->entryHeaderViewSizes(); m_entryHidePasswords = m_activeDbWidget->entryViewHidePasswords();
if (m_activeDbWidget->isInSearchMode()) {
m_entrySearchViewState = m_activeDbWidget->entryViewViewState();
} }
else { else {
m_columnSizesSearch = m_activeDbWidget->entryHeaderViewSizes(); m_entryListViewState = m_activeDbWidget->entryViewViewState();
} }
} }

View File

@ -37,7 +37,12 @@ public slots:
private slots: private slots:
void blockUpdates(); void blockUpdates();
void updateSplitterSizes(); void updateSplitterSizes();
void updateColumnSizes();
/**
* @author Fonic <https://github.com/fonic>
* Slot to update entry view view state
*/
void updateViewState();
private: private:
static QList<int> variantToIntList(const QVariant& variant); static QList<int> variantToIntList(const QVariant& variant);
@ -48,8 +53,22 @@ private:
bool m_blockUpdates; bool m_blockUpdates;
QList<int> m_mainSplitterSizes; QList<int> m_mainSplitterSizes;
QList<int> m_detailSplitterSizes; QList<int> m_detailSplitterSizes;
QList<int> m_columnSizesList;
QList<int> m_columnSizesSearch; /**
* @author Fonic <https://github.com/fonic>
* Properties to store state of entry view 'Hide Usernames'/'Hide
* Passwords' settings
*/
bool m_entryHideUsernames;
bool m_entryHidePasswords;
/**
* @author Fonic <https://github.com/fonic>
* Properties to store states of entry view list/search view (replaces
* m_columnSizesList/m_columnSizesSearch)
*/
QByteArray m_entryListViewState;
QByteArray m_entrySearchViewState;
}; };
#endif // KEEPASSX_DATABASEWIDGETSTATESYNC_H #endif // KEEPASSX_DATABASEWIDGETSTATESYNC_H

View File

@ -97,7 +97,7 @@ void EntryModel::setGroup(Group* group)
makeConnections(group); makeConnections(group);
endResetModel(); endResetModel();
emit switchedToGroupMode(); emit switchedToListMode();
} }
void EntryModel::setEntryList(const QList<Entry*>& entries) void EntryModel::setEntryList(const QList<Entry*>& entries)
@ -134,7 +134,7 @@ void EntryModel::setEntryList(const QList<Entry*>& entries)
} }
endResetModel(); endResetModel();
emit switchedToEntryListMode(); emit switchedToSearchMode();
} }
int EntryModel::rowCount(const QModelIndex& parent) const int EntryModel::rowCount(const QModelIndex& parent) const

View File

@ -75,8 +75,13 @@ public:
void setHidePasswords(const bool hide); void setHidePasswords(const bool hide);
signals: signals:
void switchedToEntryListMode(); /**
void switchedToGroupMode(); * @author Fonic <https://github.com/fonic>
* Signals to notify about list/search mode switches (NOTE: previously
* named 'switchedToGroupMode'/'switchedToEntryListMode')
*/
void switchedToListMode();
void switchedToSearchMode();
/** /**
* @author Fonic <https://github.com/fonic> * @author Fonic <https://github.com/fonic>

View File

@ -43,7 +43,7 @@ EntryView::EntryView(QWidget* parent)
: QTreeView(parent) : QTreeView(parent)
, m_model(new EntryModel(this)) , m_model(new EntryModel(this))
, m_sortModel(new SortFilterHideProxyModel(this)) , m_sortModel(new SortFilterHideProxyModel(this))
, m_inEntryListMode(false) , m_inSearchMode(false)
{ {
m_sortModel->setSourceModel(m_model); m_sortModel->setSourceModel(m_model);
m_sortModel->setDynamicSortFilter(true); m_sortModel->setDynamicSortFilter(true);
@ -70,8 +70,20 @@ EntryView::EntryView(QWidget* parent)
connect(this, SIGNAL(doubleClicked(QModelIndex)), SLOT(emitEntryActivated(QModelIndex))); connect(this, SIGNAL(doubleClicked(QModelIndex)), SLOT(emitEntryActivated(QModelIndex)));
connect(selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SIGNAL(entrySelectionChanged())); connect(selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SIGNAL(entrySelectionChanged()));
connect(m_model, SIGNAL(switchedToEntryListMode()), SLOT(switchToEntryListMode())); /**
connect(m_model, SIGNAL(switchedToGroupMode()), SLOT(switchToGroupMode())); * @author Fonic <https://github.com/fonic>
* Connect signals to get notified about list/search mode switches (NOTE:
* previously named 'switch[ed]ToGroupMode'/'switch[ed]ToEntryListMode')
*/
connect(m_model, SIGNAL(switchedToListMode()), SLOT(switchToListMode()));
connect(m_model, SIGNAL(switchedToSearchMode()), SLOT(switchToSearchMode()));
/**
* @author Fonic <https://github.com/fonic>
* Connect signals to notify about changes of view state when state of
* 'Hide Usernames'/'Hide Passwords' settings changes in model
*/
connect(m_model, SIGNAL(hideUsernamesChanged()), SIGNAL(viewStateChanged()));
connect(m_model, SIGNAL(hidePasswordsChanged()), SIGNAL(viewStateChanged()));
connect(this, SIGNAL(clicked(QModelIndex)), SLOT(emitEntryPressed(QModelIndex))); connect(this, SIGNAL(clicked(QModelIndex)), SLOT(emitEntryPressed(QModelIndex)));
@ -118,25 +130,51 @@ EntryView::EntryView(QWidget* parent)
* - Disable stretching of last section (interferes with fitting columns * - Disable stretching of last section (interferes with fitting columns
* to window) * to window)
* - Associate with context menu * - Associate with context menu
* - Connect signals to notify about changes of view state when state
* of header changes
*/ */
header()->setDefaultSectionSize(100); header()->setDefaultSectionSize(100);
header()->setStretchLastSection(false); header()->setStretchLastSection(false);
header()->setContextMenuPolicy(Qt::CustomContextMenu); header()->setContextMenuPolicy(Qt::CustomContextMenu);
connect(header(), SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showHeaderMenu(QPoint))); connect(header(), SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showHeaderMenu(QPoint)));
connect(header(), SIGNAL(sectionCountChanged(int, int)), this, SIGNAL(viewStateChanged()));
connect(header(), SIGNAL(sectionMoved(int, int, int)), this, SIGNAL(viewStateChanged()));
connect(header(), SIGNAL(sectionResized(int, int, int)), this, SIGNAL(viewStateChanged()));
connect(header(), SIGNAL(sortIndicatorChanged(int, Qt::SortOrder)), this, SIGNAL(viewStateChanged()));
/** /**
* @author Fonic <https://github.com/fonic> * @author Fonic <https://github.com/fonic>
* Finalize setup by resetting view to defaults. Although not really * Fit columns to window
* necessary at this point, it makes sense in order to avoid duplicating
* code (sorting order, visibility of first column etc.)
* *
* TODO: * TODO:
* Not working as expected, columns will end up being very small, most * Not working as expected, columns will end up being very small, most
* likely due to EntryView not being sized properly at this time. Either * likely due to EntryView not being sized properly at this time. Find
* find a way to make this work by analizing when/where EntryView is * a way to make this work by analizing when/where EntryView is created
* created or remove
*/ */
//resetViewToDefaults(); //fitColumnsToWindow();
/**
* @author Fonic <https://github.com/fonic>
* Configure default search view state and save for later use
*/
header()->showSection(EntryModel::ParentGroup);
m_sortModel->sort(EntryModel::ParentGroup, Qt::AscendingOrder);
sortByColumn(EntryModel::ParentGroup, Qt::AscendingOrder);
m_defaultSearchViewState = header()->saveState();
/**
* @author Fonic <https://github.com/fonic>
* Configure default list view state and save for later use
*
* NOTE:
* Default list view is intentionally configured last since this is the
* view that's supposed to be active after initialization as m_inSearchMode
* is initialized with 'false'
*/
header()->hideSection(EntryModel::ParentGroup);
m_sortModel->sort(EntryModel::Title, Qt::AscendingOrder);
sortByColumn(EntryModel::Title, Qt::AscendingOrder);
m_defaultListViewState = header()->saveState();
} }
void EntryView::keyPressEvent(QKeyEvent* event) void EntryView::keyPressEvent(QKeyEvent* event)
@ -175,9 +213,9 @@ void EntryView::setFirstEntryActive()
} }
} }
bool EntryView::inEntryListMode() bool EntryView::inSearchMode()
{ {
return m_inEntryListMode; return m_inSearchMode;
} }
void EntryView::emitEntryActivated(const QModelIndex& index) void EntryView::emitEntryActivated(const QModelIndex& index)
@ -230,53 +268,112 @@ Entry* EntryView::entryFromIndex(const QModelIndex& index)
} }
} }
void EntryView::switchToEntryListMode() /**
* @author Fonic <https://github.com/fonic>
* Switch to list mode, i.e. list entries of group (NOTE: previously named
* 'switchToGroupMode')
*/
void EntryView::switchToListMode()
{ {
/** /* Check if already in this mode */
* @author Fonic <https://github.com/fonic> if (!m_inSearchMode) {
* Use header()->showSection() instead of m_sortModel->hideColumn() as return;
* the latter messes up column indices, interfering with code relying on
* proper indices
*/
header()->showSection(EntryModel::ParentGroup);
if (header()->sectionSize(EntryModel::ParentGroup) == 0) {
header()->resizeSection(EntryModel::ParentGroup, header()->defaultSectionSize());
} }
/** /**
* @author Fonic <https://github.com/fonic>
* Set sorting column and order (TODO: check what first two lines do, if
* they are actually necessary, if indices are still correct and if indices
* may be replaced by EntryModel::<column>)
*/
m_sortModel->sort(1, Qt::AscendingOrder);
m_sortModel->sort(0, Qt::AscendingOrder);
sortByColumn(EntryModel::ParentGroup, Qt::AscendingOrder);
m_inEntryListMode = true;
}
void EntryView::switchToGroupMode()
{
/**
* @author Fonic <https://github.com/fonic>
* Use header()->hideSection() instead of m_sortModel->hideColumn() as * Use header()->hideSection() instead of m_sortModel->hideColumn() as
* the latter messes up column indices, interfering with code relying on * the latter messes up column indices, interfering with code relying on
* proper indices * proper indices
*/ */
header()->hideSection(EntryModel::ParentGroup); header()->hideSection(EntryModel::ParentGroup);
/** m_inSearchMode = false;
* @author Fonic <https://github.com/fonic> }
* Set sorting column and order (TODO: check what first two lines do, if
* they are actually necessary, if indices are still correct and if indices
* may be replaced by EntryModel::<column>)
*/
m_sortModel->sort(-1, Qt::AscendingOrder);
m_sortModel->sort(0, Qt::AscendingOrder);
sortByColumn(EntryModel::Title, Qt::AscendingOrder);
m_inEntryListMode = false; /**
* @author Fonic <https://github.com/fonic>
* Switch to search mode, i.e. list search results (NOTE: previously named
* 'switchToEntryListMode')
*/
void EntryView::switchToSearchMode()
{
/* Check if already in this mode */
if (m_inSearchMode) {
return;
}
/*
* Use header()->showSection() instead of m_sortModel->hideColumn() as
* the latter messes up column indices, interfering with code relying on
* proper indices
*/
header()->showSection(EntryModel::ParentGroup);
/*
* Always set sorting to column 'Group', as it does not feel right to have
* the last known sort configuration of search view restored by 'Database
* WidgetStateSync', which is what happens without this
*/
m_sortModel->sort(EntryModel::ParentGroup, Qt::AscendingOrder);
sortByColumn(EntryModel::ParentGroup, Qt::AscendingOrder);
m_inSearchMode = true;
}
/**
* @author Fonic <https://github.com/fonic>
* Get current state of 'Hide Usernames' setting (NOTE: just pass-through for
* m_model)
*/
bool EntryView::hideUsernames() const
{
return m_model->hideUsernames();
}
/**
* @author Fonic <https://github.com/fonic>
* Set state of 'Hide Usernames' setting (NOTE: just pass-through for m_model)
*/
void EntryView::setHideUsernames(const bool hide)
{
m_model->setHideUsernames(hide);
}
/**
* @author Fonic <https://github.com/fonic>
* Get current state of 'Hide Passwords' setting (NOTE: just pass-through for
* m_model)
*/
bool EntryView::hidePasswords() const
{
return m_model->hidePasswords();
}
/**
* @author Fonic <https://github.com/fonic>
* Set state of 'Hide Passwords' setting (NOTE: just pass-through for m_model)
*/
void EntryView::setHidePasswords(const bool hide)
{
m_model->setHidePasswords(hide);
}
/**
* @author Fonic <https://github.com/fonic>
* Get current state of view
*/
QByteArray EntryView::viewState() const
{
return header()->saveState();
}
/**
* @author Fonic <https://github.com/fonic>
* Set state of entry view view
*/
bool EntryView::setViewState(const QByteArray& state) const
{
return header()->restoreState(state);
} }
/** /**
@ -351,10 +448,16 @@ void EntryView::toggleColumnVisibility(QAction *action)
* its implementation MUST call the corresponding parent method using * its implementation MUST call the corresponding parent method using
* 'QTreeView::resizeEvent(event)'. Without this, fitting to window will * 'QTreeView::resizeEvent(event)'. Without this, fitting to window will
* be broken and/or work unreliably (stumbled upon during testing) * be broken and/or work unreliably (stumbled upon during testing)
*
* NOTE:
* Testing showed that it is absolutely necessary to emit signal 'viewState
* Changed' here. Without this, an incomplete view state might get saved by
* 'DatabaseWidgetStateSync' (e.g. only some columns resized)
*/ */
void EntryView::fitColumnsToWindow() void EntryView::fitColumnsToWindow()
{ {
header()->resizeSections(QHeaderView::Stretch); header()->resizeSections(QHeaderView::Stretch);
emit viewStateChanged();
} }
/** /**
@ -395,16 +498,17 @@ void EntryView::fitColumnsToContents()
} }
header()->resizeSection(header()->logicalIndex(last), header()->sectionSize(last) + (header()->width() - width)); header()->resizeSection(header()->logicalIndex(last), header()->sectionSize(last) + (header()->width() - width));
} }
/*
* This should not be necessary due to use of header()->resizeSection,
* but lets do it anyway for the sake of completeness
*/
emit viewStateChanged();
} }
/** /**
* @author Fonic <https://github.com/fonic> * @author Fonic <https://github.com/fonic>
* Reset view to defaults * Reset view to defaults
*
* NOTE:
* header()->saveState()/restoreState() could also be used for this, but
* testing showed that it complicates things more than it helps when trying
* to account for current list mode
*/ */
void EntryView::resetViewToDefaults() void EntryView::resetViewToDefaults()
{ {
@ -412,19 +516,12 @@ void EntryView::resetViewToDefaults()
m_model->setHideUsernames(false); m_model->setHideUsernames(false);
m_model->setHidePasswords(true); m_model->setHidePasswords(true);
/* Reset visibility, size and position of all columns */ /* Reset columns (size, order, sorting etc.) */
for (int colidx = 0; colidx < header()->count(); colidx++) { if (m_inSearchMode) {
header()->showSection(colidx); header()->restoreState(m_defaultSearchViewState);
header()->resizeSection(colidx, header()->defaultSectionSize());
header()->moveSection(header()->visualIndex(colidx), colidx);
}
/* Reenter current list mode (affects first column and sorting) */
if (m_inEntryListMode) {
switchToEntryListMode();
} }
else { else {
switchToGroupMode(); header()->restoreState(m_defaultListViewState);
} }
/* Nicely fitting columns to window feels like a sane default */ /* Nicely fitting columns to window feels like a sane default */

View File

@ -43,10 +43,27 @@ public:
void setCurrentEntry(Entry* entry); void setCurrentEntry(Entry* entry);
Entry* entryFromIndex(const QModelIndex& index); Entry* entryFromIndex(const QModelIndex& index);
void setEntryList(const QList<Entry*>& entries); void setEntryList(const QList<Entry*>& entries);
bool inEntryListMode(); bool inSearchMode();
int numberOfSelectedEntries(); int numberOfSelectedEntries();
void setFirstEntryActive(); void setFirstEntryActive();
/**
* @author Fonic <https://github.com/fonic>
* Methods to get/set state of 'Hide Usernames'/'Hide Passwords' settings
* (NOTE: these are just pass-through methods to avoid exposing entry model)
*/
bool hideUsernames() const;
void setHideUsernames(const bool hide);
bool hidePasswords() const;
void setHidePasswords(const bool hide);
/**
* @author Fonic <https://github.com/fonic>
* Methods to get/set state of view
*/
QByteArray viewState() const;
bool setViewState(const QByteArray& state) const;
public slots: public slots:
void setGroup(Group* group); void setGroup(Group* group);
@ -54,6 +71,11 @@ signals:
void entryActivated(Entry* entry, EntryModel::ModelColumn column); void entryActivated(Entry* entry, EntryModel::ModelColumn column);
void entryPressed(Entry* entry); void entryPressed(Entry* entry);
void entrySelectionChanged(); void entrySelectionChanged();
/**
* @author Fonic <https://github.com/fonic>
* Signal to notify about changes of view state
*/
void viewStateChanged();
protected: protected:
void keyPressEvent(QKeyEvent* event) override; void keyPressEvent(QKeyEvent* event) override;
@ -61,8 +83,13 @@ protected:
private slots: private slots:
void emitEntryActivated(const QModelIndex& index); void emitEntryActivated(const QModelIndex& index);
void emitEntryPressed(const QModelIndex& index); void emitEntryPressed(const QModelIndex& index);
void switchToEntryListMode(); /**
void switchToGroupMode(); * @author Fonic <https://github.com/fonic>
* Methods to switch to list/search mode (NOTE: previously named 'switch
* ToGroupMode'/'switchToEntryListMode')
*/
void switchToListMode();
void switchToSearchMode();
/** /**
* @author Fonic <https://github.com/fonic> * @author Fonic <https://github.com/fonic>
@ -77,8 +104,14 @@ private slots:
private: private:
EntryModel* const m_model; EntryModel* const m_model;
SortFilterHideProxyModel* const m_sortModel; SortFilterHideProxyModel* const m_sortModel;
bool m_inEntryListMode; bool m_inSearchMode;
/**
* @author Fonic <https://github.com/fonic>
* Properties to store default view states used by resetViewToDefaults()
*/
QByteArray m_defaultListViewState;
QByteArray m_defaultSearchViewState;
/** /**
* @author Fonic <https://github.com/fonic> * @author Fonic <https://github.com/fonic>
* Properties to store header context menu and actions * Properties to store header context menu and actions