9 #include <QJsonDocument>
14 #include "gui/models/allmodelcontainers.h"
19 using namespace swift::misc::aviation;
23 template <
typename T,
bool UseCompare>
28 template <
typename T,
bool UseCompare>
32 return this->containerOrFilteredContainer().size();
35 template <
typename T,
bool UseCompare>
37 int column,
const QModelIndex &parent)
const
43 if (!this->isDropAllowed()) {
return false; }
44 if (!this->acceptDrop(data)) {
return false; }
48 template <
typename T,
bool UseCompare>
50 int column,
const QModelIndex &parent)
55 if (!this->isOrderable() || !this->acceptDrop(mimeData)) {
return false; }
56 const CVariant valueVariant(this->toCVariant(mimeData));
57 if (valueVariant.isValid())
59 if (action == Qt::MoveAction)
62 if (container.
isEmpty()) {
return false; }
63 const int position = parent.row();
64 this->moveItems(container, position);
70 template <
typename T,
bool UseCompare>
73 if (!index.isValid()) {
return false; }
74 return (index.row() >= 0 && index.row() < this->rowCount(index) && index.column() >= 0 &&
75 index.column() < this->columnCount(index));
78 template <
typename T,
bool UseCompare>
82 if (!this->isValidIndex(index)) {
return QVariant(); }
84 if (role == Qt::BackgroundRole) {
return CListModelBaseNonTemplate::data(index, role); }
88 Q_ASSERT_X(formatter, Q_FUNC_INFO,
"Missing formatter");
91 if (!formatter || !formatter->
supportsRole(role)) {
return CListModelBaseNonTemplate::data(index, role); }
93 const int row = index.row();
94 const int col = index.column();
95 const CPropertyIndex propertyIndex = this->columnToPropertyIndex(col);
96 const int propertyIndexFront = propertyIndex.
frontCasted<
int>();
99 switch (propertyIndexFront)
101 case CPropertyIndexRef::GlobalIndexLineNumber:
return QVariant::fromValue(row + 1);
102 case CPropertyIndexRef::GlobalIndexEmpty:
return {};
107 const ObjectType obj = this->containerOrFilteredContainer()[row];
108 return formatter->
data(role, obj.propertyByIndex(propertyIndex)).
getQVariant();
111 template <
typename T,
bool UseCompare>
114 Qt::ItemDataRole dataRole =
static_cast<Qt::ItemDataRole
>(role);
115 if (!(dataRole == Qt::UserRole || dataRole == Qt::EditRole)) {
return false; }
118 if (!this->isValidIndex(index)) {
return false; }
119 if (!m_columns.isEditable(index)) {
return false; }
120 const CDefaultFormatter *formatter = m_columns.getFormatter(index);
122 if (!formatter) {
return false; }
124 ObjectType obj = m_container[index.row()];
126 const CPropertyIndex propertyIndex = this->columnToPropertyIndex(index.column());
127 obj.setPropertyByIndex(propertyIndex, value);
129 if (obj != currentObject)
131 const QModelIndex topLeft = index.sibling(index.row(), 0);
132 const QModelIndex bottomRight = index.sibling(index.row(), this->columnCount() - 1);
133 m_container[index.row()] = obj;
134 const CVariant co = CVariant::fromValue(obj);
135 emit objectChanged(co, propertyIndex);
136 emit this->dataChanged(topLeft, bottomRight);
137 this->updateFilteredContainer();
143 template <
typename T,
bool UseCompare>
146 if (!index.isValid()) {
return false; }
147 const int row = index.row();
148 if (row < 0 || row >= this->container().size()) {
return false; }
149 m_container[row] = obj;
153 template <
typename T,
bool UseCompare>
156 if (m_modelDestroyed) {
return 0; }
161 if (m_selectionModel) { selection = m_selectionModel->selectedObjects(); }
162 const int oldSize = m_container.
size();
163 const bool performSort = sort && container.size() > 1 && this->hasValidSortColumn();
166 const int sortColumn = this->getSortColumn();
167 sortedContainer = this->sortContainerByColumn(container, sortColumn, m_sortOrder);
170 this->beginResetModel();
171 m_container = performSort ? sortedContainer : container;
172 this->updateFilteredContainer();
173 this->endResetModel();
176 if (!selection.
isEmpty()) { m_selectionModel->selectObjects(selection); }
178 const int newSize = m_container.size();
182 this->emitModelDataChanged();
186 template <typename T,
bool UseCompare>
189 if (m_modelDestroyed) {
return; }
190 if (index.row() >= m_container.size()) {
return; }
191 m_container[index.row()] = object;
193 const QModelIndex i1 = index.sibling(index.row(), 0);
194 const QModelIndex i2 = index.sibling(index.row(), this->columnCount(index) - 1);
195 emit this->dataChanged(i1, i2);
198 template <
typename T,
bool UseCompare>
201 this->update(this->index(rowIndex, 0),
object);
204 template <
typename T,
bool UseCompare>
208 if (m_modelDestroyed) {
return nullptr; }
209 const auto sortColumn = this->getSortColumn();
210 const auto sortOrder = this->getSortOrder();
211 CWorker *worker = CWorker::fromTask(
this,
"ModelSort", [
this, container, sortColumn, sortOrder]() {
212 return this->sortContainerByColumn(container, sortColumn, sortOrder);
214 worker->
thenWithResult<ContainerType>(
this, [
this](
const ContainerType &sortedContainer) {
215 if (m_modelDestroyed) {
return; }
216 this->update(sortedContainer,
false);
222 template <
typename T,
bool UseCompare>
225 if (m_modelDestroyed) {
return; }
226 if (container.size() > asyncThreshold && sort)
229 this->updateAsync(container, sort);
231 else { this->update(container, sort); }
234 template <
typename T,
bool UseCompare>
237 const bool f = m_filter && m_filter->isValid();
241 template <
typename T,
bool UseCompare>
244 if (!this->hasFilter()) {
return; }
245 m_filter.reset(
nullptr);
246 this->beginResetModel();
247 this->updateFilteredContainer();
248 this->endResetModel();
249 this->emitModelDataChanged();
252 template <
typename T,
bool UseCompare>
256 if (m_selectionModel) { selection = m_selectionModel->selectedObjects(); }
260 this->removeFilter();
263 if (filter->isValid())
265 m_filter = std::move(filter);
266 this->beginResetModel();
267 this->updateFilteredContainer();
268 this->endResetModel();
269 this->emitModelDataChanged();
274 this->removeFilter();
278 if (!selection.isEmpty()) { m_selectionModel->selectObjects(selection); }
281 template <
typename T,
bool UseCompare>
285 if (index.row() < 0 || index.row() >= this->rowCount())
290 else {
return this->containerOrFilteredContainer()[index.row()]; }
293 template <
typename T,
bool UseCompare>
299 template <
typename T,
bool UseCompare>
303 return m_containerFiltered;
306 template <
typename T,
bool UseCompare>
310 if (this->hasFilter())
312 if (filtered) { *filtered =
true; }
313 return m_containerFiltered;
317 if (filtered) { *filtered =
false; }
322 template <
typename T,
bool UseCompare>
325 beginInsertRows(QModelIndex(), m_container.size(), m_container.size());
326 m_container.push_back(
object);
329 if (this->hasFilter())
332 this->beginResetModel();
333 this->updateFilteredContainer();
334 this->endResetModel();
336 this->emitModelDataChanged();
339 template <
typename T,
bool UseCompare>
342 beginInsertRows(QModelIndex(), m_container.size(), m_container.size());
343 m_container.push_back(container);
346 if (this->hasFilter())
349 this->beginResetModel();
350 this->updateFilteredContainer();
351 this->endResetModel();
353 this->emitModelDataChanged();
356 template <
typename T,
bool UseCompare>
359 beginInsertRows(QModelIndex(), 0, 0);
360 m_container.insert(m_container.begin(),
object);
363 if (this->hasFilter())
366 this->beginResetModel();
367 this->updateFilteredContainer();
368 this->endResetModel();
370 this->emitModelDataChanged();
373 template <
typename T,
bool UseCompare>
376 if (container.isEmpty()) {
return; }
377 beginInsertRows(QModelIndex(), 0, 0);
378 m_container.push_back(container);
381 if (this->hasFilter())
384 this->beginResetModel();
385 this->updateFilteredContainer();
386 this->endResetModel();
388 this->emitModelDataChanged();
391 template <
typename T,
bool UseCompare>
394 const int oldSize = m_container.size();
395 beginRemoveRows(QModelIndex(), 0, 0);
396 m_container.remove(
object);
398 const int newSize = m_container.size();
399 if (oldSize != newSize)
401 this->emitModelDataChanged();
402 if (this->hasFilter())
404 this->beginResetModel();
405 this->updateFilteredContainer();
406 this->endResetModel();
411 template <
typename T,
bool UseCompare>
416 m_containerFiltered.clear();
418 this->emitModelDataChanged();
421 template <
typename T,
bool UseCompare>
424 return m_container.isEmpty();
427 template <
typename T,
bool UseCompare>
430 if (this->hasFilter()) { m_containerFiltered = m_filter->filter(m_container); }
431 else { m_containerFiltered.clear(); }
434 template <
typename T,
bool UseCompare>
437 const int n = this->containerOrFilteredContainer().size();
438 emit this->modelDataChanged(n, this->hasFilter());
439 emit this->changed();
442 template <
typename T,
bool UseCompare>
444 const QVector<int> &roles)
448 Q_UNUSED(bottomRight)
450 this->emitModelDataChanged();
453 template <
typename T,
bool UseCompare>
456 const int n = this->containerOrFilteredContainer().size();
457 emit this->changedDigest();
458 emit this->modelDataChangedDigest(n, this->hasFilter());
461 template <
typename T,
bool UseCompare>
469 template <
typename T,
bool UseCompare>
472 this->sort(this->getSortColumn(), this->getSortOrder());
475 template <
typename T,
bool UseCompare>
479 this->updateContainerMaybeAsync(m_container,
true);
482 template <
typename T,
bool UseCompare>
485 if (column == m_sortColumn && order == m_sortOrder) {
return; }
488 m_sortColumn = column;
490 if (m_container.size() < 2)
496 this->updateContainerMaybeAsync(m_container,
true);
499 template <
typename T,
bool UseCompare>
502 if (this->rowCount() <= maxNumber) {
return; }
508 container.truncate(maxNumber);
509 this->updateContainerMaybeAsync(container,
false);
512 template <
typename T,
bool UseCompare>
515 Qt::SortOrder order)
const
517 if (m_modelDestroyed) {
return container; }
518 if (container.size() < 2 || !m_columns.isSortable(column))
524 const CPropertyIndex propertyIndex = m_columns.columnToSortPropertyIndex(column);
525 Q_ASSERT(!propertyIndex.
isEmpty());
532 const auto tieBreakersCopy =
534 const std::integral_constant<bool, UseCompare> marker {};
536 return Private::compareForModelSort<ObjectType>(a, b, order, propertyIndex, tieBreakersCopy, marker);
539 return container.sorted(p);
542 template <
typename T,
bool UseCompare>
545 QMimeData *mimeData =
new QMimeData();
546 if (indexes.isEmpty()) {
return mimeData; }
552 for (
const QModelIndex &index : indexes)
554 if (!index.isValid()) {
continue; }
555 const int r = index.row();
556 if (rows.contains(r)) {
continue; }
557 container.push_back(this->at(index));
562 const QJsonDocument containerJson(CVariant::fromValue(container).toJson());
563 const QString jsonString(containerJson.toJson(QJsonDocument::Compact));
569 template <
typename T,
bool UseCompare>
573 CVariant::fromValue(selectedOnly && m_selectionModel ? m_selectionModel->selectedObjects() : container());
577 template <
typename T,
bool UseCompare>
581 CVariant::fromValue(selectedOnly && m_selectionModel ? m_selectionModel->selectedObjects() : container());
585 template <
typename T,
bool UseCompare>
static const QString & swiftJsonDragAndDropMimeType()
Metatype.
const ContainerType & container() const
Used container data.
virtual void clear()
Clear the list.
virtual const ObjectType & at(const QModelIndex &index) const
Object at row position.
QMimeData * mimeData(const QModelIndexList &indexes) const final
void sort()
Sort by given sort order.
virtual bool isEmpty() const
Empty?
void removeFilter()
Remove filter.
QVariant data(const QModelIndex &index, int role) const
bool dropMimeData(const QMimeData *mimeData, Qt::DropAction action, int row, int column, const QModelIndex &parent) final
virtual void push_back(const ObjectType &object)
Similar to ContainerType::push_back.
bool hasFilter() const
Filter available.
void takeFilterOwnership(std::unique_ptr< IModelFilter< ContainerType >> &filter)
Set the filter.
QString toJsonString(QJsonDocument::JsonFormat format=QJsonDocument::Indented, bool selectedOnly=false) const
Convert to JSON string.
virtual void insert(const ObjectType &object)
Similar to ContainerType::insert here inserts at first position.
void onDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomLeft, const QVector< int > &roles)
Feedback when QStandardItemModel::dataChanged was called.
bool isOrderable() const
Orderable, normally use a container swift::misc::IOrderableList.
virtual swift::misc::CWorker * updateAsync(const ContainerType &container, bool sort=true)
Asynchronous update.
void truncate(int maxNumber, bool forceSort=false)
Truncate to given number.
void onChangedDigest()
Feedback when QStandardItemModel::dataChanged was called.
T ContainerType
Container type.
typename T::value_type ObjectType
Container element type.
virtual void remove(const ObjectType &object)
Remove object.
virtual bool isValidIndex(const QModelIndex &index) const
Valid index (in range)
void updateFilteredContainer()
Update filtered container.
int rowCount(const QModelIndex &parentIndex=QModelIndex()) const final
QJsonObject toJson(bool selectedOnly=false) const
Convert to JSON.
ContainerType sortContainerByColumn(const ContainerType &container, int column, Qt::SortOrder order) const
Sort container by given column / order. This is used by sort() but als for asynchronous updates in th...
bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole) final
const ContainerType & containerOrFilteredContainer(bool *filtered=nullptr) const
Full container or cached filtered container as approproiate.
const ContainerType & containerFiltered() const
Used container data.
virtual void moveItems(const ContainerType &items, int position)
Move items to position, normally called from dropMimeData.
void emitModelDataChanged()
Model changed.
void resort()
Sort by given sort order.
bool canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) const final
virtual int update(const ContainerType &container, bool sort=true)
Update by new container.
virtual void updateContainerMaybeAsync(const ContainerType &container, bool sort=true)
Update by new container.
bool setInContainer(const QModelIndex &index, const ObjectType &obj)
Simple set of data in container, using class is responsible for firing signals etc.
Non templated base class, allows Q_OBJECT and signals to be used.
void asyncUpdateFinished()
Asynchronous update finished.
bool isEmpty() const
Empty?
CastType frontCasted() const
First element casted to given type, usually the PropertIndex enum.
size_type size() const
Returns number of elements in the sequence.
bool isEmpty() const
Synonym for empty.
Wrapper around QVariant which provides transparent access to CValueObject methods of the contained ob...
const QVariant & getQVariant() const
Return the internal QVariant.
QJsonObject toJson() const
Cast to JSON object.
QString toJsonString(QJsonDocument::JsonFormat format=QJsonDocument::Indented) const
Convenience function JSON as string.
void then(T *context, F functor)
Connects to a functor or method which will be called when the task is finished.
Class for doing some arbitrary parcel of work in its own thread.
void thenWithResult(F functor)
Connects to a functor to which will be passed the result when the task is finished.
Value object encapsulating a list of voice rooms.
Models to be used with views, mainly QTableView.
Free functions in swift::misc.