refs #368, filter for views

This commit is contained in:
Klaus Basan
2015-01-18 23:00:01 +01:00
parent f8464a6b03
commit 23d3ea3ec5
19 changed files with 974 additions and 120 deletions

View File

@@ -0,0 +1,50 @@
/* Copyright (C) 2013
* swift project Community / Contributors
*
* This file is part of swift Project. It is subject to the license terms in the LICENSE file found in the top-level
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
* including this file, may be copied, modified, propagated, or distributed except according to the terms
* contained in the LICENSE file.
*/
#include "aircraftmodelfilter.h"
#include "blackmisc/simulation/aircraftmodel.h"
using namespace BlackMisc::Simulation;
namespace BlackGui
{
namespace Models
{
CAircraftModelFilter::CAircraftModelFilter(const QString &modelString, const QString &description) :
m_model(modelString.trimmed()), m_description(description.trimmed())
{ }
BlackMisc::Simulation::CAircraftModelList CAircraftModelFilter::filter(const CAircraftModelList &inContainer) const
{
if (!this->isValid()) { return inContainer; }
CAircraftModelList outContainer;
for (const CAircraftModel &model : inContainer)
{
if (!this->m_model.isEmpty())
{
if (!this->stringMatchesFilterExpression(model.getModelString(), this->m_model)) { continue; }
}
if (!this->m_description.isEmpty())
{
if (!this->stringMatchesFilterExpression(model.getDescription(), this->m_description)) { continue; }
}
outContainer.push_back(model);
}
return outContainer;
}
bool CAircraftModelFilter::isValid() const
{
return !(this->m_model.isEmpty() && this->m_description.isEmpty());
}
} // namespace
} // namespace

View File

@@ -0,0 +1,46 @@
/* Copyright (C) 2013
* swift project Community / Contributors
*
* This file is part of swift Project. It is subject to the license terms in the LICENSE file found in the top-level
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
* including this file, may be copied, modified, propagated, or distributed except according to the terms
* contained in the LICENSE file.
*/
//! \file
#ifndef BLACKGUI_AIRCRAFTMODELFILTER_H
#define BLACKGUI_AIRCRAFTMODELFILTER_H
#include "listmodelfilter.h"
#include "blackmisc/simulation/aircraftmodellist.h"
namespace BlackGui
{
namespace Models
{
//! Filter for aircraft models
class CAircraftModelFilter : public IModelFilter<BlackMisc::Simulation::CAircraftModelList>
{
public:
//! Constructor
CAircraftModelFilter(const QString &modelString, const QString &description);
//! \copydoc IModelFilter::filter
virtual BlackMisc::Simulation::CAircraftModelList filter(const BlackMisc::Simulation::CAircraftModelList &inContainer) const override;
//! \copydoc IModelFilter::isValid
virtual bool isValid() const override;
private:
QString m_model;
QString m_description;
};
} // namespace
} // namespace
#endif // guard

View File

