diff options
Diffstat (limited to 'application/groupview')
-rw-r--r-- | application/groupview/GroupView.cpp | 1474 | ||||
-rw-r--r-- | application/groupview/GroupView.h | 184 | ||||
-rw-r--r-- | application/groupview/GroupedProxyModel.cpp | 34 | ||||
-rw-r--r-- | application/groupview/GroupedProxyModel.h | 8 | ||||
-rw-r--r-- | application/groupview/InstanceDelegate.cpp | 550 | ||||
-rw-r--r-- | application/groupview/InstanceDelegate.h | 8 | ||||
-rw-r--r-- | application/groupview/VisualGroup.cpp | 462 | ||||
-rw-r--r-- | application/groupview/VisualGroup.h | 106 |
8 files changed, 1413 insertions, 1413 deletions
diff --git a/application/groupview/GroupView.cpp b/application/groupview/GroupView.cpp index 0d6aa49e..a1b44e64 100644 --- a/application/groupview/GroupView.cpp +++ b/application/groupview/GroupView.cpp @@ -31,937 +31,937 @@ template <typename T> bool listsIntersect(const QList<T> &l1, const QList<T> t2) { - for (auto &item : l1) - { - if (t2.contains(item)) - { - return true; - } - } - return false; + for (auto &item : l1) + { + if (t2.contains(item)) + { + return true; + } + } + return false; } GroupView::GroupView(QWidget *parent) - : QAbstractItemView(parent) + : QAbstractItemView(parent) { - setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); - setAcceptDrops(true); - setAutoScroll(true); + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); + setAcceptDrops(true); + setAutoScroll(true); } GroupView::~GroupView() { - qDeleteAll(m_groups); - m_groups.clear(); + qDeleteAll(m_groups); + m_groups.clear(); } void GroupView::setModel(QAbstractItemModel *model) { - QAbstractItemView::setModel(model); - connect(model, &QAbstractItemModel::modelReset, this, &GroupView::modelReset); - connect(model, &QAbstractItemModel::rowsRemoved, this, &GroupView::rowsRemoved); + QAbstractItemView::setModel(model); + connect(model, &QAbstractItemModel::modelReset, this, &GroupView::modelReset); + connect(model, &QAbstractItemModel::rowsRemoved, this, &GroupView::rowsRemoved); } void GroupView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, - const QVector<int> &roles) + const QVector<int> &roles) { - scheduleDelayedItemsLayout(); + scheduleDelayedItemsLayout(); } void GroupView::rowsInserted(const QModelIndex &parent, int start, int end) { - scheduleDelayedItemsLayout(); + scheduleDelayedItemsLayout(); } void GroupView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) { - scheduleDelayedItemsLayout(); + scheduleDelayedItemsLayout(); } void GroupView::modelReset() { - scheduleDelayedItemsLayout(); + scheduleDelayedItemsLayout(); } void GroupView::rowsRemoved() { - scheduleDelayedItemsLayout(); + scheduleDelayedItemsLayout(); } class LocaleString : public QString { public: - LocaleString(const char *s) : QString(s) - { - } - LocaleString(const QString &s) : QString(s) - { - } + LocaleString(const char *s) : QString(s) + { + } + LocaleString(const QString &s) : QString(s) + { + } }; inline bool operator<(const LocaleString &lhs, const LocaleString &rhs) { - return (QString::localeAwareCompare(lhs, rhs) < 0); + return (QString::localeAwareCompare(lhs, rhs) < 0); } void GroupView::updateScrollbar() { - int previousScroll = verticalScrollBar()->value(); - if (m_groups.isEmpty()) - { - verticalScrollBar()->setRange(0, 0); - } - else - { - int totalHeight = 0; - // top margin - totalHeight += m_categoryMargin; - int itemScroll = 0; - for (auto category : m_groups) - { - category->m_verticalPosition = totalHeight; - totalHeight += category->totalHeight() + m_categoryMargin; - if(!itemScroll && category->totalHeight() != 0) - { - itemScroll = category->contentHeight() / category->numRows(); - } - } - // do not divide by zero - if(itemScroll == 0) - itemScroll = 64; - - totalHeight += m_bottomMargin; - verticalScrollBar()->setSingleStep ( itemScroll ); - const int rowsPerPage = qMax ( viewport()->height() / itemScroll, 1 ); - verticalScrollBar()->setPageStep ( rowsPerPage * itemScroll ); - - verticalScrollBar()->setRange(0, totalHeight - height()); - } - - verticalScrollBar()->setValue(qMin(previousScroll, verticalScrollBar()->maximum())); + int previousScroll = verticalScrollBar()->value(); + if (m_groups.isEmpty()) + { + verticalScrollBar()->setRange(0, 0); + } + else + { + int totalHeight = 0; + // top margin + totalHeight += m_categoryMargin; + int itemScroll = 0; + for (auto category : m_groups) + { + category->m_verticalPosition = totalHeight; + totalHeight += category->totalHeight() + m_categoryMargin; + if(!itemScroll && category->totalHeight() != 0) + { + itemScroll = category->contentHeight() / category->numRows(); + } + } + // do not divide by zero + if(itemScroll == 0) + itemScroll = 64; + + totalHeight += m_bottomMargin; + verticalScrollBar()->setSingleStep ( itemScroll ); + const int rowsPerPage = qMax ( viewport()->height() / itemScroll, 1 ); + verticalScrollBar()->setPageStep ( rowsPerPage * itemScroll ); + + verticalScrollBar()->setRange(0, totalHeight - height()); + } + + verticalScrollBar()->setValue(qMin(previousScroll, verticalScrollBar()->maximum())); } void GroupView::updateGeometries() { - geometryCache.clear(); - - QMap<LocaleString, VisualGroup *> cats; - - for (int i = 0; i < model()->rowCount(); ++i) - { - const QString groupName = model()->index(i, 0).data(GroupViewRoles::GroupRole).toString(); - if (!cats.contains(groupName)) - { - VisualGroup *old = this->category(groupName); - if (old) - { - auto cat = new VisualGroup(old); - cats.insert(groupName, cat); - cat->update(); - } - else - { - auto cat = new VisualGroup(groupName, this); - cats.insert(groupName, cat); - cat->update(); - } - } - } - - qDeleteAll(m_groups); - m_groups = cats.values(); - updateScrollbar(); - viewport()->update(); + geometryCache.clear(); + + QMap<LocaleString, VisualGroup *> cats; + + for (int i = 0; i < model()->rowCount(); ++i) + { + const QString groupName = model()->index(i, 0).data(GroupViewRoles::GroupRole).toString(); + if (!cats.contains(groupName)) + { + VisualGroup *old = this->category(groupName); + if (old) + { + auto cat = new VisualGroup(old); + cats.insert(groupName, cat); + cat->update(); + } + else + { + auto cat = new VisualGroup(groupName, this); + cats.insert(groupName, cat); + cat->update(); + } + } + } + + qDeleteAll(m_groups); + m_groups = cats.values(); + updateScrollbar(); + viewport()->update(); } bool GroupView::isIndexHidden(const QModelIndex &index) const { - VisualGroup *cat = category(index); - if (cat) - { - return cat->collapsed; - } - else - { - return false; - } + VisualGroup *cat = category(index); + if (cat) + { + return cat->collapsed; + } + else + { + return false; + } } VisualGroup *GroupView::category(const QModelIndex &index) const { - return category(index.data(GroupViewRoles::GroupRole).toString()); + return category(index.data(GroupViewRoles::GroupRole).toString()); } VisualGroup *GroupView::category(const QString &cat) const { - for (auto group : m_groups) - { - if (group->text == cat) - { - return group; - } - } - return nullptr; + for (auto group : m_groups) + { + if (group->text == cat) + { + return group; + } + } + return nullptr; } VisualGroup *GroupView::categoryAt(const QPoint &pos, VisualGroup::HitResults & result) const { - for (auto group : m_groups) - { - result = group->hitScan(pos); - if(result != VisualGroup::NoHit) - { - return group; - } - } - result = VisualGroup::NoHit; - return nullptr; + for (auto group : m_groups) + { + result = group->hitScan(pos); + if(result != VisualGroup::NoHit) + { + return group; + } + } + result = VisualGroup::NoHit; + return nullptr; } QString GroupView::groupNameAt(const QPoint &point) { - VisualGroup::HitResults hitresult; - auto group = categoryAt(point + offset(), hitresult); - if(group && (hitresult & (VisualGroup::HeaderHit | VisualGroup::BodyHit))) - { - return group->text; - } - return QString(); + VisualGroup::HitResults hitresult; + auto group = categoryAt(point + offset(), hitresult); + if(group && (hitresult & (VisualGroup::HeaderHit | VisualGroup::BodyHit))) + { + return group->text; + } + return QString(); } int GroupView::calculateItemsPerRow() const { - return qFloor((qreal)(contentWidth()) / (qreal)(itemWidth() + m_spacing)); + return qFloor((qreal)(contentWidth()) / (qreal)(itemWidth() + m_spacing)); } int GroupView::contentWidth() const { - return width() - m_leftMargin - m_rightMargin; + return width() - m_leftMargin - m_rightMargin; } int GroupView::itemWidth() const { - return m_itemWidth; + return m_itemWidth; } void GroupView::mousePressEvent(QMouseEvent *event) { - // endCategoryEditor(); - - QPoint visualPos = event->pos(); - QPoint geometryPos = event->pos() + offset(); - - QPersistentModelIndex index = indexAt(visualPos); - - m_pressedIndex = index; - m_pressedAlreadySelected = selectionModel()->isSelected(m_pressedIndex); - m_pressedPosition = geometryPos; - - VisualGroup::HitResults hitresult; - m_pressedCategory = categoryAt(geometryPos, hitresult); - if (m_pressedCategory && hitresult & VisualGroup::CheckboxHit) - { - setState(m_pressedCategory->collapsed ? ExpandingState : CollapsingState); - event->accept(); - return; - } - - if (index.isValid() && (index.flags() & Qt::ItemIsEnabled)) - { - if(index != currentIndex()) - { - // FIXME: better! - m_currentCursorColumn = -1; - } - // we disable scrollTo for mouse press so the item doesn't change position - // when the user is interacting with it (ie. clicking on it) - bool autoScroll = hasAutoScroll(); - setAutoScroll(false); - selectionModel()->setCurrentIndex(index, QItemSelectionModel::NoUpdate); - - setAutoScroll(autoScroll); - QRect rect(visualPos, visualPos); - setSelection(rect, QItemSelectionModel::ClearAndSelect); - - // signal handlers may change the model - emit pressed(index); - } - else - { - // Forces a finalize() even if mouse is pressed, but not on a item - selectionModel()->select(QModelIndex(), QItemSelectionModel::Select); - } + // endCategoryEditor(); + + QPoint visualPos = event->pos(); + QPoint geometryPos = event->pos() + offset(); + + QPersistentModelIndex index = indexAt(visualPos); + + m_pressedIndex = index; + m_pressedAlreadySelected = selectionModel()->isSelected(m_pressedIndex); + m_pressedPosition = geometryPos; + + VisualGroup::HitResults hitresult; + m_pressedCategory = categoryAt(geometryPos, hitresult); + if (m_pressedCategory && hitresult & VisualGroup::CheckboxHit) + { + setState(m_pressedCategory->collapsed ? ExpandingState : CollapsingState); + event->accept(); + return; + } + + if (index.isValid() && (index.flags() & Qt::ItemIsEnabled)) + { + if(index != currentIndex()) + { + // FIXME: better! + m_currentCursorColumn = -1; + } + // we disable scrollTo for mouse press so the item doesn't change position + // when the user is interacting with it (ie. clicking on it) + bool autoScroll = hasAutoScroll(); + setAutoScroll(false); + selectionModel()->setCurrentIndex(index, QItemSelectionModel::NoUpdate); + + setAutoScroll(autoScroll); + QRect rect(visualPos, visualPos); + setSelection(rect, QItemSelectionModel::ClearAndSelect); + + // signal handlers may change the model + emit pressed(index); + } + else + { + // Forces a finalize() even if mouse is pressed, but not on a item + selectionModel()->select(QModelIndex(), QItemSelectionModel::Select); + } } void GroupView::mouseMoveEvent(QMouseEvent *event) { - QPoint topLeft; - QPoint visualPos = event->pos(); - QPoint geometryPos = event->pos() + offset(); - - if (state() == ExpandingState || state() == CollapsingState) - { - return; - } - - if (state() == DraggingState) - { - topLeft = m_pressedPosition - offset(); - if ((topLeft - event->pos()).manhattanLength() > QApplication::startDragDistance()) - { - m_pressedIndex = QModelIndex(); - startDrag(model()->supportedDragActions()); - setState(NoState); - stopAutoScroll(); - } - return; - } - - if (selectionMode() != SingleSelection) - { - topLeft = m_pressedPosition - offset(); - } - else - { - topLeft = geometryPos; - } - - if (m_pressedIndex.isValid() && (state() != DragSelectingState) && - (event->buttons() != Qt::NoButton) && !selectedIndexes().isEmpty()) - { - setState(DraggingState); - return; - } - - if ((event->buttons() & Qt::LeftButton) && selectionModel()) - { - setState(DragSelectingState); - - setSelection(QRect(visualPos, visualPos), QItemSelectionModel::ClearAndSelect); - QModelIndex index = indexAt(visualPos); - - // set at the end because it might scroll the view - if (index.isValid() && (index != selectionModel()->currentIndex()) && - (index.flags() & Qt::ItemIsEnabled)) - { - selectionModel()->setCurrentIndex(index, QItemSelectionModel::NoUpdate); - } - } + QPoint topLeft; + QPoint visualPos = event->pos(); + QPoint geometryPos = event->pos() + offset(); + + if (state() == ExpandingState || state() == CollapsingState) + { + return; + } + + if (state() == DraggingState) + { + topLeft = m_pressedPosition - offset(); + if ((topLeft - event->pos()).manhattanLength() > QApplication::startDragDistance()) + { + m_pressedIndex = QModelIndex(); + startDrag(model()->supportedDragActions()); + setState(NoState); + stopAutoScroll(); + } + return; + } + + if (selectionMode() != SingleSelection) + { + topLeft = m_pressedPosition - offset(); + } + else + { + topLeft = geometryPos; + } + + if (m_pressedIndex.isValid() && (state() != DragSelectingState) && + (event->buttons() != Qt::NoButton) && !selectedIndexes().isEmpty()) + { + setState(DraggingState); + return; + } + + if ((event->buttons() & Qt::LeftButton) && selectionModel()) + { + setState(DragSelectingState); + + setSelection(QRect(visualPos, visualPos), QItemSelectionModel::ClearAndSelect); + QModelIndex index = indexAt(visualPos); + + // set at the end because it might scroll the view + if (index.isValid() && (index != selectionModel()->currentIndex()) && + (index.flags() & Qt::ItemIsEnabled)) + { + selectionModel()->setCurrentIndex(index, QItemSelectionModel::NoUpdate); + } + } } void GroupView::mouseReleaseEvent(QMouseEvent *event) { - QPoint visualPos = event->pos(); - QPoint geometryPos = event->pos() + offset(); - QPersistentModelIndex index = indexAt(visualPos); - - VisualGroup::HitResults hitresult; - - bool click = (index == m_pressedIndex && index.isValid()) || - (m_pressedCategory && m_pressedCategory == categoryAt(geometryPos, hitresult)); - - if (click && m_pressedCategory) - { - if (state() == ExpandingState) - { - m_pressedCategory->collapsed = false; - updateGeometries(); - viewport()->update(); - event->accept(); - return; - } - else if (state() == CollapsingState) - { - m_pressedCategory->collapsed = true; - updateGeometries(); - viewport()->update(); - event->accept(); - return; - } - } - - m_ctrlDragSelectionFlag = QItemSelectionModel::NoUpdate; - - setState(NoState); - - if (click) - { - if (event->button() == Qt::LeftButton) - { - emit clicked(index); - } - QStyleOptionViewItem option = viewOptions(); - if (m_pressedAlreadySelected) - { - option.state |= QStyle::State_Selected; - } - if ((model()->flags(index) & Qt::ItemIsEnabled) && - style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, &option, this)) - { - emit activated(index); - } - } + QPoint visualPos = event->pos(); + QPoint geometryPos = event->pos() + offset(); + QPersistentModelIndex index = indexAt(visualPos); + + VisualGroup::HitResults hitresult; + + bool click = (index == m_pressedIndex && index.isValid()) || + (m_pressedCategory && m_pressedCategory == categoryAt(geometryPos, hitresult)); + + if (click && m_pressedCategory) + { + if (state() == ExpandingState) + { + m_pressedCategory->collapsed = false; + updateGeometries(); + viewport()->update(); + event->accept(); + return; + } + else if (state() == CollapsingState) + { + m_pressedCategory->collapsed = true; + updateGeometries(); + viewport()->update(); + event->accept(); + return; + } + } + + m_ctrlDragSelectionFlag = QItemSelectionModel::NoUpdate; + + setState(NoState); + + if (click) + { + if (event->button() == Qt::LeftButton) + { + emit clicked(index); + } + QStyleOptionViewItem option = viewOptions(); + if (m_pressedAlreadySelected) + { + option.state |= QStyle::State_Selected; + } + if ((model()->flags(index) & Qt::ItemIsEnabled) && + style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, &option, this)) + { + emit activated(index); + } + } } void GroupView::mouseDoubleClickEvent(QMouseEvent *event) { - QModelIndex index = indexAt(event->pos()); - if (!index.isValid() || !(index.flags() & Qt::ItemIsEnabled) || (m_pressedIndex != index)) - { - QMouseEvent me(QEvent::MouseButtonPress, event->localPos(), event->windowPos(), - event->screenPos(), event->button(), event->buttons(), - event->modifiers()); - mousePressEvent(&me); - return; - } - // signal handlers may change the model - QPersistentModelIndex persistent = index; - emit doubleClicked(persistent); + QModelIndex index = indexAt(event->pos()); + if (!index.isValid() || !(index.flags() & Qt::ItemIsEnabled) || (m_pressedIndex != index)) + { + QMouseEvent me(QEvent::MouseButtonPress, event->localPos(), event->windowPos(), + event->screenPos(), event->button(), event->buttons(), + event->modifiers()); + mousePressEvent(&me); + return; + } + // signal handlers may change the model + QPersistentModelIndex persistent = index; + emit doubleClicked(persistent); } void GroupView::paintEvent(QPaintEvent *event) { - executeDelayedItemsLayout(); - - QPainter painter(this->viewport()); - - QStyleOptionViewItem option(viewOptions()); - option.widget = this; - - int wpWidth = viewport()->width(); - option.rect.setWidth(wpWidth); - for (int i = 0; i < m_groups.size(); ++i) - { - VisualGroup *category = m_groups.at(i); - int y = category->verticalPosition(); - y -= verticalOffset(); - QRect backup = option.rect; - int height = category->totalHeight(); - option.rect.setTop(y); - option.rect.setHeight(height); - option.rect.setLeft(m_leftMargin); - option.rect.setRight(wpWidth - m_rightMargin); - category->drawHeader(&painter, option); - y += category->totalHeight() + m_categoryMargin; - option.rect = backup; - } - - for (int i = 0; i < model()->rowCount(); ++i) - { - const QModelIndex index = model()->index(i, 0); - if (isIndexHidden(index)) - { - continue; - } - Qt::ItemFlags flags = index.flags(); - option.rect = visualRect(index); - option.features |= QStyleOptionViewItem::WrapText; - if (flags & Qt::ItemIsSelectable && selectionModel()->isSelected(index)) - { - option.state |= selectionModel()->isSelected(index) ? QStyle::State_Selected - : QStyle::State_None; - } - else - { - option.state &= ~QStyle::State_Selected; - } - option.state |= (index == currentIndex()) ? QStyle::State_HasFocus : QStyle::State_None; - if (!(flags & Qt::ItemIsEnabled)) - { - option.state &= ~QStyle::State_Enabled; - } - itemDelegate()->paint(&painter, option, index); - } - - /* - * Drop indicators for manual reordering... - */ + executeDelayedItemsLayout(); + + QPainter painter(this->viewport()); + + QStyleOptionViewItem option(viewOptions()); + option.widget = this; + + int wpWidth = viewport()->width(); + option.rect.setWidth(wpWidth); + for (int i = 0; i < m_groups.size(); ++i) + { + VisualGroup *category = m_groups.at(i); + int y = category->verticalPosition(); + y -= verticalOffset(); + QRect backup = option.rect; + int height = category->totalHeight(); + option.rect.setTop(y); + option.rect.setHeight(height); + option.rect.setLeft(m_leftMargin); + option.rect.setRight(wpWidth - m_rightMargin); + category->drawHeader(&painter, option); + y += category->totalHeight() + m_categoryMargin; + option.rect = backup; + } + + for (int i = 0; i < model()->rowCount(); ++i) + { + const QModelIndex index = model()->index(i, 0); + if (isIndexHidden(index)) + { + continue; + } + Qt::ItemFlags flags = index.flags(); + option.rect = visualRect(index); + option.features |= QStyleOptionViewItem::WrapText; + if (flags & Qt::ItemIsSelectable && selectionModel()->isSelected(index)) + { + option.state |= selectionModel()->isSelected(index) ? QStyle::State_Selected + : QStyle::State_None; + } + else + { + option.state &= ~QStyle::State_Selected; + } + option.state |= (index == currentIndex()) ? QStyle::State_HasFocus : QStyle::State_None; + if (!(flags & Qt::ItemIsEnabled)) + { + option.state &= ~QStyle::State_Enabled; + } + itemDelegate()->paint(&painter, option, index); + } + + /* + * Drop indicators for manual reordering... + */ #if 0 - if (!m_lastDragPosition.isNull()) - { - QPair<Group *, int> pair = rowDropPos(m_lastDragPosition); - Group *category = pair.first; - int row = pair.second; - if (category) - { - int internalRow = row - category->firstItemIndex; - QLine line; - if (internalRow >= category->numItems()) - { - QRect toTheRightOfRect = visualRect(category->lastItem()); - line = QLine(toTheRightOfRect.topRight(), toTheRightOfRect.bottomRight()); - } - else - { - QRect toTheLeftOfRect = visualRect(model()->index(row, 0)); - line = QLine(toTheLeftOfRect.topLeft(), toTheLeftOfRect.bottomLeft()); - } - painter.save(); - painter.setPen(QPen(Qt::black, 3)); - painter.drawLine(line); - painter.restore(); - } - } + if (!m_lastDragPosition.isNull()) + { + QPair<Group *, int> pair = rowDropPos(m_lastDragPosition); + Group *category = pair.first; + int row = pair.second; + if (category) + { + int internalRow = row - category->firstItemIndex; + QLine line; + if (internalRow >= category->numItems()) + { + QRect toTheRightOfRect = visualRect(category->lastItem()); + line = QLine(toTheRightOfRect.topRight(), toTheRightOfRect.bottomRight()); + } + else + { + QRect toTheLeftOfRect = visualRect(model()->index(row, 0)); + line = QLine(toTheLeftOfRect.topLeft(), toTheLeftOfRect.bottomLeft()); + } + painter.save(); + painter.setPen(QPen(Qt::black, 3)); + painter.drawLine(line); + painter.restore(); + } + } #endif } void GroupView::resizeEvent(QResizeEvent *event) { - int newItemsPerRow = calculateItemsPerRow(); - if(newItemsPerRow != m_currentItemsPerRow) - { - m_currentCursorColumn = -1; - m_currentItemsPerRow = newItemsPerRow; - updateGeometries(); - } - else - { - updateScrollbar(); - } + int newItemsPerRow = calculateItemsPerRow(); + if(newItemsPerRow != m_currentItemsPerRow) + { + m_currentCursorColumn = -1; + m_currentItemsPerRow = newItemsPerRow; + updateGeometries(); + } + else + { + updateScrollbar(); + } } void GroupView::dragEnterEvent(QDragEnterEvent *event) { - if (!isDragEventAccepted(event)) - { - return; - } - m_lastDragPosition = event->pos() + offset(); - viewport()->update(); - event->accept(); + if (!isDragEventAccepted(event)) + { + return; + } + m_lastDragPosition = event->pos() + offset(); + viewport()->update(); + event->accept(); } void GroupView::dragMoveEvent(QDragMoveEvent *event) { - if (!isDragEventAccepted(event)) - { - return; - } - m_lastDragPosition = event->pos() + offset(); - viewport()->update(); - event->accept(); + if (!isDragEventAccepted(event)) + { + return; + } + m_lastDragPosition = event->pos() + offset(); + viewport()->update(); + event->accept(); } void GroupView::dragLeaveEvent(QDragLeaveEvent *event) { - m_lastDragPosition = QPoint(); - viewport()->update(); + m_lastDragPosition = QPoint(); + viewport()->update(); } void GroupView::dropEvent(QDropEvent *event) { - m_lastDragPosition = QPoint(); - - stopAutoScroll(); - setState(NoState); - - if (event->source() == this) - { - if(event->possibleActions() & Qt::MoveAction) - { - QPair<VisualGroup *, int> dropPos = rowDropPos(event->pos() + offset()); - const VisualGroup *category = dropPos.first; - const int row = dropPos.second; - - if (row == -1) - { - viewport()->update(); - return; - } - - const QString categoryText = category->text; - if (model()->dropMimeData(event->mimeData(), Qt::MoveAction, row, 0, QModelIndex())) - { - model()->setData(model()->index(row, 0), categoryText, - GroupViewRoles::GroupRole); - event->setDropAction(Qt::MoveAction); - event->accept(); - } - updateGeometries(); - viewport()->update(); - } - } - auto mimedata = event->mimeData(); - - // check if the action is supported - if (!mimedata) - { - return; - } - - // files dropped from outside? - if (mimedata->hasUrls()) - { - auto urls = mimedata->urls(); - event->accept(); - emit droppedURLs(urls); - } + m_lastDragPosition = QPoint(); + + stopAutoScroll(); + setState(NoState); + + if (event->source() == this) + { + if(event->possibleActions() & Qt::MoveAction) + { + QPair<VisualGroup *, int> dropPos = rowDropPos(event->pos() + offset()); + const VisualGroup *category = dropPos.first; + const int row = dropPos.second; + + if (row == -1) + { + viewport()->update(); + return; + } + + const QString categoryText = category->text; + if (model()->dropMimeData(event->mimeData(), Qt::MoveAction, row, 0, QModelIndex())) + { + model()->setData(model()->index(row, 0), categoryText, + GroupViewRoles::GroupRole); + event->setDropAction(Qt::MoveAction); + event->accept(); + } + updateGeometries(); + viewport()->update(); + } + } + auto mimedata = event->mimeData(); + + // check if the action is supported + if (!mimedata) + { + return; + } + + // files dropped from outside? + if (mimedata->hasUrls()) + { + auto urls = mimedata->urls(); + event->accept(); + emit droppedURLs(urls); + } } void GroupView::startDrag(Qt::DropActions supportedActions) { - QModelIndexList indexes = selectionModel()->selectedIndexes(); - if(indexes.count() == 0) - return; - - QMimeData *data = model()->mimeData(indexes); - if (!data) - { - return; - } - QRect rect; - QPixmap pixmap = renderToPixmap(indexes, &rect); - //rect.translate(offset()); - // rect.adjust(horizontalOffset(), verticalOffset(), 0, 0); - QDrag *drag = new QDrag(this); - drag->setPixmap(pixmap); - drag->setMimeData(data); - Qt::DropAction defaultDropAction = Qt::IgnoreAction; - if (this->defaultDropAction() != Qt::IgnoreAction && - (supportedActions & this->defaultDropAction())) - { - defaultDropAction = this->defaultDropAction(); - } - if (drag->exec(supportedActions, defaultDropAction) == Qt::MoveAction) - { - const QItemSelection selection = selectionModel()->selection(); - - for (auto it = selection.constBegin(); it != selection.constEnd(); ++it) - { - QModelIndex parent = (*it).parent(); - if ((*it).left() != 0) - { - continue; - } - if ((*it).right() != (model()->columnCount(parent) - 1)) - { - continue; - } - int count = (*it).bottom() - (*it).top() + 1; - model()->removeRows((*it).top(), count, parent); - } - } + QModelIndexList indexes = selectionModel()->selectedIndexes(); + if(indexes.count() == 0) + return; + + QMimeData *data = model()->mimeData(indexes); + if (!data) + { + return; + } + QRect rect; + QPixmap pixmap = renderToPixmap(indexes, &rect); + //rect.translate(offset()); + // rect.adjust(horizontalOffset(), verticalOffset(), 0, 0); + QDrag *drag = new QDrag(this); + drag->setPixmap(pixmap); + drag->setMimeData(data); + Qt::DropAction defaultDropAction = Qt::IgnoreAction; + if (this->defaultDropAction() != Qt::IgnoreAction && + (supportedActions & this->defaultDropAction())) + { + defaultDropAction = this->defaultDropAction(); + } + if (drag->exec(supportedActions, defaultDropAction) == Qt::MoveAction) + { + const QItemSelection selection = selectionModel()->selection(); + + for (auto it = selection.constBegin(); it != selection.constEnd(); ++it) + { + QModelIndex parent = (*it).parent(); + if ((*it).left() != 0) + { + continue; + } + if ((*it).right() != (model()->columnCount(parent) - 1)) + { + continue; + } + int count = (*it).bottom() - (*it).top() + 1; + model()->removeRows((*it).top(), count, parent); + } + } } QRect GroupView::visualRect(const QModelIndex &index) const { - return geometryRect(index).translated(-offset()); + return geometryRect(index).translated(-offset()); } QRect GroupView::geometryRect(const QModelIndex &index) const { - if (!index.isValid() || isIndexHidden(index) || index.column() > 0) - { - return QRect(); - } + if (!index.isValid() || isIndexHidden(index) || index.column() > 0) + { + return QRect(); + } - int row = index.row(); - if(geometryCache.contains(row)) - { - return *geometryCache[row]; - } + int row = index.row(); + if(geometryCache.contains(row)) + { + return *geometryCache[row]; + } - const VisualGroup *cat = category(index); - QPair<int, int> pos = cat->positionOf(index); - int x = pos.first; - // int y = pos.second; + const VisualGroup *cat = category(index); + QPair<int, int> pos = cat->positionOf(index); + int x = pos.first; + // int y = pos.second; - QRect out; - out.setTop(cat->verticalPosition() + cat->headerHeight() + 5 + cat->rowTopOf(index)); - out.setLeft(m_spacing + x * (itemWidth() + m_spacing)); - out.setSize(itemDelegate()->sizeHint(viewOptions(), index)); - geometryCache.insert(row, new QRect(out)); - return out; + QRect out; + out.setTop(cat->verticalPosition() + cat->headerHeight() + 5 + cat->rowTopOf(index)); + out.setLeft(m_spacing + x * (itemWidth() + m_spacing)); + out.setSize(itemDelegate()->sizeHint(viewOptions(), index)); + geometryCache.insert(row, new QRect(out)); + return out; } QModelIndex GroupView::indexAt(const QPoint &point) const { - const_cast<GroupView*>(this)->executeDelayedItemsLayout(); + const_cast<GroupView*>(this)->executeDelayedItemsLayout(); - for (int i = 0; i < model()->rowCount(); ++i) - { - QModelIndex index = model()->index(i, 0); - if (visualRect(index).contains(point)) - { - return index; - } - } - return QModelIndex(); + for (int i = 0; i < model()->rowCount(); ++i) + { + QModelIndex index = model()->index(i, 0); + if (visualRect(index).contains(point)) + { + return index; + } + } + return QModelIndex(); } void GroupView::setSelection(const QRect &rect, - const QItemSelectionModel::SelectionFlags commands) + const QItemSelectionModel::SelectionFlags commands) { - for (int i = 0; i < model()->rowCount(); ++i) - { - QModelIndex index = model()->index(i, 0); - QRect itemRect = visualRect(index); - if (itemRect.intersects(rect)) - { - selectionModel()->select(index, commands); - update(itemRect.translated(-offset())); - } - } + for (int i = 0; i < model()->rowCount(); ++i) + { + QModelIndex index = model()->index(i, 0); + QRect itemRect = visualRect(index); + if (itemRect.intersects(rect)) + { + selectionModel()->select(index, commands); + update(itemRect.translated(-offset())); + } + } } QPixmap GroupView::renderToPixmap(const QModelIndexList &indices, QRect *r) const { - Q_ASSERT(r); - auto paintPairs = draggablePaintPairs(indices, r); - if (paintPairs.isEmpty()) - { - return QPixmap(); - } - QPixmap pixmap(r->size()); - pixmap.fill(Qt::transparent); - QPainter painter(&pixmap); - QStyleOptionViewItem option = viewOptions(); - option.state |= QStyle::State_Selected; - for (int j = 0; j < paintPairs.count(); ++j) - { - option.rect = paintPairs.at(j).first.translated(-r->topLeft()); - const QModelIndex ¤t = paintPairs.at(j).second; - itemDelegate()->paint(&painter, option, current); - } - return pixmap; + Q_ASSERT(r); + auto paintPairs = draggablePaintPairs(indices, r); + if (paintPairs.isEmpty()) + { + return QPixmap(); + } + QPixmap pixmap(r->size()); + pixmap.fill(Qt::transparent); + QPainter painter(&pixmap); + QStyleOptionViewItem option = viewOptions(); + option.state |= QStyle::State_Selected; + for (int j = 0; j < paintPairs.count(); ++j) + { + option.rect = paintPairs.at(j).first.translated(-r->topLeft()); + const QModelIndex ¤t = paintPairs.at(j).second; + itemDelegate()->paint(&painter, option, current); + } + return pixmap; } QList<QPair<QRect, QModelIndex>> GroupView::draggablePaintPairs(const QModelIndexList &indices, - QRect *r) const + QRect *r) const { - Q_ASSERT(r); - QRect &rect = *r; - QList<QPair<QRect, QModelIndex>> ret; - for (int i = 0; i < indices.count(); ++i) - { - const QModelIndex &index = indices.at(i); - const QRect current = geometryRect(index); - ret += qMakePair(current, index); - rect |= current; - } - return ret; + Q_ASSERT(r); + QRect &rect = *r; + QList<QPair<QRect, QModelIndex>> ret; + for (int i = 0; i < indices.count(); ++i) + { + const QModelIndex &index = indices.at(i); + const QRect current = geometryRect(index); + ret += qMakePair(current, index); + rect |= current; + } + return ret; } bool GroupView::isDragEventAccepted(QDropEvent *event) { - return true; + return true; } QPair<VisualGroup *, int> GroupView::rowDropPos(const QPoint &pos) { - return qMakePair<VisualGroup*, int>(nullptr, -1); + return qMakePair<VisualGroup*, int>(nullptr, -1); } QPoint GroupView::offset() const { - return QPoint(horizontalOffset(), verticalOffset()); + return QPoint(horizontalOffset(), verticalOffset()); } QRegion GroupView::visualRegionForSelection(const QItemSelection &selection) const { - QRegion region; - for (auto &range : selection) - { - int start_row = range.top(); - int end_row = range.bottom(); - for (int row = start_row; row <= end_row; ++row) - { - int start_column = range.left(); - int end_column = range.right(); - for (int column = start_column; column <= end_column; ++column) - { - QModelIndex index = model()->index(row, column, rootIndex()); - region += visualRect(index); // OK - } - } - } - return region; + QRegion region; + for (auto &range : selection) + { + int start_row = range.top(); + int end_row = range.bottom(); + for (int row = start_row; row <= end_row; ++row) + { + int start_column = range.left(); + int end_column = range.right(); + for (int column = start_column; column <= end_column; ++column) + { + QModelIndex index = model()->index(row, column, rootIndex()); + region += visualRect(index); // OK + } + } + } + return region; } QModelIndex GroupView::moveCursor(QAbstractItemView::CursorAction cursorAction, - Qt::KeyboardModifiers modifiers) -{ - auto current = currentIndex(); - if(!current.isValid()) - { - return current; - } - auto cat = category(current); - int group_index = m_groups.indexOf(cat); - if(group_index < 0) - return current; - - auto real_group = m_groups[group_index]; - int beginning_row = 0; - for(auto group: m_groups) - { - if(group == real_group) - break; - beginning_row += group->numRows(); - } - - QPair<int, int> pos = cat->positionOf(current); - int column = pos.first; - int row = pos.second; - if(m_currentCursorColumn < 0) - { - m_currentCursorColumn = column; - } - switch(cursorAction) - { - case MoveUp: - { - if(row == 0) - { - int prevgroupindex = group_index-1; - while(prevgroupindex >= 0) - { - auto prevgroup = m_groups[prevgroupindex]; - if(prevgroup->collapsed) - { - prevgroupindex--; - continue; - } - int newRow = prevgroup->numRows() - 1; - int newRowSize = prevgroup->rows[newRow].size(); - int newColumn = m_currentCursorColumn; - if (m_currentCursorColumn >= newRowSize) - { - newColumn = newRowSize - 1; - } - return prevgroup->rows[newRow][newColumn]; - } - } - else - { - int newRow = row - 1; - int newRowSize = cat->rows[newRow].size(); - int newColumn = m_currentCursorColumn; - if (m_currentCursorColumn >= newRowSize) - { - newColumn = newRowSize - 1; - } - return cat->rows[newRow][newColumn]; - } - return current; - } - case MoveDown: - { - if(row == cat->rows.size() - 1) - { - int nextgroupindex = group_index+1; - while (nextgroupindex < m_groups.size()) - { - auto nextgroup = m_groups[nextgroupindex]; - if(nextgroup->collapsed) - { - nextgroupindex++; - continue; - } - int newRowSize = nextgroup->rows[0].size(); - int newColumn = m_currentCursorColumn; - if (m_currentCursorColumn >= newRowSize) - { - newColumn = newRowSize - 1; - } - return nextgroup->rows[0][newColumn]; - } - } - else - { - int newRow = row + 1; - int newRowSize = cat->rows[newRow].size(); - int newColumn = m_currentCursorColumn; - if (m_currentCursorColumn >= newRowSize) - { - newColumn = newRowSize - 1; - } - return cat->rows[newRow][newColumn]; - } - return current; - } - case MoveLeft: - { - if(column > 0) - { - m_currentCursorColumn = column - 1; - return cat->rows[row][column - 1]; - } - // TODO: moving to previous line - return current; - } - case MoveRight: - { - if(column < cat->rows[row].size() - 1) - { - m_currentCursorColumn = column + 1; - return cat->rows[row][column + 1]; - } - // TODO: moving to next line - return current; - } - case MoveHome: - { - m_currentCursorColumn = 0; - return cat->rows[row][0]; - } - case MoveEnd: - { - auto last = cat->rows[row].size() - 1; - m_currentCursorColumn = last; - return cat->rows[row][last]; - } - default: - break; - } - return current; + Qt::KeyboardModifiers modifiers) +{ + auto current = currentIndex(); + if(!current.isValid()) + { + return current; + } + auto cat = category(current); + int group_index = m_groups.indexOf(cat); + if(group_index < 0) + return current; + + auto real_group = m_groups[group_index]; + int beginning_row = 0; + for(auto group: m_groups) + { + if(group == real_group) + break; + beginning_row += group->numRows(); + } + + QPair<int, int> pos = cat->positionOf(current); + int column = pos.first; + int row = pos.second; + if(m_currentCursorColumn < 0) + { + m_currentCursorColumn = column; + } + switch(cursorAction) + { + case MoveUp: + { + if(row == 0) + { + int prevgroupindex = group_index-1; + while(prevgroupindex >= 0) + { + auto prevgroup = m_groups[prevgroupindex]; + if(prevgroup->collapsed) + { + prevgroupindex--; + continue; + } + int newRow = prevgroup->numRows() - 1; + int newRowSize = prevgroup->rows[newRow].size(); + int newColumn = m_currentCursorColumn; + if (m_currentCursorColumn >= newRowSize) + { + newColumn = newRowSize - 1; + } + return prevgroup->rows[newRow][newColumn]; + } + } + else + { + int newRow = row - 1; + int newRowSize = cat->rows[newRow].size(); + int newColumn = m_currentCursorColumn; + if (m_currentCursorColumn >= newRowSize) + { + newColumn = newRowSize - 1; + } + return cat->rows[newRow][newColumn]; + } + return current; + } + case MoveDown: + { + if(row == cat->rows.size() - 1) + { + int nextgroupindex = group_index+1; + while (nextgroupindex < m_groups.size()) + { + auto nextgroup = m_groups[nextgroupindex]; + if(nextgroup->collapsed) + { + nextgroupindex++; + continue; + } + int newRowSize = nextgroup->rows[0].size(); + int newColumn = m_currentCursorColumn; + if (m_currentCursorColumn >= newRowSize) + { + newColumn = newRowSize - 1; + } + return nextgroup->rows[0][newColumn]; + } + } + else + { + int newRow = row + 1; + int newRowSize = cat->rows[newRow].size(); + int newColumn = m_currentCursorColumn; + if (m_currentCursorColumn >= newRowSize) + { + newColumn = newRowSize - 1; + } + return cat->rows[newRow][newColumn]; + } + return current; + } + case MoveLeft: + { + if(column > 0) + { + m_currentCursorColumn = column - 1; + return cat->rows[row][column - 1]; + } + // TODO: moving to previous line + return current; + } + case MoveRight: + { + if(column < cat->rows[row].size() - 1) + { + m_currentCursorColumn = column + 1; + return cat->rows[row][column + 1]; + } + // TODO: moving to next line + return current; + } + case MoveHome: + { + m_currentCursorColumn = 0; + return cat->rows[row][0]; + } + case MoveEnd: + { + auto last = cat->rows[row].size() - 1; + m_currentCursorColumn = last; + return cat->rows[row][last]; + } + default: + break; + } + return current; } int GroupView::horizontalOffset() const { - return horizontalScrollBar()->value(); + return horizontalScrollBar()->value(); } int GroupView::verticalOffset() const { - return verticalScrollBar()->value(); + return verticalScrollBar()->value(); } void GroupView::scrollContentsBy(int dx, int dy) { - scrollDirtyRegion(dx, dy); - viewport()->scroll(dx, dy); + scrollDirtyRegion(dx, dy); + viewport()->scroll(dx, dy); } void GroupView::scrollTo(const QModelIndex &index, ScrollHint hint) { - if (!index.isValid()) - return; + if (!index.isValid()) + return; - const QRect rect = visualRect(index); - if (hint == EnsureVisible && viewport()->rect().contains(rect)) - { - viewport()->update(rect); - return; - } + const QRect rect = visualRect(index); + if (hint == EnsureVisible && viewport()->rect().contains(rect)) + { + viewport()->update(rect); + return; + } - verticalScrollBar()->setValue(verticalScrollToValue(index, rect, hint)); + verticalScrollBar()->setValue(verticalScrollToValue(index, rect, hint)); } int GroupView::verticalScrollToValue(const QModelIndex &index, const QRect &rect, QListView::ScrollHint hint) const { - const QRect area = viewport()->rect(); - const bool above = (hint == QListView::EnsureVisible && rect.top() < area.top()); - const bool below = (hint == QListView::EnsureVisible && rect.bottom() > area.bottom()); - - int verticalValue = verticalScrollBar()->value(); - QRect adjusted = rect.adjusted(-spacing(), -spacing(), spacing(), spacing()); - if (hint == QListView::PositionAtTop || above) - verticalValue += adjusted.top(); - else if (hint == QListView::PositionAtBottom || below) - verticalValue += qMin(adjusted.top(), adjusted.bottom() - area.height() + 1); - else if (hint == QListView::PositionAtCenter) - verticalValue += adjusted.top() - ((area.height() - adjusted.height()) / 2); - return verticalValue; + const QRect area = viewport()->rect(); + const bool above = (hint == QListView::EnsureVisible && rect.top() < area.top()); + const bool below = (hint == QListView::EnsureVisible && rect.bottom() > area.bottom()); + + int verticalValue = verticalScrollBar()->value(); + QRect adjusted = rect.adjusted(-spacing(), -spacing(), spacing(), spacing()); + if (hint == QListView::PositionAtTop || above) + verticalValue += adjusted.top(); + else if (hint == QListView::PositionAtBottom || below) + verticalValue += qMin(adjusted.top(), adjusted.bottom() - area.height() + 1); + else if (hint == QListView::PositionAtCenter) + verticalValue += adjusted.top() - ((area.height() - adjusted.height()) / 2); + return verticalValue; } diff --git a/application/groupview/GroupView.h b/application/groupview/GroupView.h index 07c65bb5..ceb602fc 100644 --- a/application/groupview/GroupView.h +++ b/application/groupview/GroupView.h @@ -23,126 +23,126 @@ struct GroupViewRoles { - enum - { - GroupRole = Qt::UserRole, - ProgressValueRole, - ProgressMaximumRole - }; + enum + { + GroupRole = Qt::UserRole, + ProgressValueRole, + ProgressMaximumRole + }; }; class GroupView : public QAbstractItemView { - Q_OBJECT + Q_OBJECT public: - GroupView(QWidget *parent = 0); - ~GroupView(); + GroupView(QWidget *parent = 0); + ~GroupView(); - void setModel(QAbstractItemModel *model) override; + void setModel(QAbstractItemModel *model) override; - /// return geometry rectangle occupied by the specified model item - QRect geometryRect(const QModelIndex &index) const; - /// return visual rectangle occupied by the specified model item - virtual QRect visualRect(const QModelIndex &index) const override; - /// get the model index at the specified visual point - virtual QModelIndex indexAt(const QPoint &point) const override; - QString groupNameAt(const QPoint &point); - void setSelection(const QRect &rect, - const QItemSelectionModel::SelectionFlags commands) override; + /// return geometry rectangle occupied by the specified model item + QRect geometryRect(const QModelIndex &index) const; + /// return visual rectangle occupied by the specified model item + virtual QRect visualRect(const QModelIndex &index) const override; + /// get the model index at the specified visual point + virtual QModelIndex indexAt(const QPoint &point) const override; + QString groupNameAt(const QPoint &point); + void setSelection(const QRect &rect, + const QItemSelectionModel::SelectionFlags commands) override; - virtual int horizontalOffset() const override; - virtual int verticalOffset() const override; - virtual void scrollContentsBy(int dx, int dy) override; - virtual void scrollTo(const QModelIndex &index, ScrollHint hint = EnsureVisible) override; + virtual int horizontalOffset() const override; + virtual int verticalOffset() const override; + virtual void scrollContentsBy(int dx, int dy) override; + virtual void scrollTo(const QModelIndex &index, ScrollHint hint = EnsureVisible) override; - virtual QModelIndex moveCursor(CursorAction cursorAction, - Qt::KeyboardModifiers modifiers) override; + virtual QModelIndex moveCursor(CursorAction cursorAction, + Qt::KeyboardModifiers modifiers) override; - virtual QRegion visualRegionForSelection(const QItemSelection &selection) const override; + virtual QRegion visualRegionForSelection(const QItemSelection &selection) const override; - int spacing() const - { - return m_spacing; - }; + int spacing() const + { + return m_spacing; + }; public slots: - virtual void updateGeometries() override; + virtual void updateGeometries() override; protected slots: - virtual void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, - const QVector<int> &roles) override; - virtual void rowsInserted(const QModelIndex &parent, int start, int end) override; - virtual void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) override; - void modelReset(); - void rowsRemoved(); + virtual void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, + const QVector<int> &roles) override; + virtual void rowsInserted(const QModelIndex &parent, int start, int end) override; + virtual void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) override; + void modelReset(); + void rowsRemoved(); signals: - void droppedURLs(QList<QUrl> urls); + void droppedURLs(QList<QUrl> urls); protected: - virtual bool isIndexHidden(const QModelIndex &index) const override; - void mousePressEvent(QMouseEvent *event) override; - void mouseMoveEvent(QMouseEvent *event) override; - void mouseReleaseEvent(QMouseEvent *event) override; - void mouseDoubleClickEvent(QMouseEvent *event) override; - void paintEvent(QPaintEvent *event) override; - void resizeEvent(QResizeEvent *event) override; + virtual bool isIndexHidden(const QModelIndex &index) const override; + void mousePressEvent(QMouseEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; + void mouseDoubleClickEvent(QMouseEvent *event) override; + void paintEvent(QPaintEvent *event) override; + void resizeEvent(QResizeEvent *event) override; - void dragEnterEvent(QDragEnterEvent *event) override; - void dragMoveEvent(QDragMoveEvent *event) override; - void dragLeaveEvent(QDragLeaveEvent *event) override; - void dropEvent(QDropEvent *event) override; + void dragEnterEvent(QDragEnterEvent *event) override; + void dragMoveEvent(QDragMoveEvent *event) override; + void dragLeaveEvent(QDragLeaveEvent *event) override; + void dropEvent(QDropEvent *event) override; - void startDrag(Qt::DropActions supportedActions) override; + void startDrag(Qt::DropActions supportedActions) override; - void updateScrollbar(); + void updateScrollbar(); private: - friend struct VisualGroup; - QList<VisualGroup *> m_groups; - - // geometry - int m_leftMargin = 5; - int m_rightMargin = 5; - int m_bottomMargin = 5; - int m_categoryMargin = 5; - int m_spacing = 5; - int m_itemWidth = 100; - int m_currentItemsPerRow = -1; - int m_currentCursorColumn= -1; - mutable QCache<int, QRect> geometryCache; - - // point where the currently active mouse action started in geometry coordinates - QPoint m_pressedPosition; - QPersistentModelIndex m_pressedIndex; - bool m_pressedAlreadySelected; - VisualGroup *m_pressedCategory; - QItemSelectionModel::SelectionFlag m_ctrlDragSelectionFlag; - QPoint m_lastDragPosition; - - VisualGroup *category(const QModelIndex &index) const; - VisualGroup *category(const QString &cat) const; - VisualGroup *categoryAt(const QPoint &pos, VisualGroup::HitResults & result) const; - - int itemsPerRow() const - { - return m_currentItemsPerRow; - }; - int contentWidth() const; + friend struct VisualGroup; + QList<VisualGroup *> m_groups; + + // geometry + int m_leftMargin = 5; + int m_rightMargin = 5; + int m_bottomMargin = 5; + int m_categoryMargin = 5; + int m_spacing = 5; + int m_itemWidth = 100; + int m_currentItemsPerRow = -1; + int m_currentCursorColumn= -1; + mutable QCache<int, QRect> geometryCache; + + // point where the currently active mouse action started in geometry coordinates + QPoint m_pressedPosition; + QPersistentModelIndex m_pressedIndex; + bool m_pressedAlreadySelected; + VisualGroup *m_pressedCategory; + QItemSelectionModel::SelectionFlag m_ctrlDragSelectionFlag; + QPoint m_lastDragPosition; + + VisualGroup *category(const QModelIndex &index) const; + VisualGroup *category(const QString &cat) const; + VisualGroup *categoryAt(const QPoint &pos, VisualGroup::HitResults & result) const; + + int itemsPerRow() const + { + return m_currentItemsPerRow; + }; + int contentWidth() const; private: /* methods */ - int itemWidth() const; - int calculateItemsPerRow() const; - int verticalScrollToValue(const QModelIndex &index, const QRect &rect, - QListView::ScrollHint hint) const; - QPixmap renderToPixmap(const QModelIndexList &indices, QRect *r) const; - QList<QPair<QRect, QModelIndex>> draggablePaintPairs(const QModelIndexList &indices, - QRect *r) const; + int itemWidth() const; + int calculateItemsPerRow() const; + int verticalScrollToValue(const QModelIndex &index, const QRect &rect, + QListView::ScrollHint hint) const; + QPixmap renderToPixmap(const QModelIndexList &indices, QRect *r) const; + QList<QPair<QRect, QModelIndex>> draggablePaintPairs(const QModelIndexList &indices, + QRect *r) const; - bool isDragEventAccepted(QDropEvent *event); + bool isDragEventAccepted(QDropEvent *event); - QPair<VisualGroup *, int> rowDropPos(const QPoint &pos); + QPair<VisualGroup *, int> rowDropPos(const QPoint &pos); - QPoint offset() const; + QPoint offset() const; }; diff --git a/application/groupview/GroupedProxyModel.cpp b/application/groupview/GroupedProxyModel.cpp index c13f2411..5617a1ee 100644 --- a/application/groupview/GroupedProxyModel.cpp +++ b/application/groupview/GroupedProxyModel.cpp @@ -24,25 +24,25 @@ GroupedProxyModel::GroupedProxyModel(QObject *parent) : QSortFilterProxyModel(pa bool GroupedProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const { - const QString leftCategory = left.data(GroupViewRoles::GroupRole).toString(); - const QString rightCategory = right.data(GroupViewRoles::GroupRole).toString(); - if (leftCategory == rightCategory) - { - return subSortLessThan(left, right); - } - else - { - // FIXME: real group sorting happens in GroupView::updateGeometries(), see LocaleString - auto result = leftCategory.localeAwareCompare(rightCategory); - if(result == 0) - { - return subSortLessThan(left, right); - } - return result < 0; - } + const QString leftCategory = left.data(GroupViewRoles::GroupRole).toString(); + const QString rightCategory = right.data(GroupViewRoles::GroupRole).toString(); + if (leftCategory == rightCategory) + { + return subSortLessThan(left, right); + } + else + { + // FIXME: real group sorting happens in GroupView::updateGeometries(), see LocaleString + auto result = leftCategory.localeAwareCompare(rightCategory); + if(result == 0) + { + return subSortLessThan(left, right); + } + return result < 0; + } } bool GroupedProxyModel::subSortLessThan(const QModelIndex &left, const QModelIndex &right) const { - return left.row() < right.row(); + return left.row() < right.row(); } diff --git a/application/groupview/GroupedProxyModel.h b/application/groupview/GroupedProxyModel.h index babeb308..e1c51c0f 100644 --- a/application/groupview/GroupedProxyModel.h +++ b/application/groupview/GroupedProxyModel.h @@ -19,12 +19,12 @@ class GroupedProxyModel : public QSortFilterProxyModel { - Q_OBJECT + Q_OBJECT public: - GroupedProxyModel(QObject *parent = 0); + GroupedProxyModel(QObject *parent = 0); protected: - virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const override; - virtual bool subSortLessThan(const QModelIndex &left, const QModelIndex &right) const; + virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const override; + virtual bool subSortLessThan(const QModelIndex &left, const QModelIndex &right) const; }; diff --git a/application/groupview/InstanceDelegate.cpp b/application/groupview/InstanceDelegate.cpp index 0855c04a..42860aef 100644 --- a/application/groupview/InstanceDelegate.cpp +++ b/application/groupview/InstanceDelegate.cpp @@ -27,25 +27,25 @@ // Origin: Qt static void viewItemTextLayout(QTextLayout &textLayout, int lineWidth, qreal &height, - qreal &widthUsed) + qreal &widthUsed) { - height = 0; - widthUsed = 0; - textLayout.beginLayout(); - QString str = textLayout.text(); - while (true) - { - QTextLine line = textLayout.createLine(); - if (!line.isValid()) - break; - if (line.textLength() == 0) - break; - line.setLineWidth(lineWidth); - line.setPosition(QPointF(0, height)); - height += line.height(); - widthUsed = qMax(widthUsed, line.naturalTextWidth()); - } - textLayout.endLayout(); + height = 0; + widthUsed = 0; + textLayout.beginLayout(); + QString str = textLayout.text(); + while (true) + { + QTextLine line = textLayout.createLine(); + if (!line.isValid()) + break; + if (line.textLength() == 0) + break; + line.setLineWidth(lineWidth); + line.setPosition(QPointF(0, height)); + height += line.height(); + widthUsed = qMax(widthUsed, line.naturalTextWidth()); + } + textLayout.endLayout(); } ListViewDelegate::ListViewDelegate(QObject *parent) : QStyledItemDelegate(parent) @@ -53,291 +53,291 @@ ListViewDelegate::ListViewDelegate(QObject *parent) : QStyledItemDelegate(parent } void drawSelectionRect(QPainter *painter, const QStyleOptionViewItem &option, - const QRect &rect) + const QRect &rect) { - if ((option.state & QStyle::State_Selected)) - painter->fillRect(rect, option.palette.brush(QPalette::Highlight)); - else - { - QColor backgroundColor = option.palette.color(QPalette::Background); - backgroundColor.setAlpha(160); - painter->fillRect(rect, QBrush(backgroundColor)); - } + if ((option.state & QStyle::State_Selected)) + painter->fillRect(rect, option.palette.brush(QPalette::Highlight)); + else + { + QColor backgroundColor = option.palette.color(QPalette::Background); + backgroundColor.setAlpha(160); + painter->fillRect(rect, QBrush(backgroundColor)); + } } void drawFocusRect(QPainter *painter, const QStyleOptionViewItem &option, const QRect &rect) { - if (!(option.state & QStyle::State_HasFocus)) - return; - QStyleOptionFocusRect opt; - opt.direction = option.direction; - opt.fontMetrics = option.fontMetrics; - opt.palette = option.palette; - opt.rect = rect; - // opt.state = option.state | QStyle::State_KeyboardFocusChange | - // QStyle::State_Item; - auto col = option.state & QStyle::State_Selected ? QPalette::Highlight : QPalette::Base; - opt.backgroundColor = option.palette.color(col); - // Apparently some widget styles expect this hint to not be set - painter->setRenderHint(QPainter::Antialiasing, false); - - QStyle *style = option.widget ? option.widget->style() : QApplication::style(); - - style->drawPrimitive(QStyle::PE_FrameFocusRect, &opt, painter, option.widget); - - painter->setRenderHint(QPainter::Antialiasing); + if (!(option.state & QStyle::State_HasFocus)) + return; + QStyleOptionFocusRect opt; + opt.direction = option.direction; + opt.fontMetrics = option.fontMetrics; + opt.palette = option.palette; + opt.rect = rect; + // opt.state = option.state | QStyle::State_KeyboardFocusChange | + // QStyle::State_Item; + auto col = option.state & QStyle::State_Selected ? QPalette::Highlight : QPalette::Base; + opt.backgroundColor = option.palette.color(col); + // Apparently some widget styles expect this hint to not be set + painter->setRenderHint(QPainter::Antialiasing, false); + + QStyle *style = option.widget ? option.widget->style() : QApplication::style(); + + style->drawPrimitive(QStyle::PE_FrameFocusRect, &opt, painter, option.widget); + + painter->setRenderHint(QPainter::Antialiasing); } // TODO this can be made a lot prettier void drawProgressOverlay(QPainter *painter, const QStyleOptionViewItem &option, - const int value, const int maximum) + const int value, const int maximum) { - if (maximum == 0 || value == maximum) - { - return; - } + if (maximum == 0 || value == maximum) + { + return; + } - painter->save(); + painter->save(); - qreal percent = (qreal)value / (qreal)maximum; - QColor color = option.palette.color(QPalette::Dark); - color.setAlphaF(0.70f); - painter->setBrush(color); - painter->setPen(QPen(QBrush(), 0)); - painter->drawPie(option.rect, 90 * 16, -percent * 360 * 16); + qreal percent = (qreal)value / (qreal)maximum; + QColor color = option.palette.color(QPalette::Dark); + color.setAlphaF(0.70f); + painter->setBrush(color); + painter->setPen(QPen(QBrush(), 0)); + painter->drawPie(option.rect, 90 * 16, -percent * 360 * 16); - painter->restore(); + painter->restore(); } void drawBadges(QPainter *painter, const QStyleOptionViewItem &option, BaseInstance *instance, QIcon::Mode mode, QIcon::State state) { - QList<QString> pixmaps; - if (instance->isRunning()) - { - pixmaps.append("status-running"); - } - else if (instance->hasCrashed() || instance->hasVersionBroken()) - { - pixmaps.append("status-bad"); - } - if (instance->hasUpdateAvailable()) - { - pixmaps.append("checkupdate"); - } - - static const int itemSide = 24; - static const int spacing = 1; - const int itemsPerRow = qMax(1, qFloor(double(option.rect.width() + spacing) / double(itemSide + spacing))); - const int rows = qCeil((double)pixmaps.size() / (double)itemsPerRow); - QListIterator<QString> it(pixmaps); - painter->translate(option.rect.topLeft()); - for (int y = 0; y < rows; ++y) - { - for (int x = 0; x < itemsPerRow; ++x) - { - if (!it.hasNext()) - { - return; - } - // FIXME: inject this. - auto icon = XdgIcon::fromTheme(it.next()); - // opt.icon.paint(painter, iconbox, Qt::AlignCenter, mode, state); - const QPixmap pixmap; - // itemSide - QRect badgeRect( - option.rect.width() - x * itemSide + qMax(x - 1, 0) * spacing - itemSide, - y * itemSide + qMax(y - 1, 0) * spacing, - itemSide, - itemSide - ); - icon.paint(painter, badgeRect, Qt::AlignCenter, mode, state); - } - } - painter->translate(-option.rect.topLeft()); + QList<QString> pixmaps; + if (instance->isRunning()) + { + pixmaps.append("status-running"); + } + else if (instance->hasCrashed() || instance->hasVersionBroken()) + { + pixmaps.append("status-bad"); + } + if (instance->hasUpdateAvailable()) + { + pixmaps.append("checkupdate"); + } + + static const int itemSide = 24; + static const int spacing = 1; + const int itemsPerRow = qMax(1, qFloor(double(option.rect.width() + spacing) / double(itemSide + spacing))); + const int rows = qCeil((double)pixmaps.size() / (double)itemsPerRow); + QListIterator<QString> it(pixmaps); + painter->translate(option.rect.topLeft()); + for (int y = 0; y < rows; ++y) + { + for (int x = 0; x < itemsPerRow; ++x) + { + if (!it.hasNext()) + { + return; + } + // FIXME: inject this. + auto icon = XdgIcon::fromTheme(it.next()); + // opt.icon.paint(painter, iconbox, Qt::AlignCenter, mode, state); + const QPixmap pixmap; + // itemSide + QRect badgeRect( + option.rect.width() - x * itemSide + qMax(x - 1, 0) * spacing - itemSide, + y * itemSide + qMax(y - 1, 0) * spacing, + itemSide, + itemSide + ); + icon.paint(painter, badgeRect, Qt::AlignCenter, mode, state); + } + } + painter->translate(-option.rect.topLeft()); } static QSize viewItemTextSize(const QStyleOptionViewItem *option) { - QStyle *style = option->widget ? option->widget->style() : QApplication::style(); - QTextOption textOption; - textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); - QTextLayout textLayout; - textLayout.setTextOption(textOption); - textLayout.setFont(option->font); - textLayout.setText(option->text); - const int textMargin = - style->pixelMetric(QStyle::PM_FocusFrameHMargin, option, option->widget) + 1; - QRect bounds(0, 0, 100 - 2 * textMargin, 600); - qreal height = 0, widthUsed = 0; - viewItemTextLayout(textLayout, bounds.width(), height, widthUsed); - const QSize size(qCeil(widthUsed), qCeil(height)); - return QSize(size.width() + 2 * textMargin, size.height()); + QStyle *style = option->widget ? option->widget->style() : QApplication::style(); + QTextOption textOption; + textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); + QTextLayout textLayout; + textLayout.setTextOption(textOption); + textLayout.setFont(option->font); + textLayout.setText(option->text); + const int textMargin = + style->pixelMetric(QStyle::PM_FocusFrameHMargin, option, option->widget) + 1; + QRect bounds(0, 0, 100 - 2 * textMargin, 600); + qreal height = 0, widthUsed = 0; + viewItemTextLayout(textLayout, bounds.width(), height, widthUsed); + const QSize size(qCeil(widthUsed), qCeil(height)); + return QSize(size.width() + 2 * textMargin, size.height()); } void ListViewDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, - const QModelIndex &index) const + const QModelIndex &index) const { - QStyleOptionViewItem opt = option; - initStyleOption(&opt, index); - painter->save(); - painter->setClipRect(opt.rect); - - opt.features |= QStyleOptionViewItem::WrapText; - opt.text = index.data().toString(); - opt.textElideMode = Qt::ElideRight; - opt.displayAlignment = Qt::AlignTop | Qt::AlignHCenter; - - QStyle *style = opt.widget ? opt.widget->style() : QApplication::style(); - - // const int iconSize = style->pixelMetric(QStyle::PM_IconViewIconSize); - const int iconSize = 48; - QRect iconbox = opt.rect; - const int textMargin = style->pixelMetric(QStyle::PM_FocusFrameHMargin, 0, opt.widget) + 1; - QRect textRect = opt.rect; - QRect textHighlightRect = textRect; - // clip the decoration on top, remove width padding - textRect.adjust(textMargin, iconSize + textMargin + 5, -textMargin, 0); - - textHighlightRect.adjust(0, iconSize + 5, 0, 0); - - // draw background - { - // FIXME: unused - // QSize textSize = viewItemTextSize ( &opt ); - QPalette::ColorGroup cg; - QStyleOptionViewItem opt2(opt); - - if ((opt.widget && opt.widget->isEnabled()) || (opt.state & QStyle::State_Enabled)) - { - if (!(opt.state & QStyle::State_Active)) - cg = QPalette::Inactive; - else - cg = QPalette::Normal; - } - else - { - cg = QPalette::Disabled; - } - opt2.palette.setCurrentColorGroup(cg); - - // fill in background, if any - - if (opt.backgroundBrush.style() != Qt::NoBrush) - { - QPointF oldBO = painter->brushOrigin(); - painter->setBrushOrigin(opt.rect.topLeft()); - painter->fillRect(opt.rect, opt.backgroundBrush); - painter->setBrushOrigin(oldBO); - } - - drawSelectionRect(painter, opt2, textHighlightRect); - - /* - if (opt.showDecorationSelected) - { - drawSelectionRect(painter, opt2, opt.rect); - drawFocusRect(painter, opt2, opt.rect); - // painter->fillRect ( opt.rect, opt.palette.brush ( cg, QPalette::Highlight ) ); - } - else - { - - // if ( opt.state & QStyle::State_Selected ) - { - // QRect textRect = subElementRect ( QStyle::SE_ItemViewItemText, opt, - // opt.widget ); - // painter->fillRect ( textHighlightRect, opt.palette.brush ( cg, - // QPalette::Highlight ) ); - drawSelectionRect(painter, opt2, textHighlightRect); - drawFocusRect(painter, opt2, textHighlightRect); - } - } - */ - } - - // icon mode and state, also used for badges - QIcon::Mode mode = QIcon::Normal; - if (!(opt.state & QStyle::State_Enabled)) - mode = QIcon::Disabled; - else if (opt.state & QStyle::State_Selected) - mode = QIcon::Selected; - QIcon::State state = opt.state & QStyle::State_Open ? QIcon::On : QIcon::Off; - - // draw the icon - { - iconbox.setHeight(iconSize); - opt.icon.paint(painter, iconbox, Qt::AlignCenter, mode, state); - } - // set the text colors - QPalette::ColorGroup cg = - opt.state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled; - if (cg == QPalette::Normal && !(opt.state & QStyle::State_Active)) - cg = QPalette::Inactive; - if (opt.state & QStyle::State_Selected) - { - painter->setPen(opt.palette.color(cg, QPalette::HighlightedText)); - } - else - { - painter->setPen(opt.palette.color(cg, QPalette::Text)); - } - - // draw the text - QTextOption textOption; - textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); - textOption.setTextDirection(opt.direction); - textOption.setAlignment(QStyle::visualAlignment(opt.direction, opt.displayAlignment)); - QTextLayout textLayout; - textLayout.setTextOption(textOption); - textLayout.setFont(opt.font); - textLayout.setText(opt.text); - - qreal width, height; - viewItemTextLayout(textLayout, textRect.width(), height, width); - - const int lineCount = textLayout.lineCount(); - - const QRect layoutRect = QStyle::alignedRect( - opt.direction, opt.displayAlignment, QSize(textRect.width(), int(height)), textRect); - const QPointF position = layoutRect.topLeft(); - for (int i = 0; i < lineCount; ++i) - { - const QTextLine line = textLayout.lineAt(i); - line.draw(painter, position); - } - - // FIXME: this really has no business of being here. Make generic. - auto instance = (BaseInstance*)index.data(InstanceList::InstancePointerRole) - .value<void *>(); - if (instance) - { - drawBadges(painter, opt, instance, mode, state); - } - - drawProgressOverlay(painter, opt, index.data(GroupViewRoles::ProgressValueRole).toInt(), - index.data(GroupViewRoles::ProgressMaximumRole).toInt()); - - painter->restore(); + QStyleOptionViewItem opt = option; + initStyleOption(&opt, index); + painter->save(); + painter->setClipRect(opt.rect); + + opt.features |= QStyleOptionViewItem::WrapText; + opt.text = index.data().toString(); + opt.textElideMode = Qt::ElideRight; + opt.displayAlignment = Qt::AlignTop | Qt::AlignHCenter; + + QStyle *style = opt.widget ? opt.widget->style() : QApplication::style(); + + // const int iconSize = style->pixelMetric(QStyle::PM_IconViewIconSize); + const int iconSize = 48; + QRect iconbox = opt.rect; + const int textMargin = style->pixelMetric(QStyle::PM_FocusFrameHMargin, 0, opt.widget) + 1; + QRect textRect = opt.rect; + QRect textHighlightRect = textRect; + // clip the decoration on top, remove width padding + textRect.adjust(textMargin, iconSize + textMargin + 5, -textMargin, 0); + + textHighlightRect.adjust(0, iconSize + 5, 0, 0); + + // draw background + { + // FIXME: unused + // QSize textSize = viewItemTextSize ( &opt ); + QPalette::ColorGroup cg; + QStyleOptionViewItem opt2(opt); + + if ((opt.widget && opt.widget->isEnabled()) || (opt.state & QStyle::State_Enabled)) + { + if (!(opt.state & QStyle::State_Active)) + cg = QPalette::Inactive; + else + cg = QPalette::Normal; + } + else + { + cg = QPalette::Disabled; + } + opt2.palette.setCurrentColorGroup(cg); + + // fill in background, if any + + if (opt.backgroundBrush.style() != Qt::NoBrush) + { + QPointF oldBO = painter->brushOrigin(); + painter->setBrushOrigin(opt.rect.topLeft()); + painter->fillRect(opt.rect, opt.backgroundBrush); + painter->setBrushOrigin(oldBO); + } + + drawSelectionRect(painter, opt2, textHighlightRect); + + /* + if (opt.showDecorationSelected) + { + drawSelectionRect(painter, opt2, opt.rect); + drawFocusRect(painter, opt2, opt.rect); + // painter->fillRect ( opt.rect, opt.palette.brush ( cg, QPalette::Highlight ) ); + } + else + { + + // if ( opt.state & QStyle::State_Selected ) + { + // QRect textRect = subElementRect ( QStyle::SE_ItemViewItemText, opt, + // opt.widget ); + // painter->fillRect ( textHighlightRect, opt.palette.brush ( cg, + // QPalette::Highlight ) ); + drawSelectionRect(painter, opt2, textHighlightRect); + drawFocusRect(painter, opt2, textHighlightRect); + } + } + */ + } + + // icon mode and state, also used for badges + QIcon::Mode mode = QIcon::Normal; + if (!(opt.state & QStyle::State_Enabled)) + mode = QIcon::Disabled; + else if (opt.state & QStyle::State_Selected) + mode = QIcon::Selected; + QIcon::State state = opt.state & QStyle::State_Open ? QIcon::On : QIcon::Off; + + // draw the icon + { + iconbox.setHeight(iconSize); + opt.icon.paint(painter, iconbox, Qt::AlignCenter, mode, state); + } + // set the text colors + QPalette::ColorGroup cg = + opt.state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled; + if (cg == QPalette::Normal && !(opt.state & QStyle::State_Active)) + cg = QPalette::Inactive; + if (opt.state & QStyle::State_Selected) + { + painter->setPen(opt.palette.color(cg, QPalette::HighlightedText)); + } + else + { + painter->setPen(opt.palette.color(cg, QPalette::Text)); + } + + // draw the text + QTextOption textOption; + textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); + textOption.setTextDirection(opt.direction); + textOption.setAlignment(QStyle::visualAlignment(opt.direction, opt.displayAlignment)); + QTextLayout textLayout; + textLayout.setTextOption(textOption); + textLayout.setFont(opt.font); + textLayout.setText(opt.text); + + qreal width, height; + viewItemTextLayout(textLayout, textRect.width(), height, width); + + const int lineCount = textLayout.lineCount(); + + const QRect layoutRect = QStyle::alignedRect( + opt.direction, opt.displayAlignment, QSize(textRect.width(), int(height)), textRect); + const QPointF position = layoutRect.topLeft(); + for (int i = 0; i < lineCount; ++i) + { + const QTextLine line = textLayout.lineAt(i); + line.draw(painter, position); + } + + // FIXME: this really has no business of being here. Make generic. + auto instance = (BaseInstance*)index.data(InstanceList::InstancePointerRole) + .value<void *>(); + if (instance) + { + drawBadges(painter, opt, instance, mode, state); + } + + drawProgressOverlay(painter, opt, index.data(GroupViewRoles::ProgressValueRole).toInt(), + index.data(GroupViewRoles::ProgressMaximumRole).toInt()); + + painter->restore(); } QSize ListViewDelegate::sizeHint(const QStyleOptionViewItem &option, - const QModelIndex &index) const + const QModelIndex &index) const { - QStyleOptionViewItem opt = option; - initStyleOption(&opt, index); - opt.features |= QStyleOptionViewItem::WrapText; - opt.text = index.data().toString(); - opt.textElideMode = Qt::ElideRight; - opt.displayAlignment = Qt::AlignTop | Qt::AlignHCenter; - - QStyle *style = opt.widget ? opt.widget->style() : QApplication::style(); - const int textMargin = - style->pixelMetric(QStyle::PM_FocusFrameHMargin, &option, opt.widget) + 1; - int height = 48 + textMargin * 2 + 5; // TODO: turn constants into variables - QSize szz = viewItemTextSize(&opt); - height += szz.height(); - // FIXME: maybe the icon items could scale and keep proportions? - QSize sz(100, height); - return sz; + QStyleOptionViewItem opt = option; + initStyleOption(&opt, index); + opt.features |= QStyleOptionViewItem::WrapText; + opt.text = index.data().toString(); + opt.textElideMode = Qt::ElideRight; + opt.displayAlignment = Qt::AlignTop | Qt::AlignHCenter; + + QStyle *style = opt.widget ? opt.widget->style() : QApplication::style(); + const int textMargin = + style->pixelMetric(QStyle::PM_FocusFrameHMargin, &option, opt.widget) + 1; + int height = 48 + textMargin * 2 + 5; // TODO: turn constants into variables + QSize szz = viewItemTextSize(&opt); + height += szz.height(); + // FIXME: maybe the icon items could scale and keep proportions? + QSize sz(100, height); + return sz; } diff --git a/application/groupview/InstanceDelegate.h b/application/groupview/InstanceDelegate.h index c0148570..d0076e60 100644 --- a/application/groupview/InstanceDelegate.h +++ b/application/groupview/InstanceDelegate.h @@ -21,10 +21,10 @@ class ListViewDelegate : public QStyledItemDelegate { public: - explicit ListViewDelegate(QObject *parent = 0); + explicit ListViewDelegate(QObject *parent = 0); protected: - void paint(QPainter *painter, const QStyleOptionViewItem &option, - const QModelIndex &index) const; - QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const; + void paint(QPainter *painter, const QStyleOptionViewItem &option, + const QModelIndex &index) const; + QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const; }; diff --git a/application/groupview/VisualGroup.cpp b/application/groupview/VisualGroup.cpp index 940c7a8b..e08cb241 100644 --- a/application/groupview/VisualGroup.cpp +++ b/application/groupview/VisualGroup.cpp @@ -28,290 +28,290 @@ VisualGroup::VisualGroup(const QString &text, GroupView *view) : view(view), tex } VisualGroup::VisualGroup(const VisualGroup *other) - : view(other->view), text(other->text), collapsed(other->collapsed) + : view(other->view), text(other->text), collapsed(other->collapsed) { } void VisualGroup::update() { - auto temp_items = items(); - auto itemsPerRow = view->itemsPerRow(); - - int numRows = qMax(1, qCeil((qreal)temp_items.size() / (qreal)itemsPerRow)); - rows = QVector<VisualRow>(numRows); - - int maxRowHeight = 0; - int positionInRow = 0; - int currentRow = 0; - int offsetFromTop = 0; - for (auto item: temp_items) - { - if(positionInRow == itemsPerRow) - { - rows[currentRow].height = maxRowHeight; - rows[currentRow].top = offsetFromTop; - currentRow ++; - offsetFromTop += maxRowHeight + 5; - positionInRow = 0; - maxRowHeight = 0; - } - auto itemHeight = view->itemDelegate()->sizeHint(view->viewOptions(), item).height(); - if(itemHeight > maxRowHeight) - { - maxRowHeight = itemHeight; - } - rows[currentRow].items.append(item); - positionInRow++; - } - rows[currentRow].height = maxRowHeight; - rows[currentRow].top = offsetFromTop; + auto temp_items = items(); + auto itemsPerRow = view->itemsPerRow(); + + int numRows = qMax(1, qCeil((qreal)temp_items.size() / (qreal)itemsPerRow)); + rows = QVector<VisualRow>(numRows); + + int maxRowHeight = 0; + int positionInRow = 0; + int currentRow = 0; + int offsetFromTop = 0; + for (auto item: temp_items) + { + if(positionInRow == itemsPerRow) + { + rows[currentRow].height = maxRowHeight; + rows[currentRow].top = offsetFromTop; + currentRow ++; + offsetFromTop += maxRowHeight + 5; + positionInRow = 0; + maxRowHeight = 0; + } + auto itemHeight = view->itemDelegate()->sizeHint(view->viewOptions(), item).height(); + if(itemHeight > maxRowHeight) + { + maxRowHeight = itemHeight; + } + rows[currentRow].items.append(item); + positionInRow++; + } + rows[currentRow].height = maxRowHeight; + rows[currentRow].top = offsetFromTop; } QPair<int, int> VisualGroup::positionOf(const QModelIndex &index) const { - int y = 0; - for (auto & row: rows) - { - for(auto x = 0; x < row.items.size(); x++) - { - if(row.items[x] == index) - { - return qMakePair(x,y); - } - } - y++; - } - qWarning() << "Item" << index.row() << index.data(Qt::DisplayRole).toString() << "not found in visual group" << text; - return qMakePair(0, 0); + int y = 0; + for (auto & row: rows) + { + for(auto x = 0; x < row.items.size(); x++) + { + if(row.items[x] == index) + { + return qMakePair(x,y); + } + } + y++; + } + qWarning() << "Item" << index.row() << index.data(Qt::DisplayRole).toString() << "not found in visual group" << text; + return qMakePair(0, 0); } int VisualGroup::rowTopOf(const QModelIndex &index) const { - auto position = positionOf(index); - return rows[position.second].top; + auto position = positionOf(index); + return rows[position.second].top; } int VisualGroup::rowHeightOf(const QModelIndex &index) const { - auto position = positionOf(index); - return rows[position.second].height; + auto position = positionOf(index); + return rows[position.second].height; } VisualGroup::HitResults VisualGroup::hitScan(const QPoint &pos) const { - VisualGroup::HitResults results = VisualGroup::NoHit; - int y_start = verticalPosition(); - int body_start = y_start + headerHeight(); - int body_end = body_start + contentHeight() + 5; // FIXME: wtf is this 5? - int y = pos.y(); - // int x = pos.x(); - if (y < y_start) - { - results = VisualGroup::NoHit; - } - else if (y < body_start) - { - results = VisualGroup::HeaderHit; - int collapseSize = headerHeight() - 4; - - // the icon - QRect iconRect = QRect(view->m_leftMargin + 2, 2 + y_start, collapseSize, collapseSize); - if (iconRect.contains(pos)) - { - results |= VisualGroup::CheckboxHit; - } - } - else if (y < body_end) - { - results |= VisualGroup::BodyHit; - } - return results; + VisualGroup::HitResults results = VisualGroup::NoHit; + int y_start = verticalPosition(); + int body_start = y_start + headerHeight(); + int body_end = body_start + contentHeight() + 5; // FIXME: wtf is this 5? + int y = pos.y(); + // int x = pos.x(); + if (y < y_start) + { + results = VisualGroup::NoHit; + } + else if (y < body_start) + { + results = VisualGroup::HeaderHit; + int collapseSize = headerHeight() - 4; + + // the icon + QRect iconRect = QRect(view->m_leftMargin + 2, 2 + y_start, collapseSize, collapseSize); + if (iconRect.contains(pos)) + { + results |= VisualGroup::CheckboxHit; + } + } + else if (y < body_end) + { + results |= VisualGroup::BodyHit; + } + return results; } void VisualGroup::drawHeader(QPainter *painter, const QStyleOptionViewItem &option) { - painter->setRenderHint(QPainter::Antialiasing); - - const QRect optRect = option.rect; - QFont font(QApplication::font()); - font.setBold(true); - const QFontMetrics fontMetrics = QFontMetrics(font); - - QColor outlineColor = option.palette.text().color(); - outlineColor.setAlphaF(0.35); - - //BEGIN: top left corner - { - painter->save(); - painter->setPen(outlineColor); - const QPointF topLeft(optRect.topLeft()); - QRectF arc(topLeft, QSizeF(4, 4)); - arc.translate(0.5, 0.5); - painter->drawArc(arc, 1440, 1440); - painter->restore(); - } - //END: top left corner - - //BEGIN: left vertical line - { - QPoint start(optRect.topLeft()); - start.ry() += 3; - QPoint verticalGradBottom(optRect.topLeft()); - verticalGradBottom.ry() += fontMetrics.height() + 5; - QLinearGradient gradient(start, verticalGradBottom); - gradient.setColorAt(0, outlineColor); - gradient.setColorAt(1, Qt::transparent); - painter->fillRect(QRect(start, QSize(1, fontMetrics.height() + 5)), gradient); - } - //END: left vertical line - - //BEGIN: horizontal line - { - QPoint start(optRect.topLeft()); - start.rx() += 3; - QPoint horizontalGradTop(optRect.topLeft()); - horizontalGradTop.rx() += optRect.width() - 6; - painter->fillRect(QRect(start, QSize(optRect.width() - 6, 1)), outlineColor); - } - //END: horizontal line - - //BEGIN: top right corner - { - painter->save(); - painter->setPen(outlineColor); - QPointF topRight(optRect.topRight()); - topRight.rx() -= 4; - QRectF arc(topRight, QSizeF(4, 4)); - arc.translate(0.5, 0.5); - painter->drawArc(arc, 0, 1440); - painter->restore(); - } - //END: top right corner - - //BEGIN: right vertical line - { - QPoint start(optRect.topRight()); - start.ry() += 3; - QPoint verticalGradBottom(optRect.topRight()); - verticalGradBottom.ry() += fontMetrics.height() + 5; - QLinearGradient gradient(start, verticalGradBottom); - gradient.setColorAt(0, outlineColor); - gradient.setColorAt(1, Qt::transparent); - painter->fillRect(QRect(start, QSize(1, fontMetrics.height() + 5)), gradient); - } - //END: right vertical line - - //BEGIN: checkboxy thing - { - painter->save(); - painter->setRenderHint(QPainter::Antialiasing, false); - painter->setFont(font); - QColor penColor(option.palette.text().color()); - penColor.setAlphaF(0.6); - painter->setPen(penColor); - QRect iconSubRect(option.rect); - iconSubRect.setTop(iconSubRect.top() + 7); - iconSubRect.setLeft(iconSubRect.left() + 7); - - int sizing = fontMetrics.height(); - int even = ( (sizing - 1) % 2 ); - - iconSubRect.setHeight(sizing - even); - iconSubRect.setWidth(sizing - even); - painter->drawRect(iconSubRect); - - - /* - if(collapsed) - painter->drawText(iconSubRect, Qt::AlignHCenter | Qt::AlignVCenter, "+"); - else - painter->drawText(iconSubRect, Qt::AlignHCenter | Qt::AlignVCenter, "-"); - */ - painter->setBrush(option.palette.text()); - painter->fillRect(iconSubRect.x(), iconSubRect.y() + iconSubRect.height() / 2, - iconSubRect.width(), 2, penColor); - if (collapsed) - { - painter->fillRect(iconSubRect.x() + iconSubRect.width() / 2, iconSubRect.y(), 2, - iconSubRect.height(), penColor); - } - - painter->restore(); - } - //END: checkboxy thing - - //BEGIN: text - { - QRect textRect(option.rect); - textRect.setTop(textRect.top() + 7); - textRect.setLeft(textRect.left() + 7 + fontMetrics.height() + 7); - textRect.setHeight(fontMetrics.height()); - textRect.setRight(textRect.right() - 7); - - painter->save(); - painter->setFont(font); - QColor penColor(option.palette.text().color()); - penColor.setAlphaF(0.6); - painter->setPen(penColor); - painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, text); - painter->restore(); - } - //END: text + painter->setRenderHint(QPainter::Antialiasing); + + const QRect optRect = option.rect; + QFont font(QApplication::font()); + font.setBold(true); + const QFontMetrics fontMetrics = QFontMetrics(font); + + QColor outlineColor = option.palette.text().color(); + outlineColor.setAlphaF(0.35); + + //BEGIN: top left corner + { + painter->save(); + painter->setPen(outlineColor); + const QPointF topLeft(optRect.topLeft()); + QRectF arc(topLeft, QSizeF(4, 4)); + arc.translate(0.5, 0.5); + painter->drawArc(arc, 1440, 1440); + painter->restore(); + } + //END: top left corner + + //BEGIN: left vertical line + { + QPoint start(optRect.topLeft()); + start.ry() += 3; + QPoint verticalGradBottom(optRect.topLeft()); + verticalGradBottom.ry() += fontMetrics.height() + 5; + QLinearGradient gradient(start, verticalGradBottom); + gradient.setColorAt(0, outlineColor); + gradient.setColorAt(1, Qt::transparent); + painter->fillRect(QRect(start, QSize(1, fontMetrics.height() + 5)), gradient); + } + //END: left vertical line + + //BEGIN: horizontal line + { + QPoint start(optRect.topLeft()); + start.rx() += 3; + QPoint horizontalGradTop(optRect.topLeft()); + horizontalGradTop.rx() += optRect.width() - 6; + painter->fillRect(QRect(start, QSize(optRect.width() - 6, 1)), outlineColor); + } + //END: horizontal line + + //BEGIN: top right corner + { + painter->save(); + painter->setPen(outlineColor); + QPointF topRight(optRect.topRight()); + topRight.rx() -= 4; + QRectF arc(topRight, QSizeF(4, 4)); + arc.translate(0.5, 0.5); + painter->drawArc(arc, 0, 1440); + painter->restore(); + } + //END: top right corner + + //BEGIN: right vertical line + { + QPoint start(optRect.topRight()); + start.ry() += 3; + QPoint verticalGradBottom(optRect.topRight()); + verticalGradBottom.ry() += fontMetrics.height() + 5; + QLinearGradient gradient(start, verticalGradBottom); + gradient.setColorAt(0, outlineColor); + gradient.setColorAt(1, Qt::transparent); + painter->fillRect(QRect(start, QSize(1, fontMetrics.height() + 5)), gradient); + } + //END: right vertical line + + //BEGIN: checkboxy thing + { + painter->save(); + painter->setRenderHint(QPainter::Antialiasing, false); + painter->setFont(font); + QColor penColor(option.palette.text().color()); + penColor.setAlphaF(0.6); + painter->setPen(penColor); + QRect iconSubRect(option.rect); + iconSubRect.setTop(iconSubRect.top() + 7); + iconSubRect.setLeft(iconSubRect.left() + 7); + + int sizing = fontMetrics.height(); + int even = ( (sizing - 1) % 2 ); + + iconSubRect.setHeight(sizing - even); + iconSubRect.setWidth(sizing - even); + painter->drawRect(iconSubRect); + + + /* + if(collapsed) + painter->drawText(iconSubRect, Qt::AlignHCenter | Qt::AlignVCenter, "+"); + else + painter->drawText(iconSubRect, Qt::AlignHCenter | Qt::AlignVCenter, "-"); + */ + painter->setBrush(option.palette.text()); + painter->fillRect(iconSubRect.x(), iconSubRect.y() + iconSubRect.height() / 2, + iconSubRect.width(), 2, penColor); + if (collapsed) + { + painter->fillRect(iconSubRect.x() + iconSubRect.width() / 2, iconSubRect.y(), 2, + iconSubRect.height(), penColor); + } + + painter->restore(); + } + //END: checkboxy thing + + //BEGIN: text + { + QRect textRect(option.rect); + textRect.setTop(textRect.top() + 7); + textRect.setLeft(textRect.left() + 7 + fontMetrics.height() + 7); + textRect.setHeight(fontMetrics.height()); + textRect.setRight(textRect.right() - 7); + + painter->save(); + painter->setFont(font); + QColor penColor(option.palette.text().color()); + penColor.setAlphaF(0.6); + painter->setPen(penColor); + painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, text); + painter->restore(); + } + //END: text } int VisualGroup::totalHeight() const { - return headerHeight() + 5 + contentHeight(); // FIXME: wtf is that '5'? + return headerHeight() + 5 + contentHeight(); // FIXME: wtf is that '5'? } int VisualGroup::headerHeight() const { - QFont font(QApplication::font()); + QFont font(QApplication::font()); font.setBold(true); QFontMetrics fontMetrics(font); const int height = fontMetrics.height() + 1 /* 1 pixel-width gradient */ + 11 /* top and bottom separation */; return height; - /* - int raw = view->viewport()->fontMetrics().height() + 4; - // add english. maybe. depends on font height. - if (raw % 2 == 0) - raw++; - return std::min(raw, 25); - */ + /* + int raw = view->viewport()->fontMetrics().height() + 4; + // add english. maybe. depends on font height. + if (raw % 2 == 0) + raw++; + return std::min(raw, 25); + */ } int VisualGroup::contentHeight() const { - if (collapsed) - { - return 0; - } - auto last = rows[numRows() - 1]; - return last.top + last.height; + if (collapsed) + { + return 0; + } + auto last = rows[numRows() - 1]; + return last.top + last.height; } int VisualGroup::numRows() const { - return rows.size(); + return rows.size(); } int VisualGroup::verticalPosition() const { - return m_verticalPosition; + return m_verticalPosition; } QList<QModelIndex> VisualGroup::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(GroupViewRoles::GroupRole).toString() == text) - { - indices.append(index); - } - } - return indices; + QList<QModelIndex> indices; + for (int i = 0; i < view->model()->rowCount(); ++i) + { + const QModelIndex index = view->model()->index(i, 0); + if (index.data(GroupViewRoles::GroupRole).toString() == text) + { + indices.append(index); + } + } + return indices; } diff --git a/application/groupview/VisualGroup.h b/application/groupview/VisualGroup.h index 2caac49f..0ffcf236 100644 --- a/application/groupview/VisualGroup.h +++ b/application/groupview/VisualGroup.h @@ -26,81 +26,81 @@ class QModelIndex; struct VisualRow { - QList<QModelIndex> items; - int height = 0; - int top = 0; - inline int size() const - { - return items.size(); - } - inline QModelIndex &operator[](int i) - { - return items[i]; - } + QList<QModelIndex> items; + int height = 0; + int top = 0; + inline int size() const + { + return items.size(); + } + inline QModelIndex &operator[](int i) + { + return items[i]; + } }; struct VisualGroup { /* constructors */ - VisualGroup(const QString &text, GroupView *view); - VisualGroup(const VisualGroup *other); + VisualGroup(const QString &text, GroupView *view); + VisualGroup(const VisualGroup *other); /* data */ - GroupView *view = nullptr; - QString text; - bool collapsed = false; - QVector<VisualRow> rows; - int firstItemIndex = 0; - int m_verticalPosition = 0; + GroupView *view = nullptr; + QString text; + bool collapsed = false; + QVector<VisualRow> rows; + int firstItemIndex = 0; + int m_verticalPosition = 0; /* logic */ - /// update the internal list of items and flow them into the rows. - void update(); + /// update the internal list of items and flow them into the rows. + void update(); - /// draw the header at y-position. - void drawHeader(QPainter *painter, const QStyleOptionViewItem &option); + /// draw the header at y-position. + void drawHeader(QPainter *painter, const QStyleOptionViewItem &option); - /// height of the group, in total. includes a small bit of padding. - int totalHeight() const; + /// height of the group, in total. includes a small bit of padding. + int totalHeight() const; - /// height of the group header, in pixels - int headerHeight() const; + /// height of the group header, in pixels + int headerHeight() const; - /// height of the group content, in pixels - int contentHeight() const; + /// height of the group content, in pixels + int contentHeight() const; - /// the number of visual rows this group has - int numRows() const; + /// the number of visual rows this group has + int numRows() const; - /// actually calculate the above value - int calculateNumRows() const; + /// actually calculate the above value + int calculateNumRows() const; - /// the height at which this group starts, in pixels - int verticalPosition() const; + /// the height at which this group starts, in pixels + int verticalPosition() const; - /// relative geometry - top of the row of the given item - int rowTopOf(const QModelIndex &index) const; + /// relative geometry - top of the row of the given item + int rowTopOf(const QModelIndex &index) const; - /// height of the row of the given item - int rowHeightOf(const QModelIndex &index) const; + /// height of the row of the given item + int rowHeightOf(const QModelIndex &index) const; - /// x/y position of the given item inside the group (in items!) - QPair<int, int> positionOf(const QModelIndex &index) const; + /// x/y position of the given item inside the group (in items!) + QPair<int, int> positionOf(const QModelIndex &index) const; - enum HitResult - { - NoHit = 0x0, - TextHit = 0x1, - CheckboxHit = 0x2, - HeaderHit = 0x4, - BodyHit = 0x8 - }; - Q_DECLARE_FLAGS(HitResults, HitResult) + enum HitResult + { + NoHit = 0x0, + TextHit = 0x1, + CheckboxHit = 0x2, + HeaderHit = 0x4, + BodyHit = 0x8 + }; + Q_DECLARE_FLAGS(HitResults, HitResult) - /// shoot! BANG! what did we hit? - HitResults hitScan (const QPoint &pos) const; + /// shoot! BANG! what did we hit? + HitResults hitScan (const QPoint &pos) const; - QList<QModelIndex> items() const; + QList<QModelIndex> items() const; }; Q_DECLARE_OPERATORS_FOR_FLAGS(VisualGroup::HitResults) |