/*************************************************************************** source::worx xtree Copyright © 2024-2025 c.holzheuer christoph.holzheuer@gmail.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. ***************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include //! erzeugt eine editorfactory mit den hauseigenen editortypen. class XQItemEditorFactory : public QItemEditorFactory { public: XQItemEditorFactory() { registerEditor(XQItem::LineEditType, new QStandardItemEditorCreator()); registerEditor(XQItem::ComboBoxType, new QStandardItemEditorCreator()); registerEditor(XQItem::PickerType, new QStandardItemEditorCreator()); //registerEditor(XQItem::ColorBarType, new QStandardItemEditorCreator()); registerEditor(XQItem::ColorBarType, new QStandardItemEditorCreator()); registerEditor(XQItem::SpinBoxType, new QStandardItemEditorCreator()); registerEditor(XQItem::CustomEditorType, new QStandardItemEditorCreator()); } }; //! kontruktor mit dem zusändigen viewModel XQItemDelegate::XQItemDelegate( XQViewModel& viewModel) : QStyledItemDelegate(), _modelView{viewModel} { static XQItemEditorFactory s_EditorFactory; setItemEditorFactory(&s_EditorFactory); } //! gibt die interne tree table zurück XQTreeTable* XQItemDelegate::treeTable() const { return _modelView.treeTable(); } //! shortcut: gibt das XQItem für den gegebenen index zurück. XQItem& XQItemDelegate::xqItemFromIndex( const QModelIndex& index ) const { return _modelView.xqItemFromIndex( index ); } //! überladene paint-methode: zeichnet das item je nach render-style. void XQItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const { if( index.isValid() ) { XQItem& item = xqItemFromIndex( index ); switch( item.renderStyle() ) { case XQItem::HeaderStyle : return drawHeaderStyle( painter, option, item ); //return drawHeaderStyleX( painter, option, index ); case XQItem::ComboBoxStyle : return drawComboBoxStyle( painter, option, item ); case XQItem::ColorBarStyle : return drawColorBarStyle( painter, option, item ); // das funktioniert nicht unter windows11 //case XQItem::SpinBoxStyle : // return drawSpinBoxStyle( painter, option, item ); case XQItem::HiddenStyle : return; default: break; } // switch } else { qDebug() << " ---- paint: INDEX DEAD!" ; } QStyledItemDelegate::paint(painter, option, index); } //! einen section header im header-style zeichnen void XQItemDelegate::drawHeaderStyle(QPainter* painter, const QStyleOptionViewItem& option, const XQItem& item) const { QStyleOptionHeader headerOption; // use the header as "parent" for style init QWidget* srcWidget = treeTable();//->header(); headerOption.initFrom(srcWidget); headerOption.text = item.text();//index.data(Qt::DisplayRole).toString(); headerOption.rect = option.rect;//.adjusted(0,0,0,3); headerOption.styleObject = option.styleObject; // __ch: reduce inner offset when painting headerOption.textAlignment |= Qt::AlignVCenter; headerOption.icon = item.icon(); // save painter painter->save(); //value = index.data(Qt::ForegroundRole); //if (value.canConvert()) //headerOption.palette.setBrush(QPalette::Text, Qt::red ); //headerOption.palette.setBrush(QPalette::Window, Qt::red ); //QCommonStyle itemStyle; //qApp->style()->drawControl(QStyle::CE_Header, &headerOption, painter, srcWidget); //srcWidget->style()->drawControl(QStyle::CE_Header, &headerOption, painter, srcWidget); // warum das nur mit dem commonstyle, ist mir echt unklar. _commonStyle.drawControl(QStyle::CE_Header, &headerOption, painter, srcWidget); // restore painter painter->restore(); } //! Zeichnet prozent-werte als balken void XQItemDelegate::drawColorBarStyle(QPainter* painter, const QStyleOptionViewItem& option, const XQItem& item) const { //QStyledItemDelegate::paint(painter, option, item); // Wert aus dem Modell holen bool ok; int value = item.data(Qt::EditRole).toInt(&ok); if (!ok || value < 0 || value > 100) return; // Balkenbereich berechnen QRect rect = option.rect.adjusted(2, 2, -2, -2); // etwas Padding int barWidth = static_cast(rect.width() * (value / 100.0)); // Balken zeichnen painter->save(); painter->setRenderHint(QPainter::Antialiasing); QRect barRect(rect.left(), rect.top(), barWidth, rect.height()); QColor barColor = QColor(100, 180, 255); painter->setBrush(barColor); painter->setPen(Qt::NoPen); painter->drawRect(barRect); painter->setPen(Qt::black); painter->drawText(rect, Qt::AlignCenter, item.text() ); painter->restore(); } //! Zeichnet das Item als combo box. void XQItemDelegate::drawComboBoxStyle(QPainter* painter, const QStyleOptionViewItem& option, const XQItem& item) const { QStyleOptionComboBox comboOption; QWidget* srcWidget = qobject_cast(option.styleObject); comboOption.initFrom(srcWidget); // set options comboOption.rect = option.rect; comboOption.state = option.state | QStyle::State_Selected | QStyle::State_Enabled; // not editable => only visual, but painter needs to know it comboOption.editable = false; comboOption.currentText = item.text(); // decoration (if any) comboOption.currentIcon = qvariant_cast(item.data(Qt::DecorationRole)); comboOption.iconSize = comboOption.currentIcon.actualSize(QSize(option.rect.height() - 3, option.rect.height() - 3)); // save painter painter->save(); // hier wiederum funktioniert der '_commonStyle' nicht QStyle* widgetStyle = srcWidget->style(); // draw combo widgetStyle->drawComplexControl(QStyle::CC_ComboBox, &comboOption, painter, srcWidget); // and combobox label widgetStyle->drawControl(QStyle::CE_ComboBoxLabel, &comboOption, painter, srcWidget); // restore painter painter->restore(); } //! Zeichnet das Item als spin box. void XQItemDelegate::drawSpinBoxStyle(QPainter* painter, const QStyleOptionViewItem& option, const XQItem& item) const { qDebug() << " --- jawas +++? SPINBOX!"; QWidget* srcWidget = qobject_cast(option.styleObject); QStyleOptionViewItem viewOption(option); QStyleOptionSpinBox spinBoxOption; spinBoxOption.initFrom(srcWidget); initStyleOption(&viewOption, item.index()); if (option.state & QStyle::State_HasFocus) { viewOption.state = viewOption.state ^ QStyle::State_HasFocus; // Fokus nicht auf dem Hintergrund malen } QApplication::style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &viewOption, painter); spinBoxOption.rect = option.rect;//.adjusted( 0,0,-40,0); spinBoxOption.state = option.state | QStyle::State_Sunken; // Sunken-State für den "LineEdit"-Look spinBoxOption.buttonSymbols = QAbstractSpinBox::UpDownArrows; spinBoxOption.stepEnabled = QAbstractSpinBox::StepUpEnabled | QAbstractSpinBox::StepDownEnabled; spinBoxOption.frame = true; _commonStyle.drawComplexControl(QStyle::CC_SpinBox, &spinBoxOption, painter, nullptr); painter->drawText(spinBoxOption.rect, Qt::AlignCenter, item.text()); } //! Überschreibt QStyledItemDelegate::sizeHint(option, index); QSize XQItemDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const { return QStyledItemDelegate::sizeHint(option, index); } //! Erzeugt ein editor-widget, sofern ein gültiger content-Ptr vorhanden und ein editor-Type gesetzt ist. QWidget* XQItemDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const { Q_UNUSED(option); XQItem& item = xqItemFromIndex(index); XQItem::EditorType edType = item.editorType(); if( edType == XQItem::NoEditorType ) { qDebug() << "---- NO Content or NO EditorType"; return nullptr; } qDebug() << "---- ed type:" << XQItem::fetchEditorTypeToString( edType ) << ": " << edType; QWidget* editor = itemEditorFactory()->createEditor(edType, parent);; //return QStyledItemDelegate::createEditor( parent, option, index ); return editor; } //! Füttert einen editor mit den model-daten void XQItemDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const { XQItem& item = xqItemFromIndex( index ); XQItem::EditorType edType = item.editorType(); if( edType == XQItem::NoEditorType ) return; switch( edType ) { case XQItemType::ComboBoxType : { QComboBox* comboBox = qobject_cast(editor); // wir erwarten hier ein gültiges model? comboBox->setModel( item.fixedChoices()); comboBox->setCurrentText( item.data().toString() ); comboBox->showPopup(); return; } default: // wir benutzen hier die DisplayRole wenn der Inhalt schon formatiert ist. int role = item.renderStyle() == XQItem::FormattedStyle ? Qt::DisplayRole : Qt::EditRole; QVariant value = index.data(role); QByteArray userProp = editor->metaObject()->userProperty().name(); if (!userProp.isEmpty()) { if (!value.isValid()) value = QVariant(editor->property(userProp).metaType()); editor->setProperty(userProp, value); } } } //! Schreibt die daten aus dem editor ins model zurück void XQItemDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const { XQItem& item = xqItemFromIndex( index ); switch( item.editorType() ) { case XQItem::ComboBoxType : { QComboBox* comboBox = qobject_cast(editor); item.setData( comboBox->currentText(), Qt::DisplayRole ); return; } default: break; } QStyledItemDelegate::setModelData(editor, model, index); } //! Überschreibt QItemDelegate::updateEditorGeometry. Nicht implementiert. void XQItemDelegate::updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index) const { //qDebug() << " --- update Editor Geometry"; QStyledItemDelegate::updateEditorGeometry(editor, option, index); }