@@ -8,6 +8,7 @@
*/
#include "listmodelbase.h"
#include "blackmisc/simulation/aircraftmodellist.h"
#include "blackmisc/namevariantpairlist.h"
#include "blackmisc/statusmessagelist.h"
#include "blackmisc/avatcstationlist.h"
@@ -16,11 +17,14 @@
#include "blackmisc/nwserverlist.h"
#include "blackmisc/nwuserlist.h"
#include "blackmisc/nwclientlist.h"
#include "blackmisc/nwaircraftmodellist.h"
#include "blackmisc/nwaircraftmappinglist.h"
#include "blackmisc/setkeyboardhotkeylist.h"
#include "blackmisc/simulation/simulatedaircraftlist.h"
#include "blackmisc/variant.h"
#include "blackmisc/blackmiscfreefunctions.h"
using namespace BlackMisc;
namespace BlackGui
{
namespace Models
@@ -28,8 +32,9 @@ namespace BlackGui
/*
* Column count
*/
int CListModelBaseNonTemplate::columnCount(const QModelIndex & /** modelIndex **/) const
int CListModelBaseNonTemplate::columnCount(const QModelIndex &modelIndex) const
{
Q_UNUSED(modelIndex);
int c = this->m_columns.size();
return c;
}
@@ -39,20 +44,20 @@ namespace BlackGui
*/
QVariant CListModelBaseNonTemplate::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal)
if (orientation != Qt::Horizontal) { return QVariant(); }
bool handled = (role == Qt::DisplayRole || role == Qt::ToolTipRole || role == Qt::InitialSortOrderRole);
if (!handled) {return QVariant();}
if (section < 0 || section >= this->m_columns.size()) { return QVariant(); }
if (role == Qt::DisplayRole)
{
if (role == Qt::DisplayRole)
{
if (section < 0 || section >= this->m_columns.size()) { return QVariant(); }
QString header = this->m_columns.at(section).getColumnName(false);
return QVariant(header);
}
else if (role == Qt::ToolTipRole)
{
if (section < 0 || section >= this->m_columns.size()) { return QVariant(); }
QString header = this->m_columns.at(section).getColumnToolTip(false);
return header.isEmpty() ? QVariant() : QVariant(header);
}
QString header = this->m_columns.at(section).getColumnName(false);
return QVariant(header);
}
else if (role == Qt::ToolTipRole)
{
QString header = this->m_columns.at(section).getColumnToolTip(false);
return header.isEmpty() ? QVariant() : QVariant(header);
}
return QVariant();
}
@@ -65,33 +70,83 @@ namespace BlackGui
return this->m_columns.columnToPropertyIndex(column);
}
/*
* To column
*/
int CListModelBaseNonTemplate::propertyIndexToColumn(const CPropertyIndex &propertyIndex) const
{
return m_columns.propertyIndexToColumn(propertyIndex);
}
/*
* Property index
*/
BlackMisc::CPropertyIndex CListModelBaseNonTemplate::modelIndexToPropertyIndex(const QModelIndex &index) const
{
return this->columnToPropertyIndex(index.column());
}
/*
* Sort column
*/
void CListModelBaseNonTemplate::setSortColumnByPropertyIndex(const BlackMisc::CPropertyIndex &propertyIndex)
{
this->m_sortedColumn = this->m_columns.propertyIndexToColumn(propertyIndex);
}
/*
* Sort column?
*/
bool CListModelBaseNonTemplate::hasValidSortColumn() const
{
return this->m_sortedColumn >= 0 && this->m_sortedColumn < this->m_columns.size();
if (!(this->m_sortedColumn >= 0 && this->m_sortedColumn < this->m_columns.size())) { return false; }
return this->m_columns.isSortable(this->m_sortedColumn);
}
/*
* Make editable
* Flags
*/
Qt::ItemFlags CListModelBaseNonTemplate::flags(const QModelIndex &index) const
{
Qt::ItemFlags f = QAbstractListModel::flags(index);
if (this->m_columns.isEditable(index))
return f | Qt::ItemIsEditable;
else
return f;
if (!index.isValid()) { return f; }
bool editable = this->m_columns.isEditable(index);
f = editable ? (f | Qt::ItemIsEditable) : (f ^ Qt::ItemIsEditable);
const CDefaultFormatter *formatter = this->m_columns.getFormatter(index);
if (formatter)
{
return formatter->flags(f, editable);
}
// fallback behaviour with no formatter
return f;
}
/*
* Translation context
*/
const QString &CListModelBaseNonTemplate::getTranslationContext() const
{
return m_columns.getTranslationContext();
}
/*
* Update
*/
int CListModelBaseNonTemplate::ps_updateContainer(const CVariant &variant, bool sort)
{
return this->performUpdateContainer(variant, sort);
}
/*
* Row count
*/
template <typename ObjectType, typename ContainerType>
int CListModelBase<ObjectType, ContainerType>::rowCount(const QModelIndex & /** parent */) const
int CListModelBase<ObjectType, ContainerType>::rowCount(const QModelIndex &parentIndex) const
{
return this->m_container.size();
Q_UNUSED(parentIndex);
return this->getContainerOrFilteredContainer().size();
}
/*
@@ -100,8 +155,8 @@ namespace BlackGui
template <typename ObjectType, typename ContainerType>
bool CListModelBase<ObjectType, ContainerType>::isValidIndex(const QModelIndex &index) const
{
if (!index.isValid()) return false;
return (index.row() >= 0 && index.row() < this->m_container.size() &&
if (!index.isValid()) { return false; }
return (index.row() >= 0 && index.row() < this->rowCount(index) &&
index.column() >= 0 && index.column() < this->columnCount(index));
}
@@ -109,7 +164,7 @@ namespace BlackGui
* Data
*/
template <typename ObjectType, typename ContainerType>
QVariant CListModelBase<ObjectType, ContainerType>::data(const QModelIndex &index, int role) const
QVariant CListModelBase<ObjectType, ContainerType>::data(const QModelIndex &index, int role) const
{
// check / init
if (!this->isValidIndex(index)) { return QVariant(); }
@@ -118,11 +173,46 @@ namespace BlackGui
if (!formatter) { return QVariant(); }
//! Formatted data
ObjectType obj = this->m_container[index.row()];
ObjectType obj = this->getContainerOrFilteredContainer()[index.row()];
BlackMisc::CPropertyIndex propertyIndex = this->columnToPropertyIndex(index.column());
return formatter->data(role, obj.propertyByIndex(propertyIndex)).toQVariant();
}
/*
* Set data
*/
template <typename ObjectType, typename ContainerType>
bool CListModelBase<ObjectType, ContainerType>::setData(const QModelIndex &index, const QVariant &value, int role)
{
Qt::ItemDataRole dataRole = static_cast<Qt::ItemDataRole>(role);
if (!(dataRole == Qt::UserRole || dataRole == Qt::EditRole)) { return false; }
// check / init
if (!this->isValidIndex(index)) { return false; }
if (!this->m_columns.isEditable(index)) { return false; }
const CDefaultFormatter *formatter = this->m_columns.getFormatter(index);
Q_ASSERT(formatter);
if (!formatter) { return false; }
ObjectType obj = this->m_container[index.row()];
ObjectType currentObject(obj);
BlackMisc::CPropertyIndex propertyIndex = this->columnToPropertyIndex(index.column());
obj.setPropertyByIndex(value, propertyIndex);
if (obj != currentObject)
{
QModelIndex topLeft = index.sibling(index.row(), 0);
QModelIndex bottomRight = index.sibling(index.row(), this->columnCount() - 1);
this->m_container[index.row()] = obj;
const CVariant co = CVariant::from(obj);
emit objectChanged(co, propertyIndex);
emit dataChanged(topLeft, bottomRight);
this->updateFilteredContainer();
return true;
}
return false;
}
/*
* Update
*/
@@ -135,15 +225,17 @@ namespace BlackGui
bool performSort = sort && container.size() > 1 && this->hasValidSortColumn();
if (performSort)
{
sortedContainer = this->sortContainerByColumn(container, this->getSortColumn(), this->m_sortOrder);
int sortColumn = this->getSortColumn();
sortedContainer = this->sortContainerByColumn(container, sortColumn, this->m_sortOrder);
}
this->beginResetModel();
this->m_container = performSort ? sortedContainer : container;
this->updateFilteredContainer();
this->endResetModel();
int newSize = this->m_container.size();
if (oldSize != newSize) { rowCountChanged(newSize); }
if (oldSize != newSize) { this->emitRowCountChanged(); }
return newSize;
}
@@ -153,7 +245,7 @@ namespace BlackGui
template <typename ObjectType, typename ContainerType>
void CListModelBase<ObjectType, ContainerType>::update(const QModelIndex &index, const ObjectType &object)
{
if (index.row() >= this->m_container.size()) return;
if (index.row() >= this->m_container.size()) { return; }
this->m_container[index.row()] = object;
QModelIndex i1 = index.sibling(index.row(), 0);
@@ -161,6 +253,12 @@ namespace BlackGui
emit this->dataChanged(i1, i2); // which range has been changed
}
template <typename ObjectType, typename ContainerType>
void CListModelBase<ObjectType, ContainerType>::update(int rowIndex, const ObjectType &object)
{
this->update(this->index(rowIndex), object);
}
/*
* Async update
*/
@@ -172,8 +270,8 @@ namespace BlackGui
BlackMisc::CWorker *worker = BlackMisc::CWorker::fromTask(this, "ModelSort", [this, container, sort, sortColumn, sortOrder]()
{
ContainerType sortedContainer = this->sortContainerByColumn(container, sortColumn, sortOrder);
QMetaObject::invokeMethod(this, "updateContainer",
Q_ARG(BlackMisc::CVariant, sortedContainer.toCVariant()), Q_ARG(bool, false));
QMetaObject::invokeMethod(this, "ps_updateContainer",
Q_ARG(BlackMisc::CVariant, sortedContainer.toCVariant()), Q_ARG(bool, false));
});
worker->then(this, &CListModelBase::asyncUpdateFinished);
return worker;
@@ -196,23 +294,76 @@ namespace BlackGui
}
}
/*
* Filter
*/
template <typename ObjectType, typename ContainerType>
bool CListModelBase<ObjectType, ContainerType>::hasFilter() const
{
return m_filter ? true : false;
}
/*
* Remove filter
*/
template <typename ObjectType, typename ContainerType>
void CListModelBase<ObjectType, ContainerType>::removeFilter()
{
if (!this->hasFilter()) { return; }
this->m_filter.reset(nullptr);
this->beginResetModel();
this->updateFilteredContainer();
this->endResetModel();
this->emitRowCountChanged();
}
/*
* Set filter
*/
template <typename ObjectType, typename ContainerType>
void CListModelBase<ObjectType, ContainerType>::setFilter(std::unique_ptr<IModelFilter<ContainerType> > &filter)
{
if (!filter) { this->removeFilter(); return; } // empty filter
if (filter->isValid())
{
this->m_filter = std::move(filter);
this->beginResetModel();
this->updateFilteredContainer();
this->endResetModel();
this->emitRowCountChanged();
}
else
{
this->removeFilter();
}
}
/*
* At
*/
template <typename ObjectType, typename ContainerType>
const ObjectType &CListModelBase<ObjectType, ContainerType>::at(const QModelIndex &index) const
{
if (index.row() < 0 || index.row() >= this->m_container.size())
if (index.row() < 0 || index.row() >= this->rowCount())
{
static const ObjectType def {}; // default object
return def;
}
else
{
return this->m_container[index.row()];
return this->getContainerOrFilteredContainer()[index.row()];
}
}
/*
* Container
*/
template <typename ObjectType, typename ContainerType>
const ContainerType &CListModelBase<ObjectType, ContainerType>::getContainer() const
{
return this->m_container;
}
/*
* Push back
*/
@@ -222,11 +373,12 @@ namespace BlackGui
beginInsertRows(QModelIndex(), this->m_container.size(), this->m_container.size());
this->m_container.push_back(object);
endInsertRows();
emit rowCountChanged(this->m_container.size());
this->updateFilteredContainer();
this->emitRowCountChanged();
}
/*
* Push back
* insert
*/
template <typename ObjectType, typename ContainerType>
void CListModelBase<ObjectType, ContainerType>::insert(const ObjectType &object)
@@ -234,8 +386,14 @@ namespace BlackGui
beginInsertRows(QModelIndex(), 0, 0);
this->m_container.insert(this->m_container.begin(), object);
endInsertRows();
int newSize = this->m_container.size();
emit rowCountChanged(newSize);
if (this->hasFilter())
{
this->beginResetModel();
this->updateFilteredContainer();
this->endResetModel();
}
this->emitRowCountChanged();
}
/*
@@ -249,42 +407,81 @@ namespace BlackGui
this->m_container.remove(object);
endRemoveRows();
int newSize = this->m_container.size();
if (oldSize != newSize) { emit rowCountChanged(newSize); }
if (oldSize != newSize)
{
this->emitRowCountChanged();
if (this->hasFilter())
{
this->beginResetModel();
this->updateFilteredContainer();
this->endResetModel();
}
}
}
/*
* Clear
*/
template <typename ObjectType, typename ContainerType> void CListModelBase<ObjectType, ContainerType>::clear()
template <typename ObjectType, typename ContainerType>
void CListModelBase<ObjectType, ContainerType>::clear()
{
int oldSize = this->m_container.size();
beginResetModel();
this->m_container.clear();
this->m_containerFiltered.clear();
endResetModel();
if (oldSize > 0) { emit rowCountChanged(0);}
this->emitRowCountChanged();
}
/*
* Update on container
*/
template <typename ObjectType, typename ContainerType> int CListModelBase<ObjectType, ContainerType>::performUpdateContainer(const BlackMisc::CVariant &variant, bool sort)
template <typename ObjectType, typename ContainerType>
int CListModelBase<ObjectType, ContainerType>::performUpdateContainer(const BlackMisc::CVariant &variant, bool sort)
{
ContainerType c;
c.convertFromCVariant(variant);
return this->update(c, sort);
}
template <typename ObjectType, typename ContainerType>
const ContainerType &CListModelBase<ObjectType, ContainerType>::getContainerOrFilteredContainer() const
{
if (!this->hasFilter()) { return this->m_container; }
return m_containerFiltered;
}
template <typename ObjectType, typename ContainerType>
void CListModelBase<ObjectType, ContainerType>::updateFilteredContainer()
{
if (this->hasFilter())
{
this->m_containerFiltered = this->m_filter->filter(this->m_container);
}
else
{
this->m_containerFiltered.clear();
}
}
template <typename ObjectType, typename ContainerType>
void CListModelBase<ObjectType, ContainerType>::emitRowCountChanged()
{
int n = this->getContainerOrFilteredContainer().size();
emit this->rowCountChanged(n, this->hasFilter());
}
/*
* Sort requested by abstract model
*/
template <typename ObjectType, typename ContainerType> void CListModelBase<ObjectType, ContainerType>::sort(int column, Qt::SortOrder order)
template <typename ObjectType, typename ContainerType>
void CListModelBase<ObjectType, ContainerType>::sort(int column, Qt::SortOrder order)
{
if (column == this->m_sortedColumn && order == this->m_sortOrder) { return; }
// new order
this->m_sortedColumn = column;
this->m_sortOrder = order;
if (this->m_container.size() < 2) return; // nothing to do
if (this->m_container.size() < 2) { return; } // nothing to do
// sort the values
this->updateContainerMaybeAsync(this->m_container, true);
@@ -293,14 +490,15 @@ namespace BlackGui
/*
* Sort list
*/
template <typename ObjectType, typename ContainerType> ContainerType CListModelBase<ObjectType, ContainerType>::sortContainerByColumn(const ContainerType &container, int column, Qt::SortOrder order) const
template <typename ObjectType, typename ContainerType>
ContainerType CListModelBase<ObjectType, ContainerType>::sortContainerByColumn(const ContainerType &container, int column, Qt::SortOrder order) const
{
if (container.size() < 2) return container; // nothing to do
if (container.size() < 2 || !this->m_columns.isSortable(column)) { return container; } // nothing to do
// this is the only part not really thread safe, but columns do not change so far
BlackMisc::CPropertyIndex propertyIndex = this->m_columns.columnToPropertyIndex(column);
BlackMisc::CPropertyIndex propertyIndex = this->m_columns.columnToSortPropertyIndex(column);
Q_ASSERT(!propertyIndex.isEmpty());
if (propertyIndex.isEmpty()) return container; // at release build do nothing
if (propertyIndex.isEmpty()) { return container; } // at release build do nothing
// sort the values
const auto p = [ = ](const ObjectType & a, const ObjectType & b) -> bool
@@ -310,11 +508,7 @@ namespace BlackGui
return (order == Qt::AscendingOrder) ? (aQv < bQv) : (bQv < aQv);
};
// KWB: qDebug() will be removed soon
QTime t;
t.start();
const ContainerType sorted = container.sorted(p);
qDebug() << "Sort" << this->objectName() << "column" << column << "index:" << propertyIndex.toQString() << "ms:" << t.elapsed() << "thread:" << QThread::currentThreadId();
return sorted;
}
@@ -328,8 +522,9 @@ namespace BlackGui
template class CListModelBase<BlackMisc::Network::CServer, BlackMisc::Network::CServerList>;
template class CListModelBase<BlackMisc::Network::CUser, BlackMisc::Network::CUserList>;
template class CListModelBase<BlackMisc::Network::CClient, BlackMisc::Network::CClientList>;
template class CListModelBase<BlackMisc::Network::CAircraftModel, BlackMisc::Network::CAircraftModelList>;
template class CListModelBase<BlackMisc::Simulation::CAircraftModel, BlackMisc::Simulation::CAircraftModelList>;
template class CListModelBase<BlackMisc::Network::CAircraftMapping, BlackMisc::Network::CAircraftMappingList>;
template class CListModelBase<BlackMisc::Simulation::CSimulatedAircraft, BlackMisc::Simulation::CSimulatedAircraftList>;
template class CListModelBase<BlackMisc::Settings::CSettingKeyboardHotkey, BlackMisc::Settings::CSettingKeyboardHotkeyList>;
} // namespace

