33 #include <QItemSelectionRange>
54 QPersistentModelIndex
Index_;
62 for (
int i = 0, size = c.size (); i < size; ++i)
63 if (c.at (i).get () ==
this)
70 FlatTreeItem*
ToFlat (
const QModelIndex& idx)
72 return static_cast<FlatTreeItem*> (idx.internalPointer ());
78 : QAbstractItemModel { parent }
80 , Root_ { std::make_shared<FlatTreeItem> () }
85 int FlatToFoldersProxyModel::columnCount (
const QModelIndex&)
const
88 SourceModel_->columnCount (QModelIndex ()) :
92 QVariant FlatToFoldersProxyModel::data (
const QModelIndex& index,
int role)
const
97 QModelIndex source = fti->Index_;
98 return source.sibling (source.row (), index.column ()).data (role);
101 index.column () == 0)
103 if (role == Qt::DisplayRole)
105 if (fti->Tag_.isEmpty ())
106 return tr (
"untagged");
108 QString ut = TM_->GetTag (fti->Tag_);
110 return tr (
"<unknown tag>");
123 QVariant FlatToFoldersProxyModel::headerData (
int section,
124 Qt::Orientation orient,
int role)
const
127 return SourceModel_->headerData (section, orient, role);
132 Qt::ItemFlags FlatToFoldersProxyModel::flags (
const QModelIndex& index)
const
134 auto fti =
ToFlat (index);
136 return fti->Index_.flags ();
138 return Qt::ItemIsSelectable |
140 Qt::ItemIsDragEnabled |
141 Qt::ItemIsDropEnabled;
144 QModelIndex FlatToFoldersProxyModel::index (
int row,
int column,
145 const QModelIndex& parent)
const
147 if (!hasIndex (row, column, parent))
148 return QModelIndex ();
151 if (parent.isValid ())
157 return QModelIndex ();
159 return createIndex (row, column, fti->C_.at (row).get ());
162 QModelIndex FlatToFoldersProxyModel::parent (
const QModelIndex& index)
const
165 if (index.isValid ())
171 parent = fti->Parent_;
175 return createIndex (parent->Row (), 0, parent.get ());
177 return QModelIndex ();
180 int FlatToFoldersProxyModel::rowCount (
const QModelIndex& index)
const
182 if (index.isValid ())
185 return Root_->C_.size ();
188 Qt::DropActions FlatToFoldersProxyModel::supportedDropActions()
const
190 return SourceModel_ ?
191 SourceModel_->supportedDropActions () :
192 QAbstractItemModel::supportedDropActions ();
195 QStringList FlatToFoldersProxyModel::mimeTypes()
const
197 return SourceModel_ ?
198 SourceModel_->mimeTypes () :
199 QAbstractItemModel::mimeTypes ();
202 QMimeData* FlatToFoldersProxyModel::mimeData (
const QModelIndexList& indexes)
const
205 return QAbstractItemModel::mimeData (indexes);
207 QModelIndexList sourceIdxs;
208 for (
const auto& index : indexes)
210 auto item = static_cast<FlatTreeItem*> (index.internalPointer ());
214 sourceIdxs << MapToSource (index);
217 for (
const auto& subItem : item->C_)
218 sourceIdxs << subItem->Index_;
225 return SourceModel_->mimeData (sourceIdxs);
228 bool FlatToFoldersProxyModel::dropMimeData (
const QMimeData* data, Qt::DropAction action,
int,
int,
const QModelIndex& parent)
234 for (
const auto& format : data->formats ())
235 modified.setData (format, data->data (format));
237 if (
auto ptr = static_cast<FlatTreeItem*> (parent.internalPointer ()))
243 modified.setData (
"x-leechcraft/tag", ptr->Tag_.toLatin1 ());
250 return SourceModel_->dropMimeData (&modified, action, -1, -1, QModelIndex ());
253 void FlatToFoldersProxyModel::SetSourceModel (QAbstractItemModel *model)
256 disconnect (SourceModel_,
261 SourceModel_ = model;
268 SIGNAL (headerDataChanged (Qt::Orientation,
int,
int)),
270 SIGNAL (headerDataChanged (Qt::Orientation,
int,
int)));
272 SIGNAL (dataChanged (
const QModelIndex&,
const QModelIndex&)),
274 SLOT (handleDataChanged (
const QModelIndex&,
const QModelIndex&)));
276 SIGNAL (layoutAboutToBeChanged ()),
278 SIGNAL (layoutAboutToBeChanged ()));
280 SIGNAL (layoutChanged ()),
282 SIGNAL (layoutChanged ()));
284 SIGNAL (modelReset ()),
286 SLOT (handleModelReset ()));
288 SIGNAL (rowsInserted (
const QModelIndex&,
291 SLOT (handleRowsInserted (
const QModelIndex&,
294 SIGNAL (rowsAboutToBeRemoved (
const QModelIndex&,
297 SLOT (handleRowsAboutToBeRemoved (
const QModelIndex&,
304 QAbstractItemModel* FlatToFoldersProxyModel::GetSourceModel ()
const
309 QModelIndex FlatToFoldersProxyModel::MapToSource (
const QModelIndex& proxy)
const
311 if (!GetSourceModel ())
314 if (!proxy.isValid ())
317 const auto item =
ToFlat (proxy);
325 QList<QModelIndex> FlatToFoldersProxyModel::MapFromSource (
const QModelIndex& source)
const
327 auto tags = source.data (
RoleTags).toStringList ();
332 for (
const auto& tag : tags)
334 const auto& folder = FindFolder (tag);
337 qWarning () << Q_FUNC_INFO
338 <<
"could not find folder for tag"
340 << GetSourceModel ();
344 const auto& folderIdx = index (folder->Row (), 0, {});
346 for (
int i = 0; i < folder->C_.size (); ++i)
348 const auto& child = folder->C_.at (i);
349 if (child->Index_ != source)
352 result << index (i, 0, folderIdx);
359 FlatTreeItem_ptr FlatToFoldersProxyModel::FindFolder (
const QString& tag)
const
361 for (
const auto& item : Root_->C_)
362 if (item->Tag_ == tag)
371 for (
const auto& item : c)
372 if (item->Tag_ == tag)
375 const auto& item = std::make_shared<FlatTreeItem> ();
378 item->Parent_ = Root_;
380 int size = c.size ();
381 beginInsertRows (QModelIndex (), size, size);
388 void FlatToFoldersProxyModel::HandleRowInserted (
int i)
390 QModelIndex idx = SourceModel_->index (i, 0);
392 QStringList tags = idx.data (
RoleTags).toStringList ();
397 QPersistentModelIndex pidx (idx);
399 for (
auto tag : tags)
400 AddForTag (tag, pidx);
403 void FlatToFoldersProxyModel::HandleRowRemoved (
int i)
405 QAbstractItemModel *model = SourceModel_;
406 QModelIndex idx = model->index (i, 0);
408 QStringList tags = idx.data (
RoleTags).toStringList ();
413 QPersistentModelIndex pidx (idx);
415 for (
const auto tag : tags)
416 RemoveFromTag (tag, pidx);
419 void FlatToFoldersProxyModel::AddForTag (
const QString& tag,
420 const QPersistentModelIndex& pidx)
424 const auto& item = std::make_shared<FlatTreeItem> ();
427 item->Parent_ = folder;
430 int size = folder->C_.size ();
431 QModelIndex iidx = index (Root_->C_.indexOf (folder), 0);
432 beginInsertRows (iidx, size, size);
433 folder->C_.append (item);
434 Items_.insert (pidx, item);
438 void FlatToFoldersProxyModel::RemoveFromTag (
const QString& tag,
439 const QPersistentModelIndex& pidx)
441 const auto& folder = GetFolder (tag);
442 auto& c = folder->C_;
443 int findex = Root_->C_.indexOf (folder);
444 for (
int i = 0, size = c.size ();
447 if (c.at (i)->Index_ != pidx)
450 beginRemoveRows (index (findex, 0), i, i);
451 Items_.remove (pidx, c.at (i));
459 beginRemoveRows (QModelIndex (), findex, findex);
460 Root_->C_.removeAt (findex);
465 void FlatToFoldersProxyModel::HandleChanged (
const QModelIndex& idx)
467 QSet<QString> newTags = QSet<QString>::fromList (idx.data (
RoleTags).toStringList ());
468 if (newTags.isEmpty ())
469 newTags << QString ();
471 QPersistentModelIndex pidx (idx);
473 const auto& oldTags = Util::MapAs<QSet> (
Items_.values (pidx), [] (
const auto& item) {
return item->Tag_; });
475 const auto added = QSet<QString> (newTags).subtract (oldTags);
476 const auto removed = QSet<QString> (oldTags).subtract (newTags);
477 const auto changed = QSet<QString> (newTags).intersect (oldTags);
479 for (
const auto& ch : changed)
484 int findex = Root_->C_.indexOf (folder);
485 QModelIndex fmi = index (findex, 0);
486 for (
int i = 0, size = c.size ();
489 if (c.at (i)->Index_ != pidx)
492 emit dataChanged (index (i, 0, fmi),
493 index (i, columnCount () - 1, fmi));
498 for (
const auto& rem : removed)
499 RemoveFromTag (rem, pidx);
501 for (
const auto& add : added)
502 AddForTag (add, pidx);
505 void FlatToFoldersProxyModel::handleDataChanged (
const QModelIndex& topLeft,
506 const QModelIndex& bottomRight)
508 QItemSelectionRange range (topLeft.sibling (topLeft.row (), 0),
509 bottomRight.sibling (bottomRight.row (), 0));
510 QModelIndexList indexes = range.indexes ();
511 for (
int i = 0, size = indexes.size ();
513 HandleChanged (indexes.at (i));
516 void FlatToFoldersProxyModel::handleModelReset ()
518 if (
const int size = Root_->C_.size ())
520 beginRemoveRows (QModelIndex (), 0, size - 1);
528 for (
int i = 0, size = SourceModel_->rowCount ();
530 HandleRowInserted (i);
534 void FlatToFoldersProxyModel::handleRowsInserted (
const QModelIndex&,
537 for (
int i = start; i <= end; ++i)
538 HandleRowInserted (i);
541 void FlatToFoldersProxyModel::handleRowsAboutToBeRemoved (
const QModelIndex&,
544 for (
int i = start; i <= end; ++i)
545 HandleRowRemoved (i);