refs #641, support for IOrderable in specialized views/models

* menu to order objects per drag and drop
* changed model/views to specialized model/views
This commit is contained in:
Klaus Basan
2016-04-23 02:42:36 +02:00
parent bb6eea6c72
commit 7d43af343e
18 changed files with 435 additions and 161 deletions

View File

@@ -20,7 +20,7 @@ namespace BlackGui
namespace Models
{
CAircraftModelListModel::CAircraftModelListModel(AircraftModelMode mode, QObject *parent) :
CListModelDbObjects("CAircraftModelListModel", parent)
COrderableListModelDbObjects("CAircraftModelListModel", parent)
{
this->setAircraftModelMode(mode);
@@ -60,16 +60,23 @@ namespace BlackGui
this->m_sortOrder = Qt::AscendingOrder;
break;
case OwnModelSet:
// intentional fall thru
this->m_columns.addColumn(CColumn::orderColumn());
case OwnSimulatorModelMapping:
this->m_columns.addColumn(CColumn::standardString("model", CAircraftModel::IndexModelString));
this->m_columns.addColumn(CColumn("DB", "DB metadata", CAircraftModel::IndexDatabaseIcon, new CPixmapFormatter()));
this->m_columns.addColumn(CColumn("mode", "model mode(include, exclude)", CAircraftModel::IndexModelModeAsIcon, new CPixmapFormatter()));
// this->m_columns.addColumn(CColumn::standardValueObject("call", "callsign", CAircraftModel::IndexCallsign));
this->m_columns.addColumn(CColumn::standardString("dist.", "distributor", { CAircraftModel::IndexDistributor, CDistributor::IndexDbStringKey}));
if (mode == OwnModelSet)
{
this->m_columns.addColumn(CColumn::standardString("d#", "distributor order", { CAircraftModel::IndexDistributor, CDistributor::IndexOrderString}));
}
this->m_columns.addColumn(CColumn::standardString("ac", "aircraft ICAO", { CAircraftModel::IndexAircraftIcaoCode, CAircraftIcaoCode::IndexAircraftDesignator}));
this->m_columns.addColumn(CColumn::standardString("fam.", "aircraft family", { CAircraftModel::IndexAircraftIcaoCode, CAircraftIcaoCode::IndexFamily}));
this->m_columns.addColumn(CColumn::standardString("al", "airline ICAO", { CAircraftModel::IndexLivery, CLivery::IndexAirlineIcaoCode, CAirlineIcaoCode::IndexAirlineDesignator}));
// this->m_columns.addColumn(CColumn::standardString("ct", "combined type", { CAircraftModel::IndexIcao, CAircraftIcaoData::IndexCombinedAircraftType}));
this->m_columns.addColumn(CColumn::standardString("description", CAircraftModel::IndexDescription));
this->m_columns.addColumn(CColumn::standardString("filename", CAircraftModel::IndexFileName));
this->m_columns.addColumn(CColumn::standardString("icon", CAircraftModel::IndexIconPath));

View File

@@ -25,7 +25,7 @@ namespace BlackGui
{
//! Aircraft model list model
class BLACKGUI_EXPORT CAircraftModelListModel :
public CListModelDbObjects<BlackMisc::Simulation::CAircraftModel, BlackMisc::Simulation::CAircraftModelList, int, true>
public COrderableListModelDbObjects<BlackMisc::Simulation::CAircraftModel, BlackMisc::Simulation::CAircraftModelList, int, true>
{
public:
//! How to display
@@ -34,6 +34,7 @@ namespace BlackGui
{
NotSet,
OwnSimulatorModel, //!< models existing for my simulator
OwnModelSet, //!< own model set
OwnSimulatorModelMapping, //!< models of my simulator, but in mapping mode
Database, //!< Database entry
VPilotRuleModel, //!< vPilot rule turned into model
@@ -73,11 +74,14 @@ namespace BlackGui
//! \copydoc QAbstractItemModel::data
virtual QVariant data(const QModelIndex &index, int role) const override;
//! \copydoc BlackGui::Models::CListModelBaseNonTemplate::isOrderable
virtual bool isOrderable() const override { return true; }
private:
AircraftModelMode m_mode = NotSet; //!< current mode
bool m_highlightModelStrings = false; //!< highlight in in model strings
QStringList m_highlightStrings; //!< model strings to highlight
QBrush m_highlightColor{Qt::yellow}; //!< how to highlight
AircraftModelMode m_mode = NotSet; //!< current mode
bool m_highlightModelStrings = false; //!< highlight in in model strings
QStringList m_highlightStrings; //!< model strings to highlight
QBrush m_highlightColor{Qt::yellow}; //!< how to highlight
};
} // ns
} // ns

View File

@@ -88,6 +88,11 @@ namespace BlackGui
return CColumn(headerName, toolTip, propertyIndex, new CStringFormatter(alignment));
}
CColumn CColumn::orderColumn(const CPropertyIndex &propertyIndex, int alignment)
{
return CColumn("#", "order", propertyIndex, new CStringFormatter(alignment));
}
// --------------- columns ----------------------------------------------
CColumns::CColumns(const QString &translationContext, QObject *parent) :

View File

@@ -100,6 +100,9 @@ namespace BlackGui
//! Get a standard string object formatted column
static CColumn standardString(const QString &headerName, const QString &toolTip, const BlackMisc::CPropertyIndex &propertyIndex, int alignment = CDefaultFormatter::alignDefault());
//! Get a standard string object formatted column
static CColumn orderColumn(const BlackMisc::CPropertyIndex &propertyIndex = BlackMisc::CPropertyIndex::GlobalIndexIOrderable, int alignment = CDefaultFormatter::alignRightVCenter());
private:
QString m_translationContext;
QString m_columnName;

View File

@@ -18,7 +18,7 @@ namespace BlackGui
namespace Models
{
CDistributorListModel::CDistributorListModel(QObject *parent) :
CListModelDbObjects("ModelDistributorList", parent)
COrderableListModelDbObjects("ModelDistributorList", parent)
{
this->setDistributorMode(Normal);
@@ -36,6 +36,8 @@ namespace BlackGui
this->m_columns.clear();
switch (distributorMode)
{
case NormalWithOrder:
this->m_columns.addColumn(CColumn::orderColumn());
case NotSet:
case Normal:
{

View File

@@ -23,7 +23,7 @@ namespace BlackGui
{
//! Distributor list model
class BLACKGUI_EXPORT CDistributorListModel :
public CListModelDbObjects<BlackMisc::Simulation::CDistributor, BlackMisc::Simulation::CDistributorList, QString, true>
public COrderableListModelDbObjects<BlackMisc::Simulation::CDistributor, BlackMisc::Simulation::CDistributorList, QString, true>
{
public:
//! What kind of stations
@@ -31,6 +31,7 @@ namespace BlackGui
{
NotSet,
Normal,
NormalWithOrder,
Minimal
};
@@ -46,6 +47,9 @@ namespace BlackGui
//! Mode
DistributorMode getDistributorMode() const { return this->m_distributorMode; }
//! \copydoc BlackGui::Models::CListModelBaseNonTemplate::isOrderable
virtual bool isOrderable() const override { return true; }
private:
DistributorMode m_distributorMode = NotSet;
};

View File

@@ -96,6 +96,12 @@ namespace BlackGui
this->m_sortedColumn = this->m_columns.propertyIndexToColumn(propertyIndex);
}
void CListModelBaseNonTemplate::setSorting(const CPropertyIndex &propertyIndex, Qt::SortOrder order)
{
this->setSortColumnByPropertyIndex(propertyIndex);
this->m_sortOrder = order;
}
bool CListModelBaseNonTemplate::hasValidSortColumn() const
{
@@ -107,7 +113,7 @@ namespace BlackGui
{
Qt::ItemFlags f = QStandardItemModel::flags(index);
if (!index.isValid()) { return f; }
bool editable = this->m_columns.isEditable(index);
const bool editable = this->m_columns.isEditable(index);
f = editable ? (f | Qt::ItemIsEditable) : (f & ~Qt::ItemIsEditable);
// flags from formatter
@@ -127,12 +133,12 @@ namespace BlackGui
Qt::DropActions CListModelBaseNonTemplate::supportedDragActions() const
{
return Qt::CopyAction;
return isOrderable() ? Qt::CopyAction | Qt::MoveAction : Qt::CopyAction;
}
Qt::DropActions CListModelBaseNonTemplate::supportedDropActions() const
{
return QStandardItemModel::supportedDropActions();
return this->m_dropActions;
}
QStringList CListModelBaseNonTemplate::mimeTypes() const
@@ -161,8 +167,8 @@ namespace BlackGui
if (columns < 1) { return; }
if (startRowIndex < 0) { startRowIndex = 0; }
if (endRowIndex >= rows) { endRowIndex = rows - 1; }
QModelIndex topLeft(createIndex(startRowIndex, 0));
QModelIndex bottomRight(createIndex(endRowIndex, columns - 1));
const QModelIndex topLeft(createIndex(startRowIndex, 0));
const QModelIndex bottomRight(createIndex(endRowIndex, columns - 1));
emit dataChanged(topLeft, bottomRight);
}
@@ -190,6 +196,38 @@ namespace BlackGui
return this->containerOrFilteredContainer().size();
}
template <typename ObjectType, typename ContainerType, bool UseCompare>
bool CListModelBase<ObjectType, ContainerType, UseCompare>::canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) const
{
Q_UNUSED(action);
Q_UNUSED(row);
Q_UNUSED(column);
Q_UNUSED(parent);
if (!this->isDropAllowed()) { return false; }
if (!this->acceptDrop(data)) { return false; }
return true;
}
template <typename ObjectType, typename ContainerType, bool UseCompare>
bool CListModelBase<ObjectType, ContainerType, UseCompare>::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
{
Q_UNUSED(row);
Q_UNUSED(column);
if (!this->isOrderable() || !this->acceptDrop(data)) { return false; }
const CVariant valueVariant(this->toCVariant(data));
if (valueVariant.isValid())
{
if (action == Qt::MoveAction)
{
const ContainerType container(valueVariant.value<ContainerType>());
if (container.isEmpty()) { return false; }
const int position = parent.row();
this->moveItems(container, position);
}
}
return true;
}
template <typename ObjectType, typename ContainerType, bool UseCompare>
bool CListModelBase<ObjectType, ContainerType, UseCompare>::isValidIndex(const QModelIndex &index) const
{
@@ -370,7 +408,7 @@ namespace BlackGui
{
if (!filter)
{
this->removeFilter(); // clear filter
this->removeFilter(); // clear filter
return;
}
if (filter->isValid())
@@ -528,6 +566,14 @@ namespace BlackGui
emit this->changed();
}
template <typename ObjectType, typename ContainerType, bool UseCompare>
void CListModelBase<ObjectType, ContainerType, UseCompare>::moveItems(const ContainerType &items, int position)
{
// overridden in specialized class
Q_UNUSED(items);
Q_UNUSED(position);
}
template <typename ObjectType, typename ContainerType, bool UseCompare>
void CListModelBase<ObjectType, ContainerType, UseCompare>::sort()
{
@@ -630,6 +676,12 @@ namespace BlackGui
return container().toJsonString(format);
}
template <typename ObjectType, typename ContainerType, bool UseCompare>
bool CListModelBase<ObjectType, ContainerType, UseCompare>::isOrderable() const
{
return false;
}
// see here for the reason of thess forward instantiations
// http://www.parashift.com/c++-faq/separate-template-class-defn-from-decl.html
template class CListModelBase<BlackMisc::Aviation::CLivery, BlackMisc::Aviation::CLiveryList, true>;

View File

@@ -15,6 +15,7 @@
#include "blackgui/blackguiexport.h"
#include "blackgui/models/columns.h"
#include "blackgui/models/modelfilter.h"
#include "blackgui/dropbase.h"
#include "blackmisc/worker.h"
#include <QStandardItemModel>
#include <QThread>
@@ -27,7 +28,9 @@ namespace BlackGui
namespace Models
{
//! Non templated base class, allows Q_OBJECT and signals to be used
class BLACKGUI_EXPORT CListModelBaseNonTemplate : public QStandardItemModel
class BLACKGUI_EXPORT CListModelBaseNonTemplate :
public QStandardItemModel,
public BlackGui::CDropBase
{
Q_OBJECT
@@ -38,17 +41,17 @@ namespace BlackGui
//! Destructor
virtual ~CListModelBaseNonTemplate() {}
//! \copydoc QStandardItemModel::columnCount()
//! \name Functions from QStandardItemModel
//! @{
virtual int columnCount(const QModelIndex &modelIndex = QModelIndex()) const override;
//! \copydoc QStandardItemModel::headerData()
virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
//! \copydoc QStandardItemModel::headerData()
virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
//! \copydoc QStandardItemModel::parent()
virtual QModelIndex parent(const QModelIndex &child) const override;
virtual Qt::ItemFlags flags(const QModelIndex &index) const override;
virtual Qt::DropActions supportedDragActions() const override;
virtual Qt::DropActions supportedDropActions() const override;
virtual QStringList mimeTypes() const override;
//! @}
//! Column to property index
virtual BlackMisc::CPropertyIndex columnToPropertyIndex(int column) const;
@@ -66,6 +69,9 @@ namespace BlackGui
//! \param propertyIndex index of column to be sorted
virtual void setSortColumnByPropertyIndex(const BlackMisc::CPropertyIndex &propertyIndex);
//! Sorting
virtual void setSorting(const BlackMisc::CPropertyIndex &propertyIndex, Qt::SortOrder order = Qt::AscendingOrder);
//! Get sort column property index
virtual int getSortColumn() const { return this->m_sortedColumn; }
@@ -78,17 +84,8 @@ namespace BlackGui
//! Translation context
virtual const QString &getTranslationContext() const;
//! \copydoc QStandardItemModel::flags
virtual Qt::ItemFlags flags(const QModelIndex &index) const override;
//! \copydoc QStandardItemModel::supportedDragActions
virtual Qt::DropActions supportedDragActions() const override;
//! \copydoc QStandardItemModel::supportedDropActions
virtual Qt::DropActions supportedDropActions() const override;
//! \copydoc QStandardItemModel::mimeTypes
virtual QStringList mimeTypes() const override;
//! Orderable, normally use a container BlackMisc::IOrderableList
virtual bool isOrderable() const = 0;
//! Mark as about to be destroyed, normally marked from view
void markDestroyed();
@@ -96,6 +93,9 @@ namespace BlackGui
//! Model about to be destroyed?
bool isModelDestroyed();
//! Drop actions
void setDropActions(Qt::DropActions dropActions) { this->m_dropActions = dropActions; }
//! Send signal that data have been changed.
//! \note Meant for scenarios where the container is directly updated and a subsequent signal is required
void sendDataChanged(int startRowIndex, int endRowIndex);
@@ -127,17 +127,18 @@ namespace BlackGui
protected:
//! Constructor
//! \param translationContext I18N context
//! \param translationContext I18N context
//! \param parent
CListModelBaseNonTemplate(const QString &translationContext, QObject *parent = nullptr);
//! Helper method with template free signature
virtual int performUpdateContainer(const BlackMisc::CVariant &variant, bool sort) = 0;
CColumns m_columns; //!< columns metadata
int m_sortedColumn; //!< current sort column
Qt::SortOrder m_sortOrder; //!< sort order (asc/desc)
bool m_modelDestroyed = false; //!< model is about to be destroyed
CColumns m_columns; //!< columns metadata
int m_sortedColumn; //!< current sort column
Qt::SortOrder m_sortOrder; //!< sort order (asc/desc)
bool m_modelDestroyed = false; //!< model is about to be destroyed
Qt::DropActions m_dropActions = Qt::IgnoreAction; //!< drop actions
};
//! List model
@@ -147,6 +148,24 @@ namespace BlackGui
//! Destructor
virtual ~CListModelBase() {}
//! \name Functions from QStandardItemModel
//! @{
virtual QVariant data(const QModelIndex &index, int role) const override;
virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
virtual QMimeData *mimeData(const QModelIndexList &indexes) const override;
virtual void sort(int column, Qt::SortOrder order) override;
virtual int rowCount(const QModelIndex &parentIndex = QModelIndex()) const override;
virtual bool canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) const override;
virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override;
//! @}
//! \name Functions from CListModelBaseNonTemplate
//! @{
virtual QJsonObject toJson() const override;
virtual QString toJsonString(QJsonDocument::JsonFormat format = QJsonDocument::Indented) const override;
virtual bool isOrderable() const override;
//! @}
//! Valid index (in range)
virtual bool isValidIndex(const QModelIndex &index) const;
@@ -156,20 +175,10 @@ namespace BlackGui
//! Full container or cached filtered container as approproiate
const ContainerType &containerOrFilteredContainer() const;
//! \copydoc QStandardItemModel::data()
virtual QVariant data(const QModelIndex &index, int role) const override;
//! \copydoc QStandardItemModel::setData()
//! \sa CListModelBaseNonTemplate::flags
virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
//! Simple set of data in container, using class is responsible for firing signals etc.
//! \sa sendDataChanged
bool setInContainer(const QModelIndex &index, const ObjectType &obj);
//! \copydoc QStandardItemModel::rowCount()
virtual int rowCount(const QModelIndex &parentIndex = QModelIndex()) const override;
//! Update by new container
//! \return int size after update
//! \remarks a sorting is performed only if a valid sort column is set
@@ -187,15 +196,15 @@ namespace BlackGui
//! Update single element
virtual void update(int rowIndex, const ObjectType &object);
//! Move items to position
virtual void moveItems(const ContainerType &items, int position);
//! Object at row position
virtual const ObjectType &at(const QModelIndex &index) const;
//! Sort by given sort order \sa getSortColumn() \sa getSortOrder()
void sort();
//! \copydoc QStandardItemModel::sort()
virtual void sort(int column, Qt::SortOrder order) override;
//! Truncate to given number
void truncate(int maxNumber, bool forceSort = false);
@@ -235,15 +244,6 @@ namespace BlackGui
//! Empty?
virtual bool isEmpty() const;
//! \copydoc QStandardItemModel::mimeData
virtual QMimeData *mimeData(const QModelIndexList &indexes) const override;
//! \copydoc BlackGui::Models::CListModelBaseNonTemplate::toJson
virtual QJsonObject toJson() const override;
//! \copydoc BlackGui::Models::CListModelBaseNonTemplate::toJsonString
virtual QString toJsonString(QJsonDocument::JsonFormat format = QJsonDocument::Indented) const override;
//! Filter available
bool hasFilter() const;
@@ -286,9 +286,8 @@ namespace BlackGui
template <typename ObjectType>
bool compareForModelSort(const ObjectType &a, const ObjectType &b, Qt::SortOrder order, const BlackMisc::CPropertyIndex &index, std::false_type)
{
Q_UNUSED(index);
BlackMisc::CVariant aQv = a.propertyByIndex(index);
BlackMisc::CVariant bQv = b.propertyByIndex(index);
const BlackMisc::CVariant aQv = a.propertyByIndex(index);
const BlackMisc::CVariant bQv = b.propertyByIndex(index);
return (order == Qt::AscendingOrder) ? (aQv < bQv) : (bQv < aQv);
}
} // namespace

View File

@@ -57,6 +57,37 @@ namespace BlackGui
return m_highlightKeys.contains(dbKeyForIndex(index));
}
template <typename ObjectType, typename ContainerType, typename KeyType, bool UseCompare>
COrderableListModelDbObjects<ObjectType, ContainerType, KeyType, UseCompare>::COrderableListModelDbObjects(const QString &translationContext, QObject *parent)
: CListModelDbObjects<ObjectType, ContainerType, KeyType, UseCompare>(translationContext, parent)
{ }
template <typename ObjectType, typename ContainerType, typename KeyType, bool UseCompare>
void COrderableListModelDbObjects<ObjectType, ContainerType, KeyType, UseCompare>::moveItems(const ContainerType &items, int position)
{
if (items.isEmpty()) { return; }
ContainerType container(this->container());
int order = 0;
if (position >= 0 && position < container.size())
{
order = container[position].getOrder();
}
container.moveTo(items, order);
this->updateContainerMaybeAsync(container);
}
template <typename ObjectType, typename ContainerType, typename KeyType, bool UseCompare>
int COrderableListModelDbObjects<ObjectType, ContainerType, KeyType, UseCompare>::update(const ContainerType &container, bool sort)
{
if (container.needsOrder())
{
ContainerType orderable(container);
orderable.resetOrder();
return CListModelDbObjects<ObjectType, ContainerType, KeyType, UseCompare>::update(orderable, sort);
}
return CListModelDbObjects<ObjectType, ContainerType, KeyType, UseCompare>::update(container, sort);
}
// see here for the reason of thess forward instantiations
// http://www.parashift.com/c++-faq/separate-template-class-defn-from-decl.html
template class CListModelDbObjects<BlackMisc::Aviation::CLivery, BlackMisc::Aviation::CLiveryList, int, true>;
@@ -65,6 +96,8 @@ namespace BlackGui
template class CListModelDbObjects<BlackMisc::Aviation::CAirlineIcaoCode, BlackMisc::Aviation::CAirlineIcaoCodeList, int, true>;
template class CListModelDbObjects<BlackMisc::Simulation::CAircraftModel, BlackMisc::Simulation::CAircraftModelList, int, true>;
template class CListModelDbObjects<BlackMisc::Simulation::CDistributor, BlackMisc::Simulation::CDistributorList, QString, true>;
template class COrderableListModelDbObjects<BlackMisc::Simulation::CAircraftModel, BlackMisc::Simulation::CAircraftModelList, int, true>;
template class COrderableListModelDbObjects<BlackMisc::Simulation::CDistributor, BlackMisc::Simulation::CDistributorList, QString, true>;
} // namespace
} // namespace

View File

@@ -58,6 +58,25 @@ namespace BlackGui
QColor m_highlightColor = Qt::green;
};
//! List model for DB objects
template <typename ObjectType, typename ContainerType, typename KeyType, bool UseCompare = false> class COrderableListModelDbObjects :
public CListModelDbObjects<ObjectType, ContainerType, KeyType, UseCompare>
{
public:
//! Destructor
virtual ~COrderableListModelDbObjects() {}
//! \name specialized BlackGui::Models::CListModelDbObjects functions for ordering
//! @{
virtual int update(const ContainerType &container, bool sort) override;
virtual void moveItems(const ContainerType &items, int position) override;
//! @}
protected:
//! Constructor
COrderableListModelDbObjects(const QString &translationContext, QObject *parent = nullptr);
};
} // namespace
} // namespace
#endif // guard