15 #include <QDataStream>
16 #include <QModelIndexList>
19 #include <type_traits>
21 #include "../../util/btassert.h"
22 #include "../../util/btconnect.h"
23 #include "../../util/macros.h"
24 #include "../config/btconfigcore.h"
25 #include "../drivers/btconstmoduleset.h"
26 #include "../drivers/btmoduleset.h"
48 QString
const & key)
const
51 config.
setValue(key, QVariant::fromValue(*
this));
56 , m_rootItem(std::make_unique<
RootItem>())
57 , m_defaultChecked(MODULE_HIDDEN)
58 , m_checkable(false) {}
61 QString
const & configKey,
64 , m_rootItem(std::make_unique<
RootItem>())
65 , m_groupingOrder(config, configKey)
66 , m_defaultChecked(MODULE_HIDDEN)
67 , m_checkable(false) {}
72 , m_rootItem(std::make_unique<
RootItem>())
73 , m_groupingOrder(grouping)
74 , m_defaultChecked(MODULE_HIDDEN)
75 , m_checkable(false) {}
94 const QModelIndex & parent)
const
96 if (!hasIndex(row, column,
parent))
return QModelIndex();
101 return QModelIndex();
103 return createIndex(row, column, childItem);
107 if (!
index.isValid())
108 return QModelIndex();
110 Item * childItem(
static_cast<Item*
>(
index.internalPointer()));
116 return QModelIndex();
118 return createIndex(parentItem->
childIndex(), 0, parentItem);
125 const Item *
const i =
static_cast<Item*
>(
index.internalPointer());
129 case Qt::CheckStateRole:
139 if (i->
type() == Item::ITEM_MODULE) {
141 return QVariant::fromValue(
static_cast<void *
>(&mi.
moduleInfo()));
143 return QVariant::fromValue(
nullptr);
145 case Qt::DisplayRole:
146 case Qt::DecorationRole:
149 if (i->
type() == Item::ITEM_MODULE)
150 return data(
static_cast<const ModuleItem *
>(i)->moduleInfo(), role);
152 return i->
data(role);
164 const QVariant & value,
167 using IP = QPair<Item *, QModelIndex>;
169 if (
UNLIKELY(role != Qt::CheckStateRole))
173 Qt::CheckState newState =
static_cast<Qt::CheckState
>(value.toInt(&ok));
178 if (newState == Qt::PartiallyChecked)
179 newState = Qt::Checked;
181 Item * item =
static_cast<Item *
>(itemIndex.internalPointer());
183 if (item->
checkState() == newState)
return false;
187 IP p(item, itemIndex);
191 Q_EMIT dataChanged(p.second, p.second);
192 if (item->
type() == Item::ITEM_MODULE) {
195 if (newState == Qt::Checked) {
204 for (
int i = 0; i < children.size(); i++)
205 q.append(IP(children.at(i),
index(i, 0, p.second)));
221 if (!
index.isValid())
222 return Qt::ItemFlags();
224 Qt::ItemFlags f(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
227 f |= Qt::ItemIsUserCheckable;
229 const Item & i = *
static_cast<Item*
>(
index.internalPointer());
230 if (i.
type() != Item::ITEM_MODULE)
231 f |= Qt::ItemIsAutoTristate;
238 Qt::Orientation orientation,
241 if (orientation == Qt::Horizontal)
242 return m_sourceModel->headerData(section, orientation, role);
248 std::shared_ptr<QAbstractItemModel> sourceModel)
255 disconnect(&model, &QAbstractItemModel::rowsAboutToBeRemoved,
257 disconnect(&model, &QAbstractItemModel::rowsInserted,
259 disconnect(&model, &QAbstractItemModel::dataChanged,
261 beginRemoveRows(QModelIndex(), 0,
m_rootItem->children().size() - 1);
273 BT_CONNECT(&model, &QAbstractItemModel::rowsAboutToBeRemoved,
275 BT_CONNECT(&model, &QAbstractItemModel::rowsInserted,
277 BT_CONNECT(&model, &QAbstractItemModel::dataChanged,
280 for (
int i = 0; i < model.rowCount(); i++) {
281 const QModelIndex moduleIndex(model.index(i, 0));
283 model.data(moduleIndex,
288 checked = !model.data(moduleIndex,
291 checked = !model.data(moduleIndex,
314 beginRemoveRows(QModelIndex(), 0,
m_rootItem->children().size() - 1);
346 if (
modules.contains(it.key())) {
355 QModelIndexList queue;
356 queue.append(QModelIndex());
358 QModelIndex
parent(queue.takeFirst());
364 queue.append(childIndex);
366 }
while (!queue.isEmpty());
388 QModelIndex parentIndex,
392 if (!intermediateGrouping.empty()) {
393 QModelIndex newIndex;
394 switch (intermediateGrouping.front()) {
397 newIndex = getGroup<CategoryItem>(
module, parentIndex);
401 newIndex = getGroup<LanguageItem>(
module, parentIndex);
405 newIndex = getGroup<IndexingItem>(
module, parentIndex);
409 intermediateGrouping.pop_front();
414 newItem->
setCheckState(checked ? Qt::Checked : Qt::Unchecked);
415 const int newIndex(parentItem.
indexFor(*newItem));
418 beginInsertRows(parentIndex, newIndex, newIndex);
436 Item * i = it.value();
465 Item *
const item =
static_cast<Item *
>(
index.internalPointer());
482 while (!indexes.isEmpty())
483 i =
index(indexes.takeLast(), 0, i);
488 for ( ; parentIndex.isValid(); parentIndex = parentIndex.parent()) {
489 Item & parentItem = *
static_cast<Item *
>(parentIndex.internalPointer());
491 const Qt::CheckState oldState = parentItem.
checkState();
492 bool haveCheckedChildren =
false;
493 bool haveUncheckedChildren =
false;
494 for (
int i = 0; i < parentItem.
children().size(); i++) {
495 const Qt::CheckState state = parentItem.
children().at(i)->checkState();
496 if (state == Qt::PartiallyChecked) {
497 haveCheckedChildren =
true;
498 haveUncheckedChildren =
true;
500 }
else if (state == Qt::Checked) {
501 haveCheckedChildren =
true;
502 if (haveUncheckedChildren)
506 haveUncheckedChildren =
true;
507 if (haveCheckedChildren)
512 Qt::CheckState newState;
513 if (haveCheckedChildren) {
514 if (haveUncheckedChildren) {
515 newState = Qt::PartiallyChecked;
517 newState = Qt::Checked;
520 newState = Qt::Unchecked;
522 if (newState == oldState)
526 Q_EMIT dataChanged(parentIndex, parentIndex);
531 const QModelIndex & bottomRight)
534 BT_ASSERT(!bottomRight.parent().isValid());
538 for (
int i = topLeft.row(); i <= bottomRight.row(); i++) {
539 const QModelIndex moduleIndex(
m_sourceModel->index(i, 0, topLeft.parent()));
546 Q_EMIT dataChanged(itemIndex, itemIndex);
553 itemIndex = itemIndex.parent();
554 Q_EMIT dataChanged(itemIndex, itemIndex);
555 }
while (itemIndex.isValid());
565 for (
int i = start; i <= end; i++) {
593 for (
int i = start; i <= end; i++) {
608 os <<
static_cast<std::underlying_type<decltype(g)
>::type>(g);
618 for (
int i = 0; i < s; i++) {
QDataStream & operator<<(QDataStream &os, const BtBookshelfTreeModel::Grouping &o)
QDataStream & operator>>(QDataStream &is, BtBookshelfTreeModel::Grouping &o)
void setCheckState(const Qt::CheckState state)
Sets the check state of this item.
virtual QVariant data(int role=Qt::DisplayRole) const
Returns data for this item.
int indexFor(Item const &newItem)
Returns the position for where the given child item would be inserted.
Type type() const
Returns the type of this item.
QList< Item * > & children()
Returns the list of child items of this node.
int childIndex() const
Returns the index of this item under its parent.
Item * parent() const
Returns a pointer to the parent item of this item.
void insertChild(int index, Item *newItem)
Inserts the given item as a child at the given index.
Qt::CheckState checkState() const
Returns the check state of this item.
CSwordModuleInfo & moduleInfo() const
void saveTo(BtConfigCore &config, QString const &key) const
bool loadFrom(BtConfigCore const &config, QString const &key)
void moduleInserted(const QModelIndex &parent, int start, int end)
CheckedBehavior m_defaultChecked
std::unique_ptr< BookshelfModel::Item > m_rootItem
void groupingOrderChanged(BtBookshelfTreeModel::Grouping newGrouping)
void removeModule(CSwordModuleInfo &module)
void resetParentCheckStates(QModelIndex parentIndex)
BtModuleSet m_checkedModulesCache
Qt::ItemFlags flags(const QModelIndex &index) const override
QModelIndex getIndex(const BookshelfModel::Item &item)
void moduleRemoved(const QModelIndex &parent, int start, int end)
QModelIndex parent(const QModelIndex &index) const override
BookshelfModel::Item & getItem(const QModelIndex &index) const
std::shared_ptr< QAbstractItemModel > m_sourceModel
void setCheckable(bool checkable)
void setCheckedModules(BtConstModuleSet const &modules)
BtBookshelfTreeModel(QObject *parent=nullptr)
std::shared_ptr< QAbstractItemModel > sourceModel() const noexcept
bool setData(const QModelIndex &index, const QVariant &value, int role) override
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
int columnCount(const QModelIndex &parent=QModelIndex()) const override
~BtBookshelfTreeModel() override
void setGroupingOrder(const BtBookshelfTreeModel::Grouping &groupingOrder, bool emitSignal=true)
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const override
SourceIndexMap m_sourceIndexMap
Grouping const & groupingOrder() const
void moduleDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
QList< CSwordModuleInfo * > modules() const
int rowCount(const QModelIndex &parent=QModelIndex()) const override
bool hasChildren(const QModelIndex &parent=QModelIndex()) const override
void setSourceModel(std::shared_ptr< QAbstractItemModel > sourceModel)
CSwordModuleInfo * module(QModelIndex const &index) const
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
void moduleChecked(CSwordModuleInfo *module, bool checked)
void addModule(CSwordModuleInfo &module, bool checked)
void setValue(QString const &key, T const &value)
Sets a value for a key.
QVariant qVariantValue(QString const &key, QVariant const &defaultValue=QVariant()) const
Returns the settings value for the given global key as a QVariant.
bool contains(CSwordModuleInfo const *const m) const
#define UNLIKELY(c)
Gives the compiler a hint that the given conditional is likely to evaluate to false.