// This may look like C code, but it's really -*- C++ -*- /* * Copyright (C) 2008 Emweb bv, Herent, Belgium. * * See the LICENSE file for terms of use. */ #ifndef WAGGREGATE_PROXY_MODEL_H_ #define WAGGREGATE_PROXY_MODEL_H_ #include namespace Wt { class WRegExp; /*! \class WAggregateProxyModel Wt/WAggregateProxyModel.h Wt/WAggregateProxyModel.h * \brief A proxy model for %Wt's item models that provides column aggregation. * * This proxy model does not store data itself, but presents data from * a source model, and presents methods to organize columns using aggregation, * through which a user may navigate (usually to obtain more detailed results * related to a single aggregate quantity). * * To use this proxy model, you should provide a source model using * setSourceModel(), and define column ranges that can be aggregated * using addAggregate(). * * \if cpp * Example: * \code int COLS = 18; int ROWS = 20; // set up the source model model_ = std::make_shared(0, COLS); std::string columns[] = { "Supplier", "2004", "Q1", "January", "February", "March", "Q2", "April", "May", "June", "Q3", "July", "August", "September", "Q4", "October", "November", "December" }; for (unsigned i = 0; i < COLS; ++i) { model_->setHeaderData(i, Orientation::Horizontal, columns[i]); } for (unsigned i = 0; i < ROWS; ++i) { model_->insertRow(i); for (unsigned j = 0; j < COLS; ++j) model_->setData(i, j, "col " + std::to_string(j)); } // set up the proxy model auto proxy = std::make_shared(); proxy->setSourceModel(model_); proxy->addAggregate(1, 2, 17); proxy->addAggregate(2, 3, 5); proxy->addAggregate(6, 7, 9); proxy->addAggregate(10, 11, 13); proxy->addAggregate(14, 15, 17); proxy->expandColumn(1); // expand 2004 -> Q1 Q2 Q3 Q4 // define a view treeView_ = root()->addWidget(std::make_unique()); treeView_->setColumnBorder(Wt::StandardColor::Black); treeView_->setModel(proxy); treeView_->setColumnWidth(0, 160); treeView_->setColumnResizeEnabled(true); treeView_->setSortingEnabled(true); \endcode * \endif * * This example would render like this: * * \image html WAggregateProxyModel-1.png "A WTreeView using a WAggregateProxyModel" * * \note This model does not support dynamic changes to the column * definition of the source model (i.e. insertions or deletions of * source model columns). * * \ingroup modelview */ class WT_API WAggregateProxyModel : public WAbstractProxyModel { public: /*! \brief Constructor. * * Sets up the proxy without aggregation functionality. */ WAggregateProxyModel(); /*! \brief Destructor. */ virtual ~WAggregateProxyModel(); /*! \brief Adds a new column aggregation definition. * * The \p parentColumn is the column index in the source model that * acts as an aggregate for columns \p firstColumn to \p * lastColumn. \p parentColumn must border the range defined by * \p firstColumn to \p lastColumn: * \code * parentColumn == firstColumn - 1 || parentColumn == lastColumn + 1 * \endcode * * Note that column parameters reference column indexes in the * source model. * * Aggregation definitions can be nested, but should be strictly * hierarchical. * * The aggregate column will initially be collapsed. * * Only one aggregate can be defined per \p parentColumn. */ void addAggregate(int parentColumn, int firstColumn, int lastColumn); virtual WModelIndex mapFromSource(const WModelIndex& sourceIndex) const override; virtual WModelIndex mapToSource(const WModelIndex& proxyIndex) const override; virtual void setSourceModel(const std::shared_ptr& sourceModel) override; virtual void expandColumn(int column) override; virtual void collapseColumn(int column) override; virtual int columnCount(const WModelIndex& parent = WModelIndex()) const override; virtual int rowCount(const WModelIndex& parent = WModelIndex()) const override; virtual WFlags headerFlags (int section, Orientation orientation = Orientation::Horizontal) const override; virtual bool setHeaderData (int section, Orientation orientation, const cpp17::any& value, ItemDataRole role = ItemDataRole::Edit) override; virtual cpp17::any headerData (int section, Orientation orientation = Orientation::Horizontal, ItemDataRole role = ItemDataRole::Display) const override; virtual WModelIndex parent(const WModelIndex& index) const override; virtual WModelIndex index(int row, int column, const WModelIndex& parent = WModelIndex()) const override; virtual void sort(int column, SortOrder order = SortOrder::Ascending) override; private: struct Aggregate { int parentSrc_; int firstChildSrc_, lastChildSrc_; int level_; bool collapsed_; std::vector nestedAggregates_; Aggregate(); Aggregate(int parentColumn, int firstColumn, int lastColumn); bool contains(const Aggregate& other) const; bool contains(int column) const; Aggregate *add(const Aggregate& other); int mapFromSource(int sourceColumn) const; int mapToSource(int column) const; bool before(const Aggregate& other) const; bool after(int column) const; bool before(int column) const; int collapsedCount() const; Aggregate *findAggregate(int parentColumn); const Aggregate *findAggregate(int parentColumn) const; const Aggregate *findEnclosingAggregate(int column) const; int firstVisibleNotBefore(int column) const; int lastVisibleNotAfter(int column) const; }; Aggregate topLevel_; std::vector modelConnections_; void expand(Aggregate& aggregate); void collapse(Aggregate& aggregate); void propagateBeginRemove(const WModelIndex& proxyIndex, int start, int end); void propagateEndRemove(const WModelIndex& proxyIndex, int start, int end); void propagateBeginInsert(const WModelIndex& proxyIndex, int start, int end); void propagateEndInsert(const WModelIndex& proxyIndex, int start, int end); int lastVisibleSourceNotAfter(int sourceColumn) const; int firstVisibleSourceNotBefore(int sourceColumn) const; void sourceColumnsAboutToBeInserted(const WModelIndex& parent, int start, int end); void sourceColumnsInserted(const WModelIndex& parent, int start, int end); void sourceColumnsAboutToBeRemoved(const WModelIndex& parent, int start, int end); void sourceColumnsRemoved(const WModelIndex& parent, int start, int end); void sourceRowsAboutToBeInserted(const WModelIndex& parent, int start, int end); void sourceRowsInserted(const WModelIndex& parent, int start, int end); void sourceRowsAboutToBeRemoved(const WModelIndex& parent, int start, int end); void sourceRowsRemoved(const WModelIndex& parent, int start, int end); void sourceDataChanged(const WModelIndex& topLeft, const WModelIndex& bottomRight); void sourceHeaderDataChanged(Orientation orientation, int start, int end); void sourceLayoutAboutToBeChanged(); void sourceLayoutChanged(); void sourceModelReset(); }; } #endif // WAGGREGATE_PROXY_MODEL_H_