#include "qmtreeview.h" #include #include #include #include #include #include #include #include // Implementation #include #include "treemodel.h" QMTreeView::QMTreeView(QWidget *parent): QTreeView(parent) { header()->setFixedHeight(30); QPushButton * cornerbutton = new QPushButton(this); setCornerWidget(cornerbutton); connect(cornerbutton, &QPushButton::released, this, &QMTreeView::onCornerButtonRelease); setLineWidth(1); setAlternatingRowColors(false); setAcceptDrops(true); // Habilita el drop setDropIndicatorShown(true); setTreePosition(0); return; setStyleSheet("QHeaderView::section:horizontal {" "background-color: qlineargradient(spread:reflect," "x1:0, y1:0, x2:0, y2:1," "stop:0 rgba(255, 255, 255, 255)," "stop:1 rgba(164, 164, 164, 255));" "border: 1px solid rgb(153, 153, 153);" "border-width: 0 1px 1px 0;" "}" "QTreeView::item {" "border-bottom: 0.5px solid lightgray;" "selection-color: black;" "}" "QTreeView::item:selected { /*被选中的index*/" "background: qlineargradient(" "x1: 0, y1: 0, x2: 0, y2: 1," "stop: 0 #FAFBFE," "stop: 1 #DCDEF1);" "}" "QTreeView::branch {" "background: yellow;" "}" "QTreeView::branch:has-siblings:!adjoins-item {" "background: cyan;" "}" "QTreeView::branch:has-siblings:adjoins-item {" "background: red;" "}" "QTreeView::branch:!has-children:!has-siblings:adjoins-item {" "background: blue;" "}" "QTreeView::branch:closed:has-children:has-siblings {" "background: black;" "}" "QTreeView::branch:has-children:!has-siblings:closed {" "background: gray;" "}" "QTreeView::branch:open:has-children:has-siblings {" "background: magenta;" "}" "QTreeView::branch:open:has-children:!has-siblings {" "background: green;}"); } void QMTreeView::resizeEvent(QResizeEvent *event) { QTreeView::resizeEvent(event); } /* void QMTreeView::drawTree(QPainter *painter, const QRegion ®ion) const { QTreeView::drawTree(painter, region); return; if (model() && model()->rowCount() > 0) { QTreeView::drawTree(painter, region); } else { // If no items draw a text in the center of the viewport. QPainter painter(viewport()); QString text(tr("There are no elements in this view")); QRect textRect = painter.fontMetrics().boundingRect(text); textRect.moveCenter(viewport()->rect().center()); painter.drawText(textRect, Qt::AlignCenter, text); } */ /* Q_D(const QTreeView); const QVector viewItems = d->viewItems; QStyleOptionViewItem option = d->viewOptionsV1(); const QStyle::State state = option.state; d->current = 0; if (viewItems.count() == 0 || d->header->count() == 0 || !d->itemDelegate) { d->paintAlternatingRowColors(painter, &option, 0, region.boundingRect().bottom()+1); return; } int firstVisibleItemOffset = 0; const int firstVisibleItem = d->firstVisibleItem(&firstVisibleItemOffset); if (firstVisibleItem < 0) { d->paintAlternatingRowColors(painter, &option, 0, region.boundingRect().bottom()+1); return; } const int viewportWidth = d->viewport->width(); QPoint hoverPos = d->viewport->mapFromGlobal(QCursor::pos()); d->hoverBranch = d->itemDecorationAt(hoverPos); QVector drawn; bool multipleRects = (region.rectCount() > 1); for (const QRect &a : region) { const QRect area = (multipleRects ? QRect(0, a.y(), viewportWidth, a.height()) : a); d->leftAndRight = d->startAndEndColumns(area); int i = firstVisibleItem; // the first item at the top of the viewport int y = firstVisibleItemOffset; // we may only see part of the first item // start at the top of the viewport and iterate down to the update area for (; i < viewItems.count(); ++i) { const int itemHeight = d->itemHeight(i); if (y + itemHeight > area.top()) break; y += itemHeight; } // paint the visible rows for (; i < viewItems.count() && y <= area.bottom(); ++i) { const int itemHeight = d->itemHeight(i); option.rect.setRect(0, y, viewportWidth, itemHeight); option.state = state | (viewItems.at(i).expanded ? QStyle::State_Open : QStyle::State_None) | (viewItems.at(i).hasChildren ? QStyle::State_Children : QStyle::State_None) | (viewItems.at(i).hasMoreSiblings ? QStyle::State_Sibling : QStyle::State_None); d->current = i; d->spanning = viewItems.at(i).spanning; if (!multipleRects || !drawn.contains(i)) { drawRow(painter, option, viewItems.at(i).index); if (multipleRects) // even if the rect only intersects the item, drawn.append(i); // the entire item will be painted } y += itemHeight; } if (y <= area.bottom()) { d->current = i; d->paintAlternatingRowColors(painter, &option, y, area.bottom()); } } */ //} void QMTreeView::drawRow(QPainter * painter, const QStyleOptionViewItem & options, const QModelIndex & index) const { QTreeView::drawRow(painter, options, index); //return; int m_iWidth = 1; QColor m_gridLineColor = QColor(200, 200, 200); QPen pen; pen.setWidth(m_iWidth); pen.setColor(m_gridLineColor); QBrush brush; brush.setColor(QColor(0,0,0,0)); painter->save(); painter->setPen(pen); painter->setBrush(brush); painter->drawRect(options.rect); painter->restore(); } void QMTreeView::drawBranches(QPainter *painter, const QRect &rect, const QModelIndex &index) const { if (!index.isValid()) { QTreeView::drawBranches(painter, rect, index); return; } // Calcula el ancho del branch basado en el nivel de profundidad int depth = 0; QModelIndex parentIndex = index.parent(); while (parentIndex.isValid()) { ++depth; parentIndex = parentIndex.parent(); } // Calcula el ancho del branch int branchWidth = depth * indentation(); // Dibuja el rectángulo del branch QRect branchRect(rect.left(), rect.top(), branchWidth, rect.height()); painter->save(); painter->setBrush(Qt::yellow); // Cambia el color según prefieras painter->setPen(Qt::NoPen); // Sin bordes painter->drawRect(branchRect); painter->restore(); // Llama al método base para que Qt dibuje el resto QTreeView::drawBranches(painter, rect, index); return; QTreeView::drawBranches(painter, rect, index); //return; //int m_iWidth = 1; QColor m_gridLineColor = QColor(200, 200, 200); QPen pen; //pen.setWidth(m_iWidth); pen.setColor(m_gridLineColor); QBrush brush; brush.setColor(QColor(0,0,0,0)); //painter->save(); painter->setPen(pen); painter->setBrush(brush); painter->drawRect(rect); //painter->restore(); //const QTreeViewItem &viewItem = d->viewItems.at(item); //int level = viewItem.level; //Q_Q(const QMTreeView); /* const bool reverse = isRightToLeft(); const int indent = d->indent; const int outer = d->rootDecoration ? 0 : 1; const int item = d->current; const QTreeViewItem &viewItem = d->viewItems.at(item); int level = viewItem.level; QRect primitive(reverse ? rect.left() : rect.right() + 1, rect.top(), indent, rect.height()); QModelIndex parent = index.parent(); QModelIndex current = parent; QModelIndex ancestor = current.parent(); QStyleOptionViewItem opt = viewOptions(); QStyle::State extraFlags = QStyle::State_None; if (isEnabled()) extraFlags |= QStyle::State_Enabled; if (hasFocus()) extraFlags |= QStyle::State_Active; QPoint oldBO = painter->brushOrigin(); if (verticalScrollMode() == QAbstractItemView::ScrollPerPixel) painter->setBrushOrigin(QPoint(0, verticalOffset())); if (d->alternatingColors) { opt.features.setFlag(QStyleOptionViewItem::Alternate, d->current & 1); } // When hovering over a row, pass State_Hover for painting the branch // indicators if it has the decoration (aka branch) selected. bool hoverRow = selectionBehavior() == QAbstractItemView::SelectRows && opt.showDecorationSelected && index.parent() == d->hover.parent() && index.row() == d->hover.row(); if (d->selectionModel->isSelected(index)) extraFlags |= QStyle::State_Selected; if (level >= outer) { // start with the innermost branch primitive.moveLeft(reverse ? primitive.left() : primitive.left() - indent); opt.rect = primitive; const bool expanded = viewItem.expanded; const bool children = viewItem.hasChildren; bool moreSiblings = viewItem.hasMoreSiblings; opt.state = QStyle::State_Item | extraFlags | (moreSiblings ? QStyle::State_Sibling : QStyle::State_None) | (children ? QStyle::State_Children : QStyle::State_None) | (expanded ? QStyle::State_Open : QStyle::State_None); opt.state.setFlag(QStyle::State_MouseOver, hoverRow || item == d->hoverBranch); style()->drawPrimitive(QStyle::PE_IndicatorBranch, &opt, painter, this); } // then go out level by level for (--level; level >= outer; --level) { // we have already drawn the innermost branch primitive.moveLeft(reverse ? primitive.left() + indent : primitive.left() - indent); opt.rect = primitive; opt.state = extraFlags; bool moreSiblings = false; if (d->hiddenIndexes.isEmpty()) { moreSiblings = (d->model->rowCount(ancestor) - 1 > current.row()); } else { int successor = item + viewItem.total + 1; while (successor < d->viewItems.size() && d->viewItems.at(successor).level >= uint(level)) { const QTreeViewItem &successorItem = d->viewItems.at(successor); if (successorItem.level == uint(level)) { moreSiblings = true; break; } successor += successorItem.total + 1; } } if (moreSiblings) opt.state |= QStyle::State_Sibling; opt.state.setFlag(QStyle::State_MouseOver, hoverRow || item == d->hoverBranch); style()->drawPrimitive(QStyle::PE_IndicatorBranch, &opt, painter, this); current = ancestor; ancestor = current.parent(); } painter->setBrushOrigin(oldBO);*/ } /* int indexRowSizeHint(const QModelIndex &index) { } int rowHeight(const QModelIndex &index) { } */ void QMTreeView::keyPressEvent(QKeyEvent *e) { bool bNextCellOnEnter = true; bool bNextRowOnLastCol = true; /* Key_Left = 0x01000012, Key_Up = 0x01000013, Key_Right = 0x01000014, Key_Down = 0x01000015, */ if(bNextCellOnEnter && (e->key() == Qt::Key_Return | e->key() == Qt::Key_Enter | e->key() == Qt::Key_Right)) { qint32 cr = currentIndex().row(), cc = currentIndex().column(), c = model()->columnCount(); QHeaderView *hdr = static_cast(header()); if(hdr) cc = hdr->visualIndex(cc); if(cc + 1 < c) { moveTo(cr, cc + 1); if(editTriggers() == QAbstractItemView::AllEditTriggers) edit(currentIndex()); } else if(bNextRowOnLastCol) { // TODO: comporbar si tiene hijos y si tiene mover el selector a este. if(cr < model()->rowCount() - 1) moveTo(cr + 1, 0); if(editTriggers() == QAbstractItemView::AllEditTriggers) edit(currentIndex()); } else QTreeView::keyPressEvent(e); } else if(e->key() == Qt::Key_Left /*&& currentIndex().row() == model()->rowCount() - 1*/) { qint32 cr = currentIndex().row(), cc = currentIndex().column(), c = model()->columnCount(); QHeaderView *hdr = static_cast(header()); if(hdr) cc = hdr->visualIndex(cc); if(cc - 1 > -1) { moveTo(cr, cc - 1); if(editTriggers() == QAbstractItemView::AllEditTriggers) edit(currentIndex()); } /* else if(bNextRowOnLastCol) { // TODO: comporbar si tiene hijos y si tiene mover el selector a este. if(cr < model()->rowCount() - 1) moveTo(cr + 1, 0); if(editTriggers() == QAbstractItemView::AllEditTriggers) edit(currentIndex()); } */ else QTreeView::keyPressEvent(e); } /* else if(e->key() == Qt::Key_Up) { qint32 cr = currentIndex().row(), cc = currentIndex().column(), c = model()->columnCount(); if(cr > 0) moveTo(cr - 1, currentIndex().column()); } */ else if(e->key() == Qt::Key_Down && currentIndex().row() == model()->rowCount() - 1) { addNewRecord(currentIndex()); //QTreeView::keyPressEvent(e); // quitar esto } /* else if(e->key() == Qt::Key_Down) { qint32 cr = currentIndex().row(), cc = currentIndex().column(), c = model()->columnCount(); if(cr < model()->rowCount() - 1) moveTo(cr + 1, currentIndex().column()); } */ else { QModelIndex c(currentIndex()); QTreeView::keyPressEvent(e); if(c.row() != currentIndex().row() || c.column() != currentIndex().column()) { selectionModel()->select(currentIndex(), QItemSelectionModel::Select); selectionModel()->select(c, QItemSelectionModel::Deselect); } } } void QMTreeView::moveTo(int r, int c) { QHeaderView *hdr = static_cast(header()); if(!hdr) return; if(c > hdr->count() - 1) c = hdr->count() - 1; if(r > model()->rowCount() - 1) r = model()->rowCount() - 1; c = nextVisibleIndex(hdr->logicalIndex(c)); QModelIndex oi = currentIndex(), ix = model()->index(r, c, oi.parent().isValid() ? oi.parent() : QModelIndex()); qDebug() << "Pos" << r << ":" << c << "MoveTo" << ix << "IsValid ?" << ix.isValid(); if(ix.isValid()) { QItemSelection os(currentIndex(), currentIndex()); setCurrentIndex(ix); selectionModel()->setCurrentIndex(ix, QItemSelectionModel::ClearAndSelect); QItemSelection ns(currentIndex(), currentIndex()); QTreeView::selectionChanged(os, ns); qDebug() << "MOveTo" << currentIndex(); //emit onPositionChanged(currentRow(), currentColumn()); } } int QMTreeView::nextVisibleIndex(int c) { QHeaderView *hdr = static_cast(header()); if(!hdr) return c; if(c > hdr->count() - 1) return nextVisibleIndex(hdr->count() - 1); for(int i = c; i < hdr->count() - 1; i++) { if(!hdr->isSectionHidden(i)) return i; } return c; } bool QMTreeView::addNewRecord(const QModelIndex &index) { if(editTriggers() == QAbstractItemView::NoEditTriggers) // read Only return false; insertRow(); scrollToBottom(); moveTo(model()->rowCount(), nextVisibleIndex(0)); /* if(!bCanAddRow) return false; if(model() && model()->inherits("PBSDataModel")) { PBSDataModel *pModel = static_cast(model()); if(pModel) { int r = currentIndex().row(), c = currentIndex().column(); if(!pModel->haveEmptyRow()) { pModel->insertEmptyRow(); emit newRecordAdd(); resizeRowToContents(pModel->rowCount()); scrollToBottom(); if(bGotoFirstCellOnNewRec) c = nextVisibleIndex(0); moveTo(pModel->rowCount(), c); emit newRecordAdd(); } } } else { model()->insertRow(model()->rowCount(QModelIndex())); model()->submit(); } */ return true; } void QMTreeView::insertChild() { QModelIndex selindex = selectionModel()->currentIndex(); QAbstractItemModel *treemodel = model(); if (treemodel->columnCount(selindex) == 0) { if (!treemodel->insertColumn(0, selindex)) return; } if (!treemodel->insertRow(0, treemodel->index(selindex.row(), 0, selindex.parent()))) return; /* for (int column = 0; column < treemodel->columnCount(selindex); ++column) { QModelIndex child = treemodel->index(0, column, selindex); treemodel->setData(child, QVariant(""), Qt::EditRole); if (!treemodel->headerData(column, Qt::Horizontal).isValid()) treemodel->setHeaderData(column, Qt::Horizontal, QVariant("[No header]"), Qt::EditRole); } */ selectionModel()->setCurrentIndex(treemodel->index(0, 0, selindex), QItemSelectionModel::ClearAndSelect); } void QMTreeView::addRow() { //QModelIndex selindex = selectionModel()->currentIndex(); QAbstractItemModel *treemodel = model(); if (!treemodel->insertRow(treemodel->rowCount())) return; } void QMTreeView::insertRow() { QModelIndex selindex = selectionModel()->currentIndex(); QAbstractItemModel *treemodel = model(); //int i = 1; //setFirstColumnSpanned(i, model()->index(i, 0), true); if (!treemodel->insertRow(selindex.row() + 1, selindex.parent())) return; } void QMTreeView::removeRow() { QModelIndex selindex = selectionModel()->currentIndex(); QAbstractItemModel *treemodel = model(); treemodel->removeRow(selindex.row(), selindex.parent()); } void QMTreeView::onCornerButtonRelease() { QMenu *menu = new QMenu(); menu->addAction(new QAction("javi")); menu->exec(); //QPushButton *bt = static_cast(cornerWidget()); //bt->setMenu(menu); } void QMTreeView::dragEnterEvent(QDragEnterEvent *event) { if (event->mimeData()->hasText()) { event->acceptProposedAction(); } } void QMTreeView::dragMoveEvent(QDragMoveEvent *event) { if (event->mimeData()->hasText()) { event->acceptProposedAction(); } } void QMTreeView::dropEvent(QDropEvent *event) { if (event->mimeData()->hasText()) { QString data = event->mimeData()->text(); QStringList items = data.split("\n"); // Aquí puedes insertar los datos en el modelo del QTreeView QAbstractItemModel *treeModel = model(); for (const QString &item : items) { if (!item.isEmpty()) { QModelIndex parentIndex = currentIndex(); treeModel->insertRow(treeModel->rowCount(parentIndex), parentIndex); QModelIndex newItemIndex = treeModel->index(treeModel->rowCount(parentIndex) - 1, 0, parentIndex); treeModel->setData(newItemIndex, item); } } event->acceptProposedAction(); } }