BibleTime
btbookshelfwidget.cpp
Go to the documentation of this file.
1/*********
2*
3* In the name of the Father, and of the Son, and of the Holy Spirit.
4*
5* This file is part of BibleTime's source code, https://bibletime.info/
6*
7* Copyright 1999-2025 by the BibleTime developers.
8* The BibleTime source code is licensed under the GNU General Public License
9* version 2.0.
10*
11**********/
12
13#include "btbookshelfwidget.h"
14
15#include <QAction>
16#include <QApplication>
17#include <QHBoxLayout>
18#include <QEvent>
19#include <QKeyEvent>
20#include <QLabel>
21#include <QLineEdit>
22#include <QMenu>
23#include <QModelIndex>
24#include <QToolButton>
25#include <QVariant>
26#include <QVBoxLayout>
27#include <utility>
28#include "../backend/bookshelfmodel/btbookshelffiltermodel.h"
29#include "../backend/bookshelfmodel/btbookshelftreemodel.h"
30#include "../backend/config/btconfig.h"
31#include "../util/btassert.h"
32#include "../util/btconnect.h"
33#include "../util/cresmgr.h"
35#include "btbookshelfview.h"
36
37
39class QPoint;
40
41BtBookshelfWidget::BtBookshelfWidget(QWidget *parent, Qt::WindowFlags flags)
42 : QWidget(parent, flags)
43 , m_treeModel(nullptr)
44 , m_leftCornerWidget(nullptr)
45 , m_rightCornerWidget(nullptr)
46{
47 // Setup post-filter:
49
50 // Init widgets and such:
52 initMenus();
54
55 // Connect treeview to model:
57
59
60 BT_CONNECT(m_nameFilterEdit, &QLineEdit::textEdited,
64 [this](QPoint const & pos){ m_contextMenu->popup(pos); });
66 [this](CSwordModuleInfo * const module, QPoint const & pos) {
69 m_itemContextMenu->setProperty(
70 "BtModule",
71 QVariant::fromValue(
72 static_cast<void *>(module)));
73 m_itemContextMenu->popup(pos);
74 });
75}
76
77void
78BtBookshelfWidget::setSourceModel(std::shared_ptr<QAbstractItemModel> model) {
79 BT_ASSERT(model);
80 if (m_treeModel) {
81 m_sourceModel = model;
82 m_treeModel->setSourceModel(std::move(model));
83 } else {
84 m_sourceModel = std::move(model);
85 }
86}
87
100
102 delete m_leftCornerWidget;
103 w->setParent(this);
104 m_toolBar->insertWidget(0, w, 0);
105}
106
108 delete m_rightCornerWidget;
109 w->setParent(this);
110 m_toolBar->insertWidget(m_toolBar->count(), w, 0);
111}
112
114 m_showHideAction = new QAction(this);
115 m_showHideAction->setIcon(CResMgr::mainIndex::showHide::icon());
116 m_showHideAction->setCheckable(true);
117 BT_CONNECT(m_showHideAction, &QAction::toggled,
119}
120
122 // Grouping menu:
126 [this](BtBookshelfTreeModel::Grouping const & grouping) {
127 m_treeModel->setGroupingOrder(grouping);
128 m_treeView->setRootIsDecorated(!grouping.list().isEmpty());
129 });
130
131 // Context menu
132 m_contextMenu = new QMenu(this);
135
136 // Item context menu
138}
139
141 QVBoxLayout *layout(new QVBoxLayout);
142 layout->setContentsMargins(0, 8, 0, 0);
143 m_toolBar = new QHBoxLayout;
144 // Add a small margin between the edge of the window and the label (looks better)
145 m_toolBar->setContentsMargins(3, 0, 0, 0);
146 m_nameFilterLabel = new QLabel(this);
147 m_toolBar->addWidget(m_nameFilterLabel);
148
149 m_nameFilterEdit = new QLineEdit(this);
150 m_nameFilterEdit->installEventFilter(this);
152 m_toolBar->addWidget(m_nameFilterEdit);
153
154 m_groupingButton = new QToolButton(this);
155 m_groupingButton->setPopupMode(QToolButton::InstantPopup);
157 m_groupingButton->setIcon(m_groupingMenu->icon());
158 m_groupingButton->setAutoRaise(true);
159 m_toolBar->addWidget(m_groupingButton);
160
161 m_showHideButton = new QToolButton(this);
162 m_showHideButton->setDefaultAction(m_showHideAction);
163 m_showHideButton->setAutoRaise(true);
164 m_toolBar->addWidget(m_showHideButton);
165 layout->addLayout(m_toolBar);
166
167 m_treeView = new BtBookshelfView(this);
168 layout->addWidget(m_treeView);
169 setLayout(layout);
170}
171
173 m_nameFilterLabel->setText(tr("Fi&lter:"));
174 m_groupingButton->setText(tr("Grouping"));
175 m_groupingButton->setToolTip(tr("Change the grouping of items in the bookshelf."));
176 m_groupingMenu->setTitle(tr("Grouping"));
177 m_showHideAction->setText(tr("Show/hide works"));
178}
179
180bool BtBookshelfWidget::eventFilter(QObject *object, QEvent *event) {
181 BT_ASSERT(object == m_nameFilterEdit);
182 if (event->type() == QEvent::KeyPress) {
183 QKeyEvent *e = static_cast<QKeyEvent*>(event);
184 switch (e->key()) {
185 case Qt::Key_Up:
186 case Qt::Key_Down:
187 case Qt::Key_Enter:
188 case Qt::Key_Return:
189 QApplication::sendEvent(m_treeView, event);
190 return true;
191 default:
192 break;
193 }
194 }
195 return false;
196}
197
199 const QModelIndex& index,
200 QString prefix,
201 QStringList * expandedPaths) {
202 QString path = index.data(Qt::DisplayRole).toString();
203 if (m_treeView->isExpanded(index)) {
204 if (! prefix.isEmpty())
205 path = QStringLiteral("%1/%2").arg(prefix, path);
206 expandedPaths->append(path);
207 }
208 int rows = m_postFilterModel->rowCount(index);
209 for (int row = 0; row < rows; ++row) {
210 auto childIndex = m_postFilterModel->index(row, 0, index);
211 findExpanded(childIndex, path, expandedPaths);
212 }
213}
214
215void BtBookshelfWidget::restoreExpanded(const QModelIndex& index, const QStringList& nodeList) {
216 if (nodeList.isEmpty())
217 return;
218 QString firstNode = nodeList.first();
219 QStringList remainingNodes = nodeList;
220 remainingNodes.removeFirst();
221 int rows = m_postFilterModel->rowCount(index);
222 for (int row = 0; row < rows; ++row) {
223 auto childIndex = m_postFilterModel->index(row, 0, index);
224 QString text = childIndex.data(Qt::DisplayRole).toString();
225 if (firstNode == text) {
226 m_treeView->expand(childIndex);
227 restoreExpanded(childIndex, remainingNodes);
228 break;
229 }
230 }
231}
232
234 auto const paths =
235 btConfig().value<QStringList>(
236 QStringLiteral("GUI/MainWindow/Docks/Bookshelf/expandPaths"));
237 auto rootIndex = m_treeView->rootIndex();
238 for (auto const & path : paths) {
239 QStringList nodeList = path.split('/');
240 restoreExpanded(rootIndex, nodeList);
241 }
242}
243
245 QStringList paths;
246 QString prefix;
247 auto rootIndex = m_treeView->rootIndex();
248 findExpanded(rootIndex, prefix, &paths);
250 QStringLiteral("GUI/MainWindow/Docks/Bookshelf/expandPaths"),
251 paths);
252}
253
#define BT_ASSERT(...)
Definition btassert.h:17
BtConfig & btConfig()
This is a shortchand for BtConfig::getInstance().
Definition btconfig.h:305
#define BT_CONNECT(...)
Definition btconnect.h:20
void setNameFilterFixedString(QString const &nameFilter)
void setGrouping(BtBookshelfTreeModel::Grouping const &grouping)
void signalGroupingOrderChanged(const BtBookshelfTreeModel::Grouping &)
auto const & list() const noexcept
void groupingOrderChanged(BtBookshelfTreeModel::Grouping newGrouping)
void setGroupingOrder(BtBookshelfTreeModel::Grouping const &groupingOrder, bool emitSignal=true)
Grouping const & groupingOrder() const
void setSourceModel(std::shared_ptr< QAbstractItemModel > sourceModel)
void contextMenuActivated(QPoint pos)
void moduleContextMenuActivated(CSwordModuleInfo *item, QPoint pos)
BtBookshelfWidget(QWidget *parent=nullptr, Qt::WindowFlags flags=Qt::WindowFlags())
QToolButton * m_showHideButton
void restoreExpanded(const QModelIndex &index, const QStringList &nodeList)
void setRightCornerWidget(QWidget *w)
QHBoxLayout * m_toolBar
QLineEdit * m_nameFilterEdit
bool eventFilter(QObject *object, QEvent *event) override
void setTreeModel(BtBookshelfTreeModel *model)
void setSourceModel(std::shared_ptr< QAbstractItemModel > model)
void findExpanded(const QModelIndex &index, QString prefix, QStringList *expandedPaths)
std::shared_ptr< QAbstractItemModel > m_sourceModel
BtBookshelfTreeModel * m_treeModel
void setLeftCornerWidget(QWidget *w)
BtBookshelfFilterModel * m_postFilterModel
BtBookshelfGroupingMenu * m_groupingMenu
BtBookshelfView * m_treeView
QToolButton * m_groupingButton
T value(QString const &key, T const &defaultValue=T()) const
Returns the settings value for the given global key.
void setValue(QString const &key, T const &value)
Sets a value for a key.