18#include <QModelIndexList>
23#include "../../util/btassert.h"
24#include "../../util/btconnect.h"
25#include "../../util/macros.h"
26#include "../config/btconfigcore.h"
27#include "../drivers/btconstmoduleset.h"
28#include "../drivers/btmoduleset.h"
41 { GROUP_CATEGORY, GROUP_LANGUAGE };
45 { GROUP_LANGUAGE, GROUP_CATEGORY };
62 QString
const & key)
const
65 config.
setValue(key, QVariant::fromValue(*
this));
75 QString
const & configKey,
78 , m_rootItem(std::make_unique<
RootItem>())
80 [](
BtConfigCore const & config_, QString const & configKey_){
85 , m_defaultChecked(MODULE_HIDDEN)
92 , m_rootItem(std::make_unique<
RootItem>())
93 , m_groupingOrder(grouping)
94 , m_defaultChecked(MODULE_HIDDEN)
95 , m_checkable(false) {}
114 QModelIndex
const & parent)
const
116 if (!hasIndex(row, column,
parent))
return QModelIndex();
121 return QModelIndex();
123 return createIndex(row, column, childItem);
127 if (!
index.isValid())
128 return QModelIndex();
130 Item const * childItem(
static_cast<Item*
>(
index.internalPointer()));
136 return QModelIndex();
138 return createIndex(parentItem->
childIndex(), 0, parentItem);
146 Item const *
const i =
static_cast<Item*
>(
index.internalPointer());
150 case Qt::CheckStateRole:
162 return QVariant::fromValue(
static_cast<void *
>(&mi.
moduleInfo()));
164 return QVariant::fromValue(
nullptr);
166 case Qt::DisplayRole:
167 case Qt::DecorationRole:
171 return data(
static_cast<ModuleItem const *
>(i)->moduleInfo(), role);
173 return i->
data(role);
186 QVariant
const & value,
190 using IP = QPair<Item *, QModelIndex>;
192 if (
UNLIKELY(role != Qt::CheckStateRole))
196 Qt::CheckState newState =
static_cast<Qt::CheckState
>(value.toInt(&ok));
201 if (newState == Qt::PartiallyChecked)
202 newState = Qt::Checked;
204 Item * item =
static_cast<Item *
>(itemIndex.internalPointer());
206 if (item->
checkState() == newState)
return false;
210 IP p(item, itemIndex);
214 Q_EMIT dataChanged(p.second, p.second);
218 if (newState == Qt::Checked) {
226 QList<Item *>
const & children = item->
children();
227 for (
int i = 0; i < children.size(); i++)
228 q.append(IP(children.at(i),
index(i, 0, p.second)));
244 if (!
index.isValid())
245 return Qt::ItemFlags();
247 Qt::ItemFlags f(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
250 f |= Qt::ItemIsUserCheckable;
252 Item const & i = *
static_cast<Item*
>(
index.internalPointer());
254 f |= Qt::ItemIsAutoTristate;
261 Qt::Orientation
const orientation,
262 int const role)
const
264 if (orientation == Qt::Horizontal)
265 return m_sourceModel->headerData(section, orientation, role);
271 std::shared_ptr<QAbstractItemModel> sourceModel)
279 disconnect(&model, &QAbstractItemModel::rowsAboutToBeRemoved,
281 disconnect(&model, &QAbstractItemModel::rowsInserted,
283 disconnect(&model, &QAbstractItemModel::dataChanged,
295 BT_CONNECT(&model, &QAbstractItemModel::rowsAboutToBeRemoved,
297 BT_CONNECT(&model, &QAbstractItemModel::rowsInserted,
299 BT_CONNECT(&model, &QAbstractItemModel::dataChanged,
302 for (
int i = 0; i < model.rowCount(); i++) {
303 QModelIndex
const moduleIndex(model.index(i, 0));
305 model.data(moduleIndex,
306 BtBookshelfModel::ModulePointerRole).value<void*>());
310 checked = !model.data(moduleIndex,
313 checked = !model.data(moduleIndex,
326 bool const emitSignal)
344 m_sourceModel->data(sourceIndex,
345 BtBookshelfModel::ModulePointerRole).value<void *>());
369 if (
modules.contains(it.key())) {
378 QModelIndexList queue;
379 queue.append(QModelIndex());
381 QModelIndex
const parent(queue.takeFirst());
387 queue.append(childIndex);
389 }
while (!queue.isEmpty());
399 bool beginInsert = !inReset;
400 QModelIndex parentIndex;
403 while (!intermediateGrouping.empty()) {
404 switch (intermediateGrouping.takeFirst()) {
454 &&
i->parent()->children().size() <= 1)
460 int const index =
i->childIndex();
465 delete i->parent()->children().takeAt(
index);
478 Item *
const item =
static_cast<Item *
>(
index.internalPointer());
511 if (
state == Qt::PartiallyChecked) {
515 }
else if (
state == Qt::Checked) {
548 QModelIndex
const & bottomRight)
559 CSwordModuleInfo &
module = *static_cast<CSwordModuleInfo *>(data.value<void *>());
586 CSwordModuleInfo &
module = *static_cast<CSwordModuleInfo *>(data.value<void *>());
614 CSwordModuleInfo &
module = *static_cast<CSwordModuleInfo *>(data.value<void*>());
623 os << o.
list().size();
624 for (
auto const g : o.
list())
625 os <<
static_cast<std::underlying_type_t<decltype(g)
>>(g);
632 using Size =
decltype(o.
list().size());
641 using U = std::underlying_type_t<BtBookshelfTreeModel::Group>;
642 if constexpr (std::is_same_v<int, Size>) {
646 static_assert(
sizeof(int) == 4,
"Platform not supported");
647 static_assert(
sizeof(Size) == 8,
"Platform not supported");
655 static constexpr Size
const maxReadSize =
656 sizeof(Size) +
sizeof(U) * 2 + 2;
657 char buf[maxReadSize];
658 auto readSize = is.device()->peek(buf, maxReadSize);
659 if (readSize < maxReadSize) {
660 if (buf[readSize - 1] ==
')')
667 }
else if (readSize == 8) {
679 }
else if (readSize == 12) {
686 }
else if (s >= 0 && s <= 1) {
692 }
else if (readSize == 16) {
700 if (size >= 0 && size <= 2) {
701 decltype(o.
m_list) newList;
702 for (; size; --size) {
710 o.
m_list = std::move(newList);
715 qWarning() <<
"Failed to deserialize BtBookshelfTreeModel::Grouping";
716 is.setStatus(QDataStream::ReadCorruptData);
724template <
typename SizeType>
727 using U = std::underlying_type_t<BtBookshelfTreeModel::Group>;
728 auto const & list = expected.
list();
729 QByteArray byteArray;
731 QBuffer buffer(&byteArray);
732 buffer.open(QIODevice::WriteOnly);
733 QDataStream os(&buffer);
734 SizeType s = list.size();
736 for (
auto const g : list)
737 os << static_cast<U>(g);
739 QBuffer buffer(&byteArray);
740 buffer.open(QIODevice::ReadOnly);
741 QDataStream is(&buffer);
744 if (value == expected) {
745 qInfo() <<
"SUCCESS" << Q_FUNC_INFO << byteArray << list;
747 qFatal() <<
"FAILURE" << Q_FUNC_INFO << byteArray << list;
752 testGroupingSerialization_<int>(expected);
753 testGroupingSerialization_<
decltype(expected.
list().size())>(expected);
758void testGroupingSerializations() {
760 testGroupingSerialization(G::NONE);
761 testGroupingSerialization(G::CAT);
762 testGroupingSerialization(G::CAT_LANG);
763 testGroupingSerialization(G::LANG);
764 testGroupingSerialization(G::LANG_CAT);
QDataStream & operator>>(QDataStream &is, BtBookshelfTreeModel::Grouping &o)
QDataStream & operator<<(QDataStream &os, BtBookshelfTreeModel::Grouping const &o)
virtual QVariant data(int role=Qt::DisplayRole) const
Returns data for this item.
QList< Item * > & children()
Returns the list of child items of this node.
Type type() const
Returns the type of this item.
void setCheckState(Qt::CheckState const state)
Sets the check state of this item.
int childIndex() const
Returns the index of this item under its parent.
Qt::CheckState checkState() const
Returns the check state of this item.
Item * parent() const
Returns a pointer to the parent item of this item.
CSwordModuleInfo & moduleInfo() const
static Grouping const LANG_CAT
auto const & list() const noexcept
static Grouping const DEFAULT
static Grouping const CAT
static Grouping const CAT_LANG
void saveTo(BtConfigCore &config, QString const &key) const
static Grouping const LANG
static Grouping const NONE
bool loadFrom(BtConfigCore const &config, QString const &key)
QVariant data(QModelIndex const &index, int role=Qt::DisplayRole) const override
CheckedBehavior m_defaultChecked
QModelIndex index(int row, int column, QModelIndex const &parent=QModelIndex()) const override
std::unique_ptr< BookshelfModel::Item > m_rootItem
void groupingOrderChanged(BtBookshelfTreeModel::Grouping newGrouping)
void removeModule(CSwordModuleInfo &module)
BtModuleSet m_checkedModulesCache
QModelIndex parent(QModelIndex const &index) const override
std::shared_ptr< QAbstractItemModel > m_sourceModel
BookshelfModel::Item & getItem(QModelIndex const &index) const
QModelIndex getIndex(BookshelfModel::Item const &item)
void setCheckable(bool checkable)
void setCheckedModules(BtConstModuleSet const &modules)
void setGroupingOrder(BtBookshelfTreeModel::Grouping const &groupingOrder, bool emitSignal=true)
BtBookshelfTreeModel(QObject *parent=nullptr)
CSwordModuleInfo * module(QModelIndex const &index) const
bool setData(QModelIndex const &index, QVariant const &value, int role) override
QList< CSwordModuleInfo * > modules() const
int columnCount(QModelIndex const &parent=QModelIndex()) const override
~BtBookshelfTreeModel() override
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const override
SourceIndexMap m_sourceIndexMap
void resetParentCheckStates(QModelIndex parentIndex, bool inReset)
QModelIndex getGroup(CSwordModuleInfo const &module, QModelIndex const parentIndex, bool &beginInsert)
Qt::ItemFlags flags(QModelIndex const &index) const override
Grouping const & groupingOrder() const
bool hasChildren(QModelIndex const &parent=QModelIndex()) const override
std::shared_ptr< QAbstractItemModel > sourceModel() const noexcept
void setSourceModel(std::shared_ptr< QAbstractItemModel > sourceModel)
int rowCount(QModelIndex const &parent=QModelIndex()) const override
void moduleDataChanged(QModelIndex const &topLeft, QModelIndex const &bottomRight)
void addModule(CSwordModuleInfo &module, bool checked, bool inReset)
void moduleRemoved(QModelIndex const &parent, int start, int end)
void moduleInserted(QModelIndex const &parent, int start, int end)
void moduleChecked(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.