summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Dalheimer <jan@dalheimer.de>2013-12-31 17:26:36 +0100
committerJan Dalheimer <jan@dalheimer.de>2013-12-31 17:26:36 +0100
commitc47933d95cae407a99acfbbb941655f7cd52e1ae (patch)
treee61e312395089934affedea3916416881acfdc10
parent8cfd0881ac3fcbb45fd42dedcb1caf0be38eacaf (diff)
downloadMultiMC-c47933d95cae407a99acfbbb941655f7cd52e1ae.tar
MultiMC-c47933d95cae407a99acfbbb941655f7cd52e1ae.tar.gz
MultiMC-c47933d95cae407a99acfbbb941655f7cd52e1ae.tar.lz
MultiMC-c47933d95cae407a99acfbbb941655f7cd52e1ae.tar.xz
MultiMC-c47933d95cae407a99acfbbb941655f7cd52e1ae.zip
Loads of changes and some refactorings
-rw-r--r--CMakeLists.txt2
-rw-r--r--CategorizedView.cpp296
-rw-r--r--CategorizedView.h56
-rw-r--r--CategorizedViewCategory.cpp128
-rw-r--r--CategorizedViewCategory.h39
5 files changed, 248 insertions, 273 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 029c90b3..44a28c57 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -28,6 +28,8 @@ set(SOURCES
CategorizedView.h
CategorizedView.cpp
+ CategorizedViewCategory.h
+ CategorizedViewCategory.cpp
CategorizedProxyModel.h
CategorizedProxyModel.cpp
InstanceDelegate.h
diff --git a/CategorizedView.cpp b/CategorizedView.cpp
index 6bf18cbc..60230661 100644
--- a/CategorizedView.cpp
+++ b/CategorizedView.cpp
@@ -11,6 +11,8 @@
#include <QMimeData>
#include <QScrollBar>
+#include "CategorizedViewCategory.h"
+
template<typename T>
bool listsIntersect(const QList<T> &l1, const QList<T> t2)
{
@@ -24,86 +26,6 @@ bool listsIntersect(const QList<T> &l1, const QList<T> t2)
return false;
}
-CategorizedView::Category::Category(const QString &text, CategorizedView *view)
- : view(view), text(text), collapsed(false)
-{
-}
-CategorizedView::Category::Category(const CategorizedView::Category *other) :
- view(other->view), text(other->text), collapsed(other->collapsed), iconRect(other->iconRect), textRect(other->textRect)
-{
-}
-
-void CategorizedView::Category::drawHeader(QPainter *painter, const int y)
-{
- painter->save();
-
- int height = headerHeight() - 4;
- int collapseSize = height;
-
- // the icon
- iconRect = QRect(view->m_rightMargin + 2, 2 + y, collapseSize, collapseSize);
- painter->setPen(QPen(Qt::black, 1));
- painter->drawRect(iconRect);
- static const int margin = 2;
- QRect iconSubrect = iconRect.adjusted(margin, margin, -margin, -margin);
- int midX = iconSubrect.center().x();
- int midY = iconSubrect.center().y();
- if (collapsed)
- {
- painter->drawLine(midX, iconSubrect.top(), midX, iconSubrect.bottom());
- }
- painter->drawLine(iconSubrect.left(), midY, iconSubrect.right(), midY);
-
- // the text
- int textWidth = painter->fontMetrics().width(text);
- textRect = QRect(iconRect.right() + 4, y, textWidth, headerHeight());
- view->style()->drawItemText(painter, textRect, Qt::AlignHCenter | Qt::AlignVCenter, view->palette(), true, text);
-
- // the line
- painter->drawLine(textRect.right() + 4, y + headerHeight() / 2, view->contentWidth() - view->m_rightMargin, y + headerHeight() / 2);
-
- painter->restore();
-}
-
-int CategorizedView::Category::totalHeight() const
-{
- return headerHeight() + 5 + contentHeight();
-}
-int CategorizedView::Category::headerHeight() const
-{
- return qApp->fontMetrics().height() + 4;
-}
-int CategorizedView::Category::contentHeight() const
-{
- if (collapsed)
- {
- return 0;
- }
- QMap<int, int> rowToHeightMapping;
- foreach (const QModelIndex &index, view->itemsForCategory(this))
- {
- int row = view->categoryInternalPosition(index).second;
- if (!rowToHeightMapping.contains(row))
- {
- rowToHeightMapping.insert(row, view->itemSize(index).height());
- }
- }
- int result = 0;
- if (!rowToHeightMapping.isEmpty())
- {
- for (int i = 0; i < numRows(); ++i)
- {
- Q_ASSERT(rowToHeightMapping.contains(i));
- result += rowToHeightMapping[i];
- }
- }
- return result;
-}
-int CategorizedView::Category::numRows() const
-{
- return qMax(1, qCeil((qreal)view->numItemsForCategory(this) / (qreal)view->itemsPerRow()));
-}
-
CategorizedView::CategorizedView(QWidget *parent)
: QListView(parent), m_leftMargin(5), m_rightMargin(5), m_bottomMargin(5), m_categoryMargin(5)//, m_updatesDisabled(false), m_categoryEditor(0), m_editedCategory(0)
{
@@ -115,9 +37,6 @@ CategorizedView::CategorizedView(QWidget *parent)
setDragDropMode(QListView::InternalMove);
setAcceptDrops(true);
setSpacing(10);
-
- m_cachedCategoryToIndexMapping.setMaxCost(50);
- m_cachedVisualRects.setMaxCost(50);
}
CategorizedView::~CategorizedView()
@@ -172,23 +91,21 @@ void CategorizedView::updateGeometries()
int previousScroll = verticalScrollBar()->value();
- invalidateCaches();
-
- QMap<QString, Category *> cats;
+ QMap<QString, CategorizedViewCategory *> cats;
for (int i = 0; i < model()->rowCount(); ++i)
{
const QString category = model()->index(i, 0).data(CategorizedViewRoles::CategoryRole).toString();
if (!cats.contains(category))
{
- Category *old = this->category(category);
+ CategorizedViewCategory *old = this->category(category);
if (old)
{
- cats.insert(category, new Category(old));
+ cats.insert(category, new CategorizedViewCategory(old));
}
else
{
- cats.insert(category, new Category(category, this));
+ cats.insert(category, new CategorizedViewCategory(category, this));
}
}
}
@@ -201,6 +118,11 @@ void CategorizedView::updateGeometries()
qDeleteAll(m_categories);
m_categories = cats.values();
+ for (auto cat : m_categories)
+ {
+ cat->update();
+ }
+
if (m_categories.isEmpty())
{
verticalScrollBar()->setRange(0, 0);
@@ -208,7 +130,7 @@ void CategorizedView::updateGeometries()
else
{
int totalHeight = 0;
- foreach (const Category *category, m_categories)
+ foreach (const CategorizedViewCategory *category, m_categories)
{
totalHeight += category->totalHeight() + m_categoryMargin;
}
@@ -225,7 +147,7 @@ void CategorizedView::updateGeometries()
bool CategorizedView::isIndexHidden(const QModelIndex &index) const
{
- Category *cat = category(index);
+ CategorizedViewCategory *cat = category(index);
if (cat)
{
return cat->collapsed;
@@ -236,11 +158,11 @@ bool CategorizedView::isIndexHidden(const QModelIndex &index) const
}
}
-CategorizedView::Category *CategorizedView::category(const QModelIndex &index) const
+CategorizedViewCategory *CategorizedView::category(const QModelIndex &index) const
{
return category(index.data(CategorizedViewRoles::CategoryRole).toString());
}
-CategorizedView::Category *CategorizedView::category(const QString &cat) const
+CategorizedViewCategory *CategorizedView::category(const QString &cat) const
{
for (int i = 0; i < m_categories.size(); ++i)
{
@@ -251,7 +173,7 @@ CategorizedView::Category *CategorizedView::category(const QString &cat) const
}
return 0;
}
-CategorizedView::Category *CategorizedView::categoryAt(const QPoint &pos) const
+CategorizedViewCategory *CategorizedView::categoryAt(const QPoint &pos) const
{
for (int i = 0; i < m_categories.size(); ++i)
{
@@ -263,70 +185,6 @@ CategorizedView::Category *CategorizedView::categoryAt(const QPoint &pos) const
return 0;
}
-int CategorizedView::numItemsForCategory(const CategorizedView::Category *category) const
-{
- return itemsForCategory(category).size();
-}
-QList<QModelIndex> CategorizedView::itemsForCategory(const CategorizedView::Category *category) const
-{
- if (!m_cachedCategoryToIndexMapping.contains(category) || true)
- {
- QList<QModelIndex> *indices = new QList<QModelIndex>();
- for (int i = 0; i < model()->rowCount(); ++i)
- {
- if (model()->index(i, 0).data(CategorizedViewRoles::CategoryRole).toString() == category->text)
- {
- indices->append(model()->index(i, 0));
- }
- }
- m_cachedCategoryToIndexMapping.insert(category, indices, indices->size());
- }
- return *m_cachedCategoryToIndexMapping.object(category);
-}
-QModelIndex CategorizedView::firstItemForCategory(const CategorizedView::Category *category) const
-{
- QList<QModelIndex> indices = itemsForCategory(category);
- QModelIndex first;
- foreach (const QModelIndex &index, indices)
- {
- if (index.row() < first.row() || !first.isValid())
- {
- first = index;
- }
- }
-
- return first;
-}
-QModelIndex CategorizedView::lastItemForCategory(const CategorizedView::Category *category) const
-{
- QList<QModelIndex> indices = itemsForCategory(category);
- QModelIndex last;
- foreach (const QModelIndex &index, indices)
- {
- if (index.row() > last.row() || !last.isValid())
- {
- last = index;
- }
- }
-
- return last;
-}
-
-int CategorizedView::categoryTop(const CategorizedView::Category *category) const
-{
- int res = 0;
- const QList<Category *> cats = sortedCategories();
- for (int i = 0; i < cats.size(); ++i)
- {
- if (cats.at(i) == category)
- {
- break;
- }
- res += cats.at(i)->totalHeight() + m_categoryMargin;
- }
- return res;
-}
-
int CategorizedView::itemsPerRow() const
{
return qFloor((qreal)(contentWidth()) / (qreal)(itemWidth() + spacing()));
@@ -336,49 +194,34 @@ int CategorizedView::contentWidth() const
return width() - m_leftMargin - m_rightMargin;
}
-QList<CategorizedView::Category *> CategorizedView::sortedCategories() const
-{
- QList<Category *> out = m_categories;
- qSort(out.begin(), out.end(), [](const Category *c1, const Category *c2) { return c1->text < c2->text; });
- return out;
-}
-
int CategorizedView::itemWidth() const
{
- if (m_cachedItemWidth == -1)
- {
- m_cachedItemWidth = itemDelegate()->sizeHint(viewOptions(), model()->index(model()->rowCount() -1, 0)).width();
- }
- return m_cachedItemWidth;
+ return itemDelegate()->sizeHint(viewOptions(), model()->index(model()->rowCount() -1, 0)).width();
}
-QSize CategorizedView::itemSize(const QModelIndex &index) const
+int CategorizedView::categoryRowHeight(const QModelIndex &index) const
{
- if (!m_cachedItemSizes.contains(index))
+ QModelIndexList indices;
+ int internalRow = categoryInternalPosition(index).second;
+ foreach (const QModelIndex &i, category(index)->items())
{
- QModelIndexList indices;
- int internalRow = categoryInternalPosition(index).second;
- foreach (const QModelIndex &i, itemsForCategory(category(index)))
+ if (categoryInternalPosition(i).second == internalRow)
{
- if (categoryInternalPosition(i).second == internalRow)
- {
- indices.append(i);
- }
+ indices.append(i);
}
+ }
- int largestHeight = 0;
- foreach (const QModelIndex &i, indices)
- {
- largestHeight = qMax(largestHeight, itemDelegate()->sizeHint(viewOptions(), i).height());
- }
- m_cachedItemSizes.insert(index, new QSize(itemWidth(), largestHeight));
+ int largestHeight = 0;
+ foreach (const QModelIndex &i, indices)
+ {
+ largestHeight = qMax(largestHeight, itemDelegate()->sizeHint(viewOptions(), i).height());
}
- return *m_cachedItemSizes.object(index);
+ return largestHeight;
}
QPair<int, int> CategorizedView::categoryInternalPosition(const QModelIndex &index) const
{
- QList<QModelIndex> indices = itemsForCategory(category(index));
+ QList<QModelIndex> indices = category(index)->items();
int x = 0;
int y = 0;
const int perRow = itemsPerRow();
@@ -397,14 +240,25 @@ QPair<int, int> CategorizedView::categoryInternalPosition(const QModelIndex &ind
}
return qMakePair(x, y);
}
-int CategorizedView::itemHeightForCategoryRow(const CategorizedView::Category *category, const int internalRow) const
+int CategorizedView::categoryInternalRowTop(const QModelIndex &index) const
{
- foreach (const QModelIndex &i, itemsForCategory(category))
+ CategorizedViewCategory *cat = category(index);
+ int categoryInternalRow = categoryInternalPosition(index).second;
+ int result = 0;
+ for (int i = 0; i < categoryInternalRow; ++i)
+ {
+ result += cat->rowHeights.at(i);
+ }
+ return result;
+}
+int CategorizedView::itemHeightForCategoryRow(const CategorizedViewCategory *category, const int internalRow) const
+{
+ foreach (const QModelIndex &i, category->items())
{
QPair<int, int> pos = categoryInternalPosition(i);
if (pos.second == internalRow)
{
- return itemSize(i).height();
+ return categoryRowHeight(i);
}
}
return -1;
@@ -586,13 +440,10 @@ void CategorizedView::paintEvent(QPaintEvent *event)
QPainter painter(this->viewport());
painter.translate(-offset());
- // FIXME we shouldn't need to do this
- invalidateCaches();
-
int y = 0;
for (int i = 0; i < m_categories.size(); ++i)
{
- Category *category = m_categories.at(i);
+ CategorizedViewCategory *category = m_categories.at(i);
category->drawHeader(&painter, y);
y += category->totalHeight() + m_categoryMargin;
}
@@ -627,16 +478,16 @@ void CategorizedView::paintEvent(QPaintEvent *event)
if (!m_lastDragPosition.isNull())
{
- QPair<Category *, int> pair = rowDropPos(m_lastDragPosition);
- Category *category = pair.first;
+ QPair<CategorizedViewCategory *, int> pair = rowDropPos(m_lastDragPosition);
+ CategorizedViewCategory *category = pair.first;
int row = pair.second;
if (category)
{
- int internalRow = row - firstItemForCategory(category).row();
+ int internalRow = row - category->firstRow;
QLine line;
- if (internalRow >= numItemsForCategory(category))
+ if (internalRow >= category->numItems())
{
- QRect toTheRightOfRect = visualRect(lastItemForCategory(category));
+ QRect toTheRightOfRect = visualRect(category->lastItem());
line = QLine(toTheRightOfRect.topRight(), toTheRightOfRect.bottomRight());
}
else
@@ -700,8 +551,8 @@ void CategorizedView::dropEvent(QDropEvent *event)
return;
}
- QPair<Category *, int> dropPos = rowDropPos(event->pos() + offset());
- const Category *category = dropPos.first;
+ QPair<CategorizedViewCategory *, int> dropPos = rowDropPos(event->pos() + offset());
+ const CategorizedViewCategory *category = dropPos.first;
const int row = dropPos.second;
if (row == -1)
@@ -772,24 +623,17 @@ QRect CategorizedView::visualRect(const QModelIndex &index) const
return QRect();
}
- if (!m_cachedVisualRects.contains(index))
- {
- const Category *cat = category(index);
- QPair<int, int> pos = categoryInternalPosition(index);
- int x = pos.first;
- int y = pos.second;
-
- QSize size = itemSize(index);
+ const CategorizedViewCategory *cat = category(index);
+ QPair<int, int> pos = categoryInternalPosition(index);
+ int x = pos.first;
+ int y = pos.second;
- QRect *out = new QRect;
- out->setTop(categoryTop(cat) + cat->headerHeight() + 5 + y * size.height());
- out->setLeft(spacing() + x * itemWidth() + x * spacing());
- out->setSize(size);
+ QRect out;
+ out.setTop(cat->top() + cat->headerHeight() + 5 + categoryInternalRowTop(index));
+ out.setLeft(spacing() + x * itemWidth() + x * spacing());
+ out.setSize(itemDelegate()->sizeHint(viewOptions(), index));
- m_cachedVisualRects.insert(index, out);
- }
-
- return *m_cachedVisualRects.object(index);
+ return out;
}
/*
void CategorizedView::startCategoryEditor(Category *category)
@@ -908,13 +752,13 @@ bool CategorizedView::isDragEventAccepted(QDropEvent *event)
}
return true;
}
-QPair<CategorizedView::Category *, int> CategorizedView::rowDropPos(const QPoint &pos)
+QPair<CategorizedViewCategory *, int> CategorizedView::rowDropPos(const QPoint &pos)
{
// check that we aren't on a category header and calculate which category we're in
- Category *category = 0;
+ CategorizedViewCategory *category = 0;
{
int y = 0;
- foreach (Category *cat, m_categories)
+ foreach (CategorizedViewCategory *cat, m_categories)
{
if (pos.y() > y && pos.y() < (y + cat->headerHeight()))
{
@@ -933,7 +777,7 @@ QPair<CategorizedView::Category *, int> CategorizedView::rowDropPos(const QPoint
}
}
- QList<QModelIndex> indices = itemsForCategory(category);
+ QList<QModelIndex> indices = category->items();
// calculate the internal column
int internalColumn = -1;
@@ -967,7 +811,7 @@ QPair<CategorizedView::Category *, int> CategorizedView::rowDropPos(const QPoint
int internalRow = -1;
{
// FIXME rework the drag and drop code
- const int top = categoryTop(category);
+ const int top = category->top();
for (int r = 0, h = top; r < category->numRows(); h += itemHeightForCategoryRow(category, r), ++r)
{
if (pos.y() > h && pos.y() < (h + itemHeightForCategoryRow(category, r)))
@@ -1000,14 +844,6 @@ QPair<CategorizedView::Category *, int> CategorizedView::rowDropPos(const QPoint
return qMakePair(category, indices.at(categoryRow).row());
}
-void CategorizedView::invalidateCaches()
-{
- m_cachedItemWidth = -1;
- m_cachedCategoryToIndexMapping.clear();
- m_cachedVisualRects.clear();
- m_cachedItemSizes.clear();
-}
-
QPoint CategorizedView::offset() const
{
return QPoint(horizontalOffset(), verticalOffset());
diff --git a/CategorizedView.h b/CategorizedView.h
index 08d43be8..0550c7f8 100644
--- a/CategorizedView.h
+++ b/CategorizedView.h
@@ -3,7 +3,6 @@
#include <QListView>
#include <QLineEdit>
-#include <QCache>
struct CategorizedViewRoles
{
@@ -15,6 +14,8 @@ struct CategorizedViewRoles
};
};
+struct CategorizedViewCategory;
+
class CategorizedView : public QListView
{
Q_OBJECT
@@ -28,7 +29,7 @@ public:
void setSelection(const QRect &rect, const QItemSelectionModel::SelectionFlags commands) override;
protected slots:
- void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles);
+ void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles);
virtual void rowsInserted(const QModelIndex &parent, int start, int end);
virtual void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end);
virtual void updateGeometries();
@@ -50,57 +51,27 @@ protected:
void startDrag(Qt::DropActions supportedActions) override;
private:
- struct Category
- {
- Category(const QString &text, CategorizedView *view);
- Category(const Category *other);
- CategorizedView *view;
- QString text;
- bool collapsed;
- QRect iconRect;
- QRect textRect;
-
- void drawHeader(QPainter *painter, const int y);
- int totalHeight() const;
- int headerHeight() const;
- int contentHeight() const;
- int numRows() const;
- };
- friend struct Category;
+ friend struct CategorizedViewCategory;
- QList<Category *> m_categories;
- mutable QCache<const Category *, QList<QModelIndex> > m_cachedCategoryToIndexMapping;
- mutable QCache<const QModelIndex, QRect> m_cachedVisualRects;
+ QList<CategorizedViewCategory *> m_categories;
int m_leftMargin;
int m_rightMargin;
int m_bottomMargin;
int m_categoryMargin;
- int m_itemSpacing;
//bool m_updatesDisabled;
- Category *category(const QModelIndex &index) const;
- Category *category(const QString &cat) const;
- Category *categoryAt(const QPoint &pos) const;
- int numItemsForCategory(const Category *category) const;
- QList<QModelIndex> itemsForCategory(const Category *category) const;
- QModelIndex firstItemForCategory(const Category *category) const;
- QModelIndex lastItemForCategory(const Category *category) const;
-
- int categoryTop(const Category *category) const;
+ CategorizedViewCategory *category(const QModelIndex &index) const;
+ CategorizedViewCategory *category(const QString &cat) const;
+ CategorizedViewCategory *categoryAt(const QPoint &pos) const;
int itemsPerRow() const;
int contentWidth() const;
- static bool lessThanCategoryPointer(const Category *c1, const Category *c2);
- QList<Category *> sortedCategories() const;
-
private:
- mutable int m_cachedItemWidth;
- mutable QCache<QModelIndex, QSize> m_cachedItemSizes;
int itemWidth() const;
- QSize itemSize(const QModelIndex &index) const;
+ int categoryRowHeight(const QModelIndex &index) const;
/*QLineEdit *m_categoryEditor;
Category *m_editedCategory;
@@ -113,21 +84,20 @@ private:
QPoint m_pressedPosition;
QPersistentModelIndex m_pressedIndex;
bool m_pressedAlreadySelected;
- Category *m_pressedCategory;
+ CategorizedViewCategory *m_pressedCategory;
QItemSelectionModel::SelectionFlag m_ctrlDragSelectionFlag;
QPoint m_lastDragPosition;
QPair<int, int> categoryInternalPosition(const QModelIndex &index) const;
- int itemHeightForCategoryRow(const Category *category, const int internalRow) const;
+ int categoryInternalRowTop(const QModelIndex &index) const;
+ int itemHeightForCategoryRow(const CategorizedViewCategory *category, const int internalRow) const;
QPixmap renderToPixmap(const QModelIndexList &indices, QRect *r) const;
QList<QPair<QRect, QModelIndex> > draggablePaintPairs(const QModelIndexList &indices, QRect *r) const;
bool isDragEventAccepted(QDropEvent *event);
- QPair<Category *, int> rowDropPos(const QPoint &pos);
-
- void invalidateCaches();
+ QPair<CategorizedViewCategory *, int> rowDropPos(const QPoint &pos);
QPoint offset() const;
};
diff --git a/CategorizedViewCategory.cpp b/CategorizedViewCategory.cpp
new file mode 100644
index 00000000..b82ffc96
--- /dev/null
+++ b/CategorizedViewCategory.cpp
@@ -0,0 +1,128 @@
+#include "CategorizedViewCategory.h"
+
+#include <QModelIndex>
+#include <QPainter>
+#include <QtMath>
+
+#include "CategorizedView.h"
+
+CategorizedViewCategory::CategorizedViewCategory(const QString &text, CategorizedView *view)
+ : view(view), text(text), collapsed(false)
+{
+}
+CategorizedViewCategory::CategorizedViewCategory(const CategorizedViewCategory *other) :
+ view(other->view), text(other->text), collapsed(other->collapsed), iconRect(other->iconRect), textRect(other->textRect)
+{
+}
+
+void CategorizedViewCategory::update()
+{
+ firstRow = firstItem().row();
+
+ rowHeights = QVector<int>(numRows());
+ for (int i = 0; i < numRows(); ++i)
+ {
+ rowHeights[i] = view->categoryRowHeight(view->model()->index(i * view->itemsPerRow() + firstRow, 0));
+ }
+}
+
+void CategorizedViewCategory::drawHeader(QPainter *painter, const int y)
+{
+ painter->save();
+
+ int height = headerHeight() - 4;
+ int collapseSize = height;
+
+ // the icon
+ iconRect = QRect(view->m_rightMargin + 2, 2 + y, collapseSize, collapseSize);
+ painter->setPen(QPen(Qt::black, 1));
+ painter->drawRect(iconRect);
+ static const int margin = 2;
+ QRect iconSubrect = iconRect.adjusted(margin, margin, -margin, -margin);
+ int midX = iconSubrect.center().x();
+ int midY = iconSubrect.center().y();
+ if (collapsed)
+ {
+ painter->drawLine(midX, iconSubrect.top(), midX, iconSubrect.bottom());
+ }
+ painter->drawLine(iconSubrect.left(), midY, iconSubrect.right(), midY);
+
+ // the text
+ int textWidth = painter->fontMetrics().width(text);
+ textRect = QRect(iconRect.right() + 4, y, textWidth, headerHeight());
+ painter->setBrush(view->viewOptions().palette.text());
+ view->style()->drawItemText(painter, textRect, Qt::AlignHCenter | Qt::AlignVCenter, view->viewport()->palette(), true, text);
+
+ // the line
+ painter->drawLine(textRect.right() + 4, y + headerHeight() / 2, view->contentWidth() - view->m_rightMargin, y + headerHeight() / 2);
+
+ painter->restore();
+}
+
+int CategorizedViewCategory::totalHeight() const
+{
+ return headerHeight() + 5 + contentHeight();
+}
+int CategorizedViewCategory::headerHeight() const
+{
+ return view->viewport()->fontMetrics().height() + 4;
+}
+int CategorizedViewCategory::contentHeight() const
+{
+ if (collapsed)
+ {
+ return 0;
+ }
+ int result = 0;
+ for (int i = 0; i < rowHeights.size(); ++i)
+ {
+ result += rowHeights[i];
+ }
+ return result;
+}
+int CategorizedViewCategory::numRows() const
+{
+ return qMax(1, qCeil((qreal)numItems() / (qreal)view->itemsPerRow()));
+}
+int CategorizedViewCategory::top() const
+{
+ int res = 0;
+ const QList<CategorizedViewCategory *> cats = view->m_categories;
+ for (int i = 0; i < cats.size(); ++i)
+ {
+ if (cats.at(i) == this)
+ {
+ break;
+ }
+ res += cats.at(i)->totalHeight() + view->m_categoryMargin;
+ }
+ return res;
+}
+
+QList<QModelIndex> CategorizedViewCategory::items() const
+{
+ QList<QModelIndex> indices;
+ for (int i = 0; i < view->model()->rowCount(); ++i)
+ {
+ const QModelIndex index = view->model()->index(i, 0);
+ if (index.data(CategorizedViewRoles::CategoryRole).toString() == text)
+ {
+ indices.append(index);
+ }
+ }
+ return indices;
+}
+int CategorizedViewCategory::numItems() const
+{
+ return items().size();
+}
+QModelIndex CategorizedViewCategory::firstItem() const
+{
+ QList<QModelIndex> indices = items();
+ return indices.isEmpty() ? QModelIndex() : indices.first();
+}
+QModelIndex CategorizedViewCategory::lastItem() const
+{
+ QList<QModelIndex> indices = items();
+ return indices.isEmpty() ? QModelIndex() : indices.last();
+}
diff --git a/CategorizedViewCategory.h b/CategorizedViewCategory.h
new file mode 100644
index 00000000..cb6ef8c5
--- /dev/null
+++ b/CategorizedViewCategory.h
@@ -0,0 +1,39 @@
+#ifndef CATEGORIZEDVIEWROW_H
+#define CATEGORIZEDVIEWROW_H
+
+#include <QString>
+#include <QRect>
+#include <QVector>
+
+class CategorizedView;
+class QPainter;
+class QModelIndex;
+
+struct CategorizedViewCategory
+{
+ CategorizedViewCategory(const QString &text, CategorizedView *view);
+ CategorizedViewCategory(const CategorizedViewCategory *other);
+ CategorizedView *view;
+ QString text;
+ bool collapsed;
+ QRect iconRect;
+ QRect textRect;
+ QVector<int> rowHeights;
+ int firstRow;
+
+ void update();
+
+ void drawHeader(QPainter *painter, const int y);
+ int totalHeight() const;
+ int headerHeight() const;
+ int contentHeight() const;
+ int numRows() const;
+ int top() const;
+
+ QList<QModelIndex> items() const;
+ int numItems() const;
+ QModelIndex firstItem() const;
+ QModelIndex lastItem() const;
+};
+
+#endif // CATEGORIZEDVIEWROW_H