Initial commit of BudgetPro

This commit is contained in:
Javi
2026-05-24 23:21:33 +02:00
commit f3096faee6
575 changed files with 90288 additions and 0 deletions
+655
View File
@@ -0,0 +1,655 @@
#include "qmtreeview.h"
#include <QPen>
#include <QPainter>
#include <QStyleOptionFrame>
#include <QHeaderView>
#include <QPushButton>
#include <QtEvents>
#include <QMenu>
#include <QMimeData>
// Implementation
#include <QDebug>
#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 &region) 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<QTreeViewItem> 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<int> 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<QHeaderView*>(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<QHeaderView*>(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<QHeaderView*>(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<QHeaderView*>(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<PBSDataModel*>(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<QPushButton *>(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();
}
}