View File

@@ -13,10 +13,13 @@
#define BLACKGUI_LISTMODELBASE_H
#include "blackgui/models/columns.h"
#include "blackgui/models/listmodelfilter.h"
#include "blackmisc/worker.h"
#include "blackmisc/propertyindex.h"
#include <QAbstractItemModel>
#include <QThread>
#include <memory>
#include <iostream>
namespace BlackGui
{
@@ -35,7 +38,7 @@ namespace BlackGui
virtual ~CListModelBaseNonTemplate() {}
//! \copydoc QAbstractListModel::columnCount()
virtual int columnCount(const QModelIndex &modelIndex) const override;
virtual int columnCount(const QModelIndex &modelIndex = QModelIndex()) const override;
//! \copydoc QAbstractItemModel::headerData()
virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
@@ -43,11 +46,11 @@ namespace BlackGui
//! Column to property index
virtual BlackMisc::CPropertyIndex columnToPropertyIndex(int column) const;
//! Property index to column number
virtual int propertyIndexToColumn(const BlackMisc::CPropertyIndex &propertyIndex) const;
//! Index to property index
virtual BlackMisc::CPropertyIndex modelIndexToPropertyIndex(const QModelIndex &index) const
{
return this->columnToPropertyIndex(index.column());
}
virtual BlackMisc::CPropertyIndex modelIndexToPropertyIndex(const QModelIndex &index) const;
//! Set sort column
virtual void setSortColumn(int column) { this->m_sortedColumn = column; }
@@ -56,10 +59,7 @@ namespace BlackGui
* Set column for sorting
* \param propertyIndex index of column to be sorted
*/
virtual void setSortColumnByPropertyIndex(const BlackMisc::CPropertyIndex &propertyIndex)
{
this->m_sortedColumn = this->m_columns.propertyIndexToColumn(propertyIndex);
}
virtual void setSortColumnByPropertyIndex(const BlackMisc::CPropertyIndex &propertyIndex);
//! Get sort column property index
virtual int getSortColumn() const { return this->m_sortedColumn; }
@@ -74,26 +74,23 @@ namespace BlackGui
Qt::ItemFlags flags(const QModelIndex &index) const override;
//! Translation context
virtual const QString &getTranslationContext() const
{
return m_columns.getTranslationContext();
}
virtual const QString &getTranslationContext() const;
signals:
//! Asynchronous update finished
void asyncUpdateFinished();
//! Number of elements changed
void rowCountChanged(int count);
void rowCountChanged(int count, bool withFilter);
//! Template free information, that object changed
void objectChanged(const BlackMisc::CVariant &object, const BlackMisc::CPropertyIndex &changedIndex);
protected slots:
//! Helper method with template free signature
//! \param variant container is transferred in variant
//! \param sort
int updateContainer(const BlackMisc::CVariant &variant, bool sort)
{
return this->performUpdateContainer(variant, sort);
}
int ps_updateContainer(const BlackMisc::CVariant &variant, bool sort);
protected:
/*!
@@ -117,8 +114,7 @@ namespace BlackGui
};
//! List model
template <typename ObjectType, typename ContainerType> class CListModelBase :
public CListModelBaseNonTemplate
template <typename ObjectType, typename ContainerType> class CListModelBase : public CListModelBaseNonTemplate
{
public:
@@ -129,13 +125,17 @@ namespace BlackGui
virtual bool isValidIndex(const QModelIndex &index) const;
//! Used container data
virtual const ContainerType &getContainer() const { return this->m_container; }
virtual const ContainerType &getContainer() const;
//! \copydoc QAbstractListModel::data()
virtual QVariant data(const QModelIndex &index, int role) const override;
//! \copydoc QAbstractListModel::setData()
//! \sa CListModelBaseNonTemplate::flags
virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
//! \copydoc QAbstractListModel::rowCount()
virtual int rowCount(const QModelIndex &index = QModelIndex()) const override;
virtual int rowCount(const QModelIndex &parentIndex = QModelIndex()) const override;
//! Update by new container
//! \remarks a sorting is performed only if a valid sort column is set
@@ -151,10 +151,7 @@ namespace BlackGui
virtual void update(const QModelIndex &index, const ObjectType &object);
//! Update single element
virtual void update(int rowIndex, const ObjectType &object)
{
this->update(this->index(rowIndex), object);
}
virtual void update(int rowIndex, const ObjectType &object);
//! Object at row position
virtual const ObjectType &at(const QModelIndex &index) const;
@@ -186,15 +183,25 @@ namespace BlackGui
int removeIf(K0 k0, V0 v0, KeysValues... keysValues)
{
int c = m_container.removeIf(BlackMisc::Predicates::MemberEqual(k0, v0, keysValues...));
if (c > 0) { emit rowCountChanged(this->rowCount());}
if (c > 0) { this->emitRowCountChanged();}
this->updateFilteredContainer();
return c;
}
//! Clear the list
virtual void clear();
//! Filter available
bool hasFilter() const;
//! Remove filter
void removeFilter();
//! Set the filter
void setFilter(std::unique_ptr<IModelFilter<ContainerType> > &filter);
protected:
ContainerType m_container; //!< used container
std::unique_ptr<IModelFilter<ContainerType> > m_filter; //!< Used filter
/*!
* Constructor
@@ -207,6 +214,18 @@ namespace BlackGui
//! \copydoc CModelBaseNonTemplate::performUpdateContainer
virtual int performUpdateContainer(const BlackMisc::CVariant &variant, bool sort) override;
//! Full container or cached filtered container as approproiate
const ContainerType &getContainerOrFilteredContainer() const;
//! Update filtered container
void updateFilteredContainer();
//! Row count changed
void emitRowCountChanged();
ContainerType m_container; //!< used container
ContainerType m_containerFiltered; //!< cache for filtered container data
};
} // namespace

View File

@@ -0,0 +1,68 @@
/* Copyright (C) 2015
* swift project Community / Contributors
*
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
* including this file, may be copied, modified, propagated, or distributed except according to the terms
* contained in the LICENSE file.
*/
#include "listmodelfilter.h"
#include "blackmisc/simulation/aircraftmodellist.h"
namespace BlackGui
{
namespace Models
{
template<class ContainerType>
bool IModelFilter<ContainerType>::stringMatchesFilterExpression(const QString &value, const QString &filter, Qt::CaseSensitivity cs) const
{
QString v = value.trimmed();
QString f = filter.trimmed();
if (v.isEmpty() && f.isEmpty()) { return true; }
if (v.isEmpty()) { return false; }
// no wildcard, just string matching
if (!filter.contains('*'))
{
return (v.indexOf(f, 0, cs) == 0) &&
(v.length() == f.length());
}
const QString filterNoWildcard = stripWildcard(f);
// included?
if (f.startsWith('*') && f.endsWith('*'))
{
return v.contains(filterNoWildcard, cs);
}
// starting with
if (f.startsWith('*'))
{
return v.endsWith(filterNoWildcard, cs);
}
if (f.endsWith('*'))
{
return v.startsWith(filterNoWildcard, cs);
}
// should never happen
Q_ASSERT(false);
return false;
}
template<class ContainerType>
QString IModelFilter<ContainerType>::stripWildcard(const QString &value) const
{
QString sw(value);
return sw.remove('*');
}
// Forward instantiations
template class IModelFilter<BlackMisc::Simulation::CAircraftModelList>;
} // namespace
} // namespace

View File

@@ -0,0 +1,47 @@
/* Copyright (C) 2015
* swift project Community / Contributors
*
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
* including this file, may be copied, modified, propagated, or distributed except according to the terms
* contained in the LICENSE file.
*/
//! \file
#ifndef BLACKGUI_LISTMODELFILTER_H
#define BLACKGUI_LISTMODELFILTER_H
#include <QString>
namespace BlackGui
{
namespace Models
{
//! Model filter interface
template<class ContainerType> class IModelFilter
{
public:
//! Destructor
virtual ~IModelFilter() {}
//! Used container data
virtual ContainerType filter(const ContainerType &container) const = 0;
//! Anything to do?
virtual bool isValid() const = 0;
protected:
//! Standard string search supporting wildcard at begin and end: "*xyz", "abc*"
bool stringMatchesFilterExpression(const QString &value, const QString &filter, Qt::CaseSensitivity cs = Qt::CaseInsensitive) const;
//! Remove the * wildcards
QString stripWildcard(const QString &value) const;
};
} // namespace
} // namespace
#endif // guard