Add custom light and dark UI themes

This commit is contained in:
Janek Bevendorff 2020-01-06 03:00:25 +01:00
parent 6d2ca74878
commit 557736ea5e
39 changed files with 6452 additions and 401 deletions

View file

@ -24,7 +24,6 @@
#include <QMenu>
#include <QShortcut>
#include "core/FilePath.h"
#include "gui/SortFilterHideProxyModel.h"
EntryView::EntryView(QWidget* parent)
@ -70,22 +69,31 @@ EntryView::EntryView(QWidget* parent)
m_hidePasswordsAction->setCheckable(true);
m_headerMenu->addSeparator();
resetViewToDefaults();
// Actions to toggle column visibility, each carrying the corresponding
// colummn index as data
m_columnActions = new QActionGroup(this);
m_columnActions->setExclusive(false);
for (int columnIndex = 1; columnIndex < header()->count(); ++columnIndex) {
QString caption = m_model->headerData(columnIndex, Qt::Horizontal, Qt::DisplayRole).toString();
if (columnIndex == EntryModel::Paperclip) {
caption = tr("Attachments (icon)");
for (int visualIndex = 1; visualIndex < header()->count(); ++visualIndex) {
int logicalIndex = header()->logicalIndex(visualIndex);
QString caption = m_model->headerData(logicalIndex, Qt::Horizontal, Qt::DisplayRole).toString();
if (logicalIndex == EntryModel::Paperclip) {
caption = tr("Has attachments", "Entry attachment icon toggle");
} else if (logicalIndex == EntryModel::Totp) {
caption = tr("Has TOTP", "Entry TOTP icon toggle");
}
QAction* action = m_headerMenu->addAction(caption);
action->setCheckable(true);
action->setData(columnIndex);
action->setData(logicalIndex);
m_columnActions->addAction(action);
}
connect(m_columnActions, SIGNAL(triggered(QAction*)), this, SLOT(toggleColumnVisibility(QAction*)));
connect(header(), &QHeaderView::sortIndicatorChanged, [this](int index, Qt::SortOrder order) {
Q_UNUSED(order)
header()->setSortIndicatorShown(index != EntryModel::Paperclip && index != EntryModel::Totp);
});
m_headerMenu->addSeparator();
m_headerMenu->addAction(tr("Fit to window"), this, SLOT(fitColumnsToWindow()));
@ -114,22 +122,6 @@ EntryView::EntryView(QWidget* parent)
// clang-format off
connect(header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), SIGNAL(viewStateChanged()));
// clang-format on
resetFixedColumns();
// 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();
// Configure default list view state and save for later use
header()->hideSection(EntryModel::ParentGroup);
m_sortModel->sort(EntryModel::Title, Qt::AscendingOrder);
sortByColumn(EntryModel::Title, Qt::AscendingOrder);
m_defaultListViewState = header()->saveState();
m_model->setPaperClipPixmap(filePath()->icon("actions", "paperclip").pixmap(16));
}
void EntryView::contextMenuShortcutPressed()
@ -325,6 +317,7 @@ bool EntryView::setViewState(const QByteArray& state)
{
bool status = header()->restoreState(state);
resetFixedColumns();
m_columnsNeedRelayout = state.isEmpty();
return status;
}
@ -397,9 +390,11 @@ void EntryView::toggleColumnVisibility(QAction* action)
*/
void EntryView::fitColumnsToWindow()
{
header()->resizeSections(QHeaderView::Stretch);
header()->setSectionResizeMode(QHeaderView::Stretch);
resetFixedColumns();
QCoreApplication::processEvents();
header()->setSectionResizeMode(QHeaderView::Interactive);
resetFixedColumns();
fillRemainingWidth(true);
emit viewStateChanged();
}
@ -409,69 +404,88 @@ void EntryView::fitColumnsToWindow()
*/
void EntryView::fitColumnsToContents()
{
// Resize columns to fit contents
header()->resizeSections(QHeaderView::ResizeToContents);
header()->setSectionResizeMode(QHeaderView::ResizeToContents);
resetFixedColumns();
QCoreApplication::processEvents();
header()->setSectionResizeMode(QHeaderView::Interactive);
resetFixedColumns();
fillRemainingWidth(false);
emit viewStateChanged();
}
/**
* Reset view to defaults
* Mark icon-only columns as fixed and resize them to their minimum section size.
*/
void EntryView::resetFixedColumns()
{
header()->setSectionResizeMode(EntryModel::Paperclip, QHeaderView::Fixed);
header()->resizeSection(EntryModel::Paperclip, header()->minimumSectionSize());
header()->setSectionResizeMode(EntryModel::Totp, QHeaderView::Fixed);
header()->resizeSection(EntryModel::Totp, header()->minimumSectionSize());
}
/**
* Reset item view to defaults.
*/
void EntryView::resetViewToDefaults()
{
m_model->setUsernamesHidden(false);
m_model->setPasswordsHidden(true);
// Reduce number of columns that are shown by default
if (m_inSearchMode) {
header()->restoreState(m_defaultSearchViewState);
header()->showSection(EntryModel::ParentGroup);
} else {
header()->restoreState(m_defaultListViewState);
header()->hideSection(EntryModel::ParentGroup);
}
header()->showSection(EntryModel::Title);
header()->showSection(EntryModel::Username);
header()->showSection(EntryModel::Url);
header()->showSection(EntryModel::Notes);
header()->showSection(EntryModel::Modified);
header()->showSection(EntryModel::Paperclip);
header()->showSection(EntryModel::Totp);
header()->hideSection(EntryModel::Password);
header()->hideSection(EntryModel::Expires);
header()->hideSection(EntryModel::Created);
header()->hideSection(EntryModel::Accessed);
header()->hideSection(EntryModel::Attachments);
// Reset column order to logical indices
for (int i = 0; i < header()->count(); ++i) {
header()->moveSection(header()->visualIndex(i), i);
}
fitColumnsToWindow();
// Reorder some columns
header()->moveSection(header()->visualIndex(EntryModel::Paperclip), 1);
header()->moveSection(header()->visualIndex(EntryModel::Totp), 2);
// Sort by title or group (depending on the mode)
m_sortModel->sort(EntryModel::Title, Qt::AscendingOrder);
sortByColumn(EntryModel::Title, Qt::AscendingOrder);
if (m_inSearchMode) {
m_sortModel->sort(EntryModel::ParentGroup, Qt::AscendingOrder);
sortByColumn(EntryModel::ParentGroup, Qt::AscendingOrder);
}
// The following call only relayouts reliably if the widget has been shown
// already, so only do it if the widget is visible and let showEvent() handle
// the initial default layout.
if (isVisible()) {
fitColumnsToWindow();
}
}
void EntryView::fillRemainingWidth(bool lastColumnOnly)
void EntryView::showEvent(QShowEvent* event)
{
// Determine total width of currently visible columns
int width = 0;
int lastColumnIndex = 0;
for (int columnIndex = 0; columnIndex < header()->count(); ++columnIndex) {
if (!header()->isSectionHidden(columnIndex)) {
width += header()->sectionSize(columnIndex);
}
if (header()->visualIndex(columnIndex) > lastColumnIndex) {
lastColumnIndex = header()->visualIndex(columnIndex);
}
}
QTreeView::showEvent(event);
int numColumns = header()->count() - header()->hiddenSectionCount();
int availWidth = header()->width() - width;
if ((numColumns <= 0) || (availWidth <= 0)) {
return;
// Check if header columns need to be resized to sensible defaults.
// This is only needed if no previous view state has been loaded.
if (m_columnsNeedRelayout) {
fitColumnsToWindow();
m_columnsNeedRelayout = false;
}
if (!lastColumnOnly) {
// Equally distribute remaining width to visible columns
int add = availWidth / numColumns;
width = 0;
for (int columnIndex = 0; columnIndex < header()->count(); ++columnIndex) {
if (!header()->isSectionHidden(columnIndex)) {
header()->resizeSection(columnIndex, header()->sectionSize(columnIndex) + add);
width += header()->sectionSize(columnIndex);
}
}
}
// Add remaining width to last column
header()->resizeSection(header()->logicalIndex(lastColumnIndex),
header()->sectionSize(lastColumnIndex) + (header()->width() - width));
}
void EntryView::resetFixedColumns()
{
header()->setSectionResizeMode(EntryModel::Paperclip, QHeaderView::Fixed);
header()->resizeSection(EntryModel::Paperclip, header()->minimumSectionSize());
}