22 enum class Type : std::uint8_t
41 ,
Tag_ { std::move (tag) }
51 const auto pos = std::ranges::find_if (siblings, [
this] (
const auto& sibling) {
return sibling.get () ==
this; });
52 return pos - siblings.begin ();
57 return C_.emplaceBack (std::make_shared<FlatTreeItem> (
Type::Folder, *
this, tag));
62 const auto& leaf =
C_.emplaceBack (std::make_shared<FlatTreeItem> (
Type::Item, *
this,
Tag_));
70 FlatTreeItem* ToFlat (
const QModelIndex& idx)
72 return static_cast<FlatTreeItem*
> (idx.internalPointer ());
75 QStringList TagsOf (
const QModelIndex& idx)
85 : QAbstractItemModel {
parent }
95 SourceModel_->columnCount ({}) :
101 if (!
index.isValid ())
104 const auto fti = ToFlat (
index);
108 const auto& source = fti->Index_;
109 return source.sibling (source.row (),
index.column ()).data (role);
116 case Qt::DisplayRole:
118 if (fti->Tag_.isEmpty ())
119 return tr (
"untagged");
121 const auto& ut = TM_->GetTag (fti->Tag_);
122 return ut.isEmpty () ? tr (
"<unknown tag>") : ut;
139 return SourceModel_->headerData (section, orient, role);
144 if (!
index.isValid ())
145 return Qt::ItemIsDropEnabled;
147 if (
const auto fti = ToFlat (
index);
150 const auto& source = fti->Index_;
151 return source.sibling (source.row (),
index.column ()).flags ();
154 return Qt::ItemIsSelectable |
156 Qt::ItemIsDragEnabled |
157 Qt::ItemIsDropEnabled;
162 if (!
index.isValid ())
165 const auto fti = ToFlat (
index);
169 const auto& source = fti->Index_;
170 return SourceModel_->setData (source.sibling (source.row (),
index.column ()), value, role);
175 if (!hasIndex (row, column,
parent))
178 return createIndex (row, column, ToFlatOrRoot (
parent).C_.at (row).get ());
192 if (
index.column () > 0)
195 return ToFlatOrRoot (
index).C_.size ();
200 return SourceModel_ ?
201 SourceModel_->supportedDropActions () :
202 QAbstractItemModel::supportedDropActions ();
207 return SourceModel_ ?
208 SourceModel_->mimeTypes () :
209 QAbstractItemModel::mimeTypes ();
215 return QAbstractItemModel::mimeData (indexes);
217 QModelIndexList sourceIdxs;
218 for (
const auto&
index : indexes)
227 for (
const auto& subItem : item->C_)
228 sourceIdxs << subItem->Index_;
235 return SourceModel_->mimeData (sourceIdxs);
244 for (
const auto& format :
data->formats ())
245 modified.setData (format,
data->data (format));
248 modified.setData (QStringLiteral (
"x-leechcraft/tag"), ToFlat (
parent)->Tag_.toLatin1 ());
250 return SourceModel_->dropMimeData (&modified, action, -1, -1, QModelIndex ());
256 disconnect (SourceModel_,
261 SourceModel_ = model;
270 &QAbstractItemModel::headerDataChanged,
272 &QAbstractItemModel::headerDataChanged);
274 &QAbstractItemModel::dataChanged,
276 &FlatToFoldersProxyModel::HandleDataChanged);
278 &QAbstractItemModel::modelReset,
280 &FlatToFoldersProxyModel::HandleModelReset);
282 &QAbstractItemModel::rowsInserted,
284 &FlatToFoldersProxyModel::HandleRowsInserted);
286 &QAbstractItemModel::rowsAboutToBeRemoved,
288 &FlatToFoldersProxyModel::HandleRowsAboutToBeRemoved);
304 if (!proxy.isValid ())
307 const auto item = ToFlat (proxy);
318 for (
const auto& leaf : Items_.values (QPersistentModelIndex { source }))
319 result << IndexOf (*leaf);
325 const auto item = ToFlat (
index);
334 const auto& children = ToFlat (
index)->C_;
336 result.reserve (children.size ());
337 for (
const auto& child : children)
338 result << child->Index_;
347 result.reserve (children.size ());
348 for (
const auto& child : children)
349 result.push_back (child.data (role));
353 FlatTreeItem_ptr FlatToFoldersProxyModel::FindFolder (
const QString& tag)
const
355 const auto& folders = Root_->C_;
357 return pos == folders.end () ? nullptr : *pos;
362 if (
const auto& folder = FindFolder (tag))
365 const auto row = Root_->C_.size ();
366 beginInsertRows ({}, row, row);
367 const auto& folder = Root_->AddFolder (tag);
372 const FlatTreeItem& FlatToFoldersProxyModel::ToFlatOrRoot (
const QModelIndex& idx)
const
374 return idx.isValid () ? *ToFlat (idx) : *Root_;
377 QModelIndex FlatToFoldersProxyModel::IndexOf (
const FlatTreeItem& item,
int column)
const
379 return createIndex (item.Row (), column, &item);
382 void FlatToFoldersProxyModel::AddForTag (
const QString& tag,
const QPersistentModelIndex& pidx)
384 const auto& folder = GetFolder (tag);
385 const auto row = folder->C_.size ();
386 beginInsertRows (IndexOf (*folder), row, row);
387 Items_.insert (pidx, folder->AddLeaf (pidx));
393 const auto folder = leaf->Parent_;
394 const auto leafRow = leaf->Row ();
395 beginRemoveRows (IndexOf (*folder), leafRow, leafRow);
396 Items_.remove (leaf->Index_, leaf);
397 folder->C_.removeAt (leafRow);
400 if (!folder->C_.isEmpty ())
403 const auto folderRow = folder->Row ();
404 beginRemoveRows ({}, folderRow, folderRow);
405 Root_->C_.removeAt (folderRow);
409 void FlatToFoldersProxyModel::HandleDataChanged (
const QModelIndex& topLeft,
const QModelIndex& bottomRight,
const QList<int>& roles)
411 for (
int row = topLeft.row (); row <= bottomRight.row (); ++row)
413 const QPersistentModelIndex pidx { topLeft.sibling (row, 0) };
414 auto tags =
AsSet (TagsOf (pidx));
415 for (
const auto& leaf : Items_.values (pidx))
416 if (tags.remove (leaf->Tag_))
417 emit dataChanged (IndexOf (*leaf), IndexOf (*leaf,
columnCount () - 1), roles);
421 for (
const auto& tag : tags)
422 AddForTag (tag, pidx);
426 void FlatToFoldersProxyModel::HandleModelReset ()
432 for (
int i = 0, size = SourceModel_->rowCount (); i < size; ++i)
434 const QPersistentModelIndex pidx { SourceModel_->index (i, 0) };
435 for (
const auto& tag : TagsOf (pidx))
437 auto folder = FindFolder (tag);
439 folder = Root_->AddFolder (tag);
440 Items_.insert (pidx, folder->AddLeaf (pidx));
446 void FlatToFoldersProxyModel::HandleRowsInserted (
const QModelIndex&,
int start,
int end)
448 for (
int i = start; i <= end; ++i)
450 const QPersistentModelIndex pidx { SourceModel_->index (i, 0) };
451 for (
const auto& tag : TagsOf (pidx))
452 AddForTag (tag, pidx);
456 void FlatToFoldersProxyModel::HandleRowsAboutToBeRemoved (
const QModelIndex&,
int start,
int end)
458 for (
int i = start; i <= end; ++i)
459 for (
const auto& leaf : Items_.values (QPersistentModelIndex { SourceModel_->index (i, 0) }))
QList< QModelIndex > GetChildren(const QModelIndex &) const
QVariant headerData(int, Qt::Orientation, int) const override
Qt::DropActions supportedDropActions() const override
int rowCount(const QModelIndex &={}) const override
QAbstractItemModel * GetSourceModel() const
void SetSourceModel(QAbstractItemModel *)
bool IsFolder(const QModelIndex &) const
FlatToFoldersProxyModel(const ITagsManager *, QObject *=nullptr)
QModelIndex parent(const QModelIndex &) const override
QMimeData * mimeData(const QModelIndexList &indexes) const override
QList< QModelIndex > MapFromSource(const QModelIndex &) const
QList< QVariant > GetChildrenData(const QModelIndex &index, int role) const
bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override
int columnCount(const QModelIndex &={}) const override
QVariant data(const QModelIndex &, int=Qt::DisplayRole) const override
bool setData(const QModelIndex &, const QVariant &, int=Qt::EditRole) override
QModelIndex MapToSource(const QModelIndex &) const
QModelIndex index(int, int, const QModelIndex &={}) const override
Qt::ItemFlags flags(const QModelIndex &) const override
QStringList mimeTypes() const override
std::shared_ptr< FlatTreeItem > FlatTreeItem_ptr
auto AsSet(const T &cont)
void InstallModelSanitizer(QAbstractItemModel &model)
QPersistentModelIndex Index_
FlatTreeItem(Type type, FlatTreeItem &parent, QString tag)
QList< FlatTreeItem_ptr > C_
FlatTreeItem *const Parent_
FlatTreeItem_ptr AddLeaf(const QPersistentModelIndex &index)
FlatTreeItem_ptr AddFolder(const QString &tag)