#include "propertyeditor.h" QWidget * Delegate::widgetForProperty(QWidget * parent, const QModelIndex & index) const { QWidget * w = 0; int type = 0; QVariant value = index.data(Qt::UserRole); if (index.data(Qt::UserRole + 2).toString() == "__flags") return 0; if (index.data(Qt::UserRole + 1).toString() == "__flag") { qulonglong key = index.data(Qt::UserRole).toULongLong(); value = index.parent().data(Qt::UserRole); //QMetaProperty prop = index.parent().data(Qt::UserRole + 1).value(); w = new QCheckBox(parent); type = 14; ((QCheckBox*)w)->setChecked(((value.toULongLong() & key) == key && key != 0) || (value.toULongLong() == 0 && key == 0)); ((QCheckBox*)w)->setText("0x" + QString::number(key, 16).toUpper()); connect((QCheckBox*)w, SIGNAL(clicked(bool)), this, SLOT(changedFlag())); //qDebug() << prop.enumerator().name(); } else { if (value.canConvert()) { PropertyValuePair prop = value.value(); if (prop.first.isEnumType()) { w = new QComboBox(parent); type = 13; ((QComboBox*)w)->setCurrentIndex(value.toInt()); w->setProperty("__prop", QVariant::fromValue(prop.first)); QMetaEnum menum = prop.first.enumerator(); for (int i = 0; i < menum.keyCount(); ++i) { ((QComboBox*)w)->addItem(QString(menum.key(i)) + " (0x" + QString::number(menum.value(i), 16).toUpper() + ")", menum.value(i)); if (menum.value(i) == prop.second.toInt()) ((QComboBox*)w)->setCurrentIndex(i); } connect((QComboBox*)w, SIGNAL(currentIndexChanged(int)), this, SLOT(changed())); } } else { switch (value.type()) { case QVariant::Int: w = new QSpinBox(parent); type = 2; ((QSpinBox*)w)->setRange(-0x7FFFFFFF, 0x7FFFFFFF); connect((QSpinBox*)w, SIGNAL(valueChanged(int)), this, SLOT(changed())); break; case QVariant::UInt: w = new QSpinBox(parent); type = 3; ((QSpinBox*)w)->setRange(0, 0xFFFFFFFF); connect((QSpinBox*)w, SIGNAL(valueChanged(int)), this, SLOT(changed())); break; case QVariant::LongLong: w = new QSpinBox(parent); type = 4; ((QSpinBox*)w)->setRange(-0x7FFFFFFF, 0x7FFFFFFF); connect((QSpinBox*)w, SIGNAL(valueChanged(int)), this, SLOT(changed())); break; case QVariant::ULongLong: w = new QSpinBox(parent); type = 5; ((QSpinBox*)w)->setRange(0, 0xFFFFFFFF); connect((QSpinBox*)w, SIGNAL(valueChanged(int)), this, SLOT(changed())); break; case QVariant::Double: w = new QDoubleSpinBox(parent); type = 6; ((QDoubleSpinBox*)w)->setRange(-999999999, 999999999); ((QDoubleSpinBox*)w)->setDecimals(3); connect((QDoubleSpinBox*)w, SIGNAL(valueChanged(double)), this, SLOT(changed())); break; case QVariant::Bool: w = new QCheckBox(parent); type = 7; ((QCheckBox*)w)->setChecked(value.toBool()); connect((QCheckBox*)w, SIGNAL(toggled(bool)), this, SLOT(changed())); break; case QVariant::Color: w = new ColorButton(parent); type = 8; ((ColorButton*)w)->setUseAlphaChannel(true); ((ColorButton*)w)->setColor(value.value()); connect((ColorButton*)w, SIGNAL(colorChanged(QColor)), this, SLOT(changed())); break; case QVariant::Point: w = new QPointEdit(parent); type = 9; ((QPointEdit*)w)->setDecimals(0); ((QPointEdit*)w)->setValue(QPointF(value.toPoint())); connect((QPointEdit*)w, SIGNAL(valueChanged(QPointF)), this, SLOT(changed())); break; case QVariant::PointF: w = new QPointEdit(parent); type = 10; ((QPointEdit*)w)->setDecimals(3); ((QPointEdit*)w)->setValue(value.toPointF()); connect((QPointEdit*)w, SIGNAL(valueChanged(QPointF)), this, SLOT(changed())); break; case QVariant::Rect: w = new QRectEdit(parent); type = 11; ((QRectEdit*)w)->setDecimals(0); ((QRectEdit*)w)->setValue(QRectF(value.toRect())); connect((QRectEdit*)w, SIGNAL(valueChanged(QRectF)), this, SLOT(changed())); break; case QVariant::RectF: w = new QRectEdit(parent); type = 12; ((QRectEdit*)w)->setDecimals(3); ((QRectEdit*)w)->setValue(value.toRectF()); connect((QRectEdit*)w, SIGNAL(valueChanged(QRectF)), this, SLOT(changed())); break; case QVariant::String: default: w = new CLineEdit(parent); type = 1; ((CLineEdit*)w)->setDefaultText(value.toString()); connect((CLineEdit*)w, SIGNAL(textChanged(QString)), this, SLOT(changed())); break; } } } if (w == 0) return 0; /*QPalette pal = w->palette(); pal.setColor(QPalette::Window, Qt::white); w->setPalette(pal);*/ w->setAutoFillBackground(true); w->setProperty("__type", type); return w; } void Delegate::setWidgetProperty(QWidget * w, const QVariant & value) const { if (w == 0) return; switch (w->property("__type").toInt()) { case 1: ((CLineEdit*)w)->setText(value.toString()); break; case 2: case 3: case 4: case 5: ((QSpinBox*)w)->setValue(value.toInt()); break; case 6: ((QDoubleSpinBox*)w)->setValue(value.toDouble()); break; case 7: ((QCheckBox*)w)->setChecked(value.toBool()); break; case 8: ((ColorButton*)w)->setColor(value.value()); break; case 9: ((QPointEdit*)w)->setValue(value.value()); break; case 10: ((QPointEdit*)w)->setValue(value.value()); break; case 11: ((QRectEdit*)w)->setValue(value.value()); break; case 12: ((QRectEdit*)w)->setValue(value.value()); break; } } const QVariant Delegate::widgetProperty(QWidget * w) const { if (w == 0) return QVariant(); switch (w->property("__type").toInt()) { case 1: return QVariant::fromValue(((CLineEdit*)w)->text()); break; case 2: return QVariant::fromValue(((QSpinBox*)w)->value()); break; case 3: return QVariant::fromValue(((QSpinBox*)w)->value()); break; case 4: return QVariant::fromValue(((QSpinBox*)w)->value()); break; case 5: return QVariant::fromValue(((QSpinBox*)w)->value()); break; case 6: return QVariant::fromValue(((QDoubleSpinBox*)w)->value()); break; case 7: return QVariant::fromValue(((QCheckBox*)w)->isChecked()); break; case 8: return QVariant::fromValue(((ColorButton*)w)->color()); break; case 9: return QVariant::fromValue(((QPointEdit*)w)->value().toPoint()); break; case 10: return QVariant::fromValue(((QPointEdit*)w)->value()); break; case 11: return QVariant::fromValue(((QRectEdit*)w)->value().toRect()); break; case 12: return QVariant::fromValue(((QRectEdit*)w)->value()); break; case 13: return QVariant::fromValue(PropertyValuePair(w->property("__prop").value(), ((QComboBox*)w)->itemData(((QComboBox*)w)->currentIndex()))); break; default: return QVariant(); break; } return QVariant(); } void Delegate::setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const { if (index.data(Qt::UserRole + 1).toString() != "__flag") model->setData(index, widgetProperty(editor), Qt::UserRole); } void Delegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const { QStyledItemDelegate::paint(painter, option, index); QVariant value = index.data(Qt::UserRole); QStyle * style = QApplication::style(); QStyleOption * so = 0; QStyleOptionComplex * soc = 0; QString text; QRect rect; QPalette::ColorRole role = (option.state.testFlag(QStyle::State_Selected) && option.state.testFlag(QStyle::State_Active) ? QPalette::HighlightedText : QPalette::WindowText); if (index.data(Qt::UserRole + 2).toString() == "__flags") { text = "0x" + QString::number(value.toInt(), 16).toUpper(); style->drawItemText(painter, style->itemTextRect(option.fontMetrics, option.rect, Qt::AlignLeft | Qt::AlignVCenter, true, text), Qt::AlignLeft | Qt::AlignVCenter, option.palette, true, text, role); return; } if (index.data(Qt::UserRole + 1) == "__flag") { qulonglong key = index.data(Qt::UserRole).toULongLong(); value = index.parent().data(Qt::UserRole); so = new QStyleOptionButton(); so->rect = option.rect; so->palette = option.palette; so->fontMetrics = option.fontMetrics; ((QStyleOptionButton*)so)->state = (((value.toULongLong() & key) == key && key != 0) || (value.toULongLong() == 0 && key == 0) ? QStyle::State_On : QStyle::State_Off) | option.state; ((QStyleOptionButton*)so)->text = "0x" + QString::number(key, 16).toUpper(); if (option.state.testFlag(QStyle::State_Selected)) so->palette.setColor(QPalette::WindowText, so->palette.color(QPalette::HighlightedText)); style->drawControl(QStyle::CE_CheckBox, so, painter); } else { if (value.canConvert()) { PropertyValuePair prop = value.value(); if (prop.first.isEnumType()) { QMetaEnum menum = prop.first.enumerator(); for (int i = 0; i < menum.keyCount(); ++i) { if (menum.value(i) == prop.second.toInt()) { text = QString(menum.key(i)) + " (0x" + QString::number(menum.value(i), 16).toUpper() + ")"; break; } } style->drawItemText(painter, style->itemTextRect(option.fontMetrics, option.rect, Qt::AlignLeft | Qt::AlignVCenter, true, text), Qt::AlignLeft | Qt::AlignVCenter, option.palette, true, text, role); } } else { switch (value.type()) { case QVariant::Int: text.setNum(value.toInt()); style->drawItemText(painter, style->itemTextRect(option.fontMetrics, option.rect, Qt::AlignLeft | Qt::AlignVCenter, true, text), Qt::AlignLeft | Qt::AlignVCenter, option.palette, true, text, role); break; case QVariant::UInt: text.setNum(value.toUInt()); style->drawItemText(painter, style->itemTextRect(option.fontMetrics, option.rect, Qt::AlignLeft | Qt::AlignVCenter, true, text), Qt::AlignLeft | Qt::AlignVCenter, option.palette, true, text, role); break; case QVariant::LongLong: text.setNum(value.toLongLong()); style->drawItemText(painter, style->itemTextRect(option.fontMetrics, option.rect, Qt::AlignLeft | Qt::AlignVCenter, true, text), Qt::AlignLeft | Qt::AlignVCenter, option.palette, true, text, role); break; case QVariant::ULongLong: text.setNum(value.toULongLong()); style->drawItemText(painter, style->itemTextRect(option.fontMetrics, option.rect, Qt::AlignLeft | Qt::AlignVCenter, true, text), Qt::AlignLeft | Qt::AlignVCenter, option.palette, true, text, role); break; case QVariant::Double: text.setNum(value.toDouble(), 'f', 3); style->drawItemText(painter, style->itemTextRect(option.fontMetrics, option.rect, Qt::AlignLeft | Qt::AlignVCenter, true, text), Qt::AlignLeft | Qt::AlignVCenter, option.palette, true, text, role); break; case QVariant::Bool: so = new QStyleOptionButton(); so->rect = option.rect; so->state = option.state; so->palette = option.palette; so->fontMetrics = option.fontMetrics; ((QStyleOptionButton*)so)->state = (value.toBool() ? QStyle::State_On : QStyle::State_Off) | option.state; style->drawControl(QStyle::CE_CheckBox, so, painter); break; case QVariant::Color: rect = option.rect;//style->subElementRect(QStyle::QStyle::SE_FrameContents, so); rect.setRect(rect.x() + 3, rect.y() + 3, rect.width() - 6, rect.height() - 6); painter->fillRect(rect, ab); painter->fillRect(rect, value.value()); break; case QVariant::Point: text = pointString(value.toPoint()); style->drawItemText(painter, style->itemTextRect(option.fontMetrics, option.rect, Qt::AlignLeft | Qt::AlignVCenter, true, text), Qt::AlignLeft | Qt::AlignVCenter, option.palette, true, text, role); break; case QVariant::PointF: text = pointString(value.toPointF()); style->drawItemText(painter, style->itemTextRect(option.fontMetrics, option.rect, Qt::AlignLeft | Qt::AlignVCenter, true, text), Qt::AlignLeft | Qt::AlignVCenter, option.palette, true, text, role); break; case QVariant::Rect: text = rectString(value.toRect()); style->drawItemText(painter, style->itemTextRect(option.fontMetrics, option.rect, Qt::AlignLeft | Qt::AlignVCenter, true, text), Qt::AlignLeft | Qt::AlignVCenter, option.palette, true, text, role); break; case QVariant::RectF: text = rectString(value.toRectF()); style->drawItemText(painter, style->itemTextRect(option.fontMetrics, option.rect, Qt::AlignLeft | Qt::AlignVCenter, true, text), Qt::AlignLeft | Qt::AlignVCenter, option.palette, true, text, role); break; case QVariant::String: default: style->drawItemText(painter, style->itemTextRect(option.fontMetrics, option.rect, Qt::AlignLeft | Qt::AlignVCenter, true, value.toString()), Qt::AlignLeft | Qt::AlignVCenter, option.palette, true, value.toString(), role); break; } } } /*so = new QStyleOptionFrame(); so->rect = option.rect; so->state = option.state; so->palette = option.palette; so->fontMetrics = option.fontMetrics; ((QStyleOptionFrame*)so)->state = (value.toBool() ? QStyle::State_On : QStyle::State_Off); style->drawPrimitive(QStyle::PE_PanelLineEdit, so, painter); style->drawPrimitive(QStyle::PE_FrameLineEdit, so, painter); break;*/ if (so != 0) delete so; if (soc != 0) delete soc; } void Delegate::changedFlag() { QAbstractItemModel * model = const_cast(cmi.model()); model->setData(cmi, qobject_cast(sender())->isChecked(), Qt::UserRole + 3); QModelIndex p = cmi.parent(), mi; int row = 0; qulonglong val = 0; QList chldr; mi = p.child(row, 1); while (mi.isValid()) { chldr << mi; model->setData(mi, !mi.data(Qt::UserRole + 4).toBool(), Qt::UserRole + 4); mi = p.child(++row, 1); } bool cc = cmi.data(Qt::UserRole + 3).toBool(); qulonglong cv = cmi.data(Qt::UserRole).toULongLong(); //qDebug() << "*****"; if (cc && cv == 0) { val = 0; //qDebug() << "null" << cv; } else { if (!cc && cv != 0) { //qDebug() << "uncheck" << cv; for (int i = 0; i < chldr.size(); ++i) { if (chldr[i] == cmi) continue; //qDebug() << (chldr[i].data(Qt::UserRole).toULongLong() & cv); if (chldr[i].data(Qt::UserRole).toULongLong() & cv) model->setData(chldr[i], false, Qt::UserRole + 3); } } for (int i = 0; i < chldr.size(); ++i) { //qDebug() << chldr[i].data(Qt::UserRole + 3).toBool(); if (chldr[i].data(Qt::UserRole + 3).toBool()) val |= chldr[i].data(Qt::UserRole).toULongLong(); } } for (int i = 0; i < chldr.size(); ++i) { if (chldr[i] == cmi) continue; cv = chldr[i].data(Qt::UserRole).toULongLong(); model->setData(chldr[i], ((val & cv) == cv && cv != 0) || (val == 0 && cv == 0), Qt::UserRole + 3); } //qDebug() << val; model->setData(p, val, Qt::UserRole); model->setData(p.sibling(p.row(), 1), val, Qt::UserRole); } PropertyEditor::PropertyEditor(QWidget * parent): QTreeWidget(parent) { object = 0; active_ = false; configTree(); connect(this, SIGNAL(itemClicked(QTreeWidgetItem * , int)), this, SLOT(itemClicked(QTreeWidgetItem * , int))); connect(this, SIGNAL(itemChanged(QTreeWidgetItem * , int)), this, SLOT(itemChanged(QTreeWidgetItem * , int))); } PropertyEditor::~PropertyEditor() { } void PropertyEditor::changeEvent(QEvent * e) { QTreeWidget::changeEvent(e); if (e->type() == QEvent::LanguageChange) { configTree(); return; } } void PropertyEditor::configTree() { setColumnCount(2); setRootIsDecorated(false); setColumnWidth(0, 170); setColumnWidth(1, 10); header()->setStretchLastSection(true); QStringList lbls; lbls << tr("Property") << tr("Value"); setHeaderLabels(lbls); setAlternatingRowColors(true); setItemDelegateForColumn(1, new Delegate()); } void PropertyEditor::itemClicked(QTreeWidgetItem * item, int column) { if (column == 0) item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); else { item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable); editItem(item, 1); } } void PropertyEditor::itemChanged(QTreeWidgetItem * item, int column) { if (!active_) return; if (column != 1) return; QVariant value = item->data(1, Qt::UserRole); if (value.canConvert()) { value = value.value().second; } object->setProperty(item->text(0).toLatin1(), value); } void PropertyEditor::rebuild() { clear(); configTree(); if (object == 0) return; active_ = false; const QMetaObject * mo = object->metaObject(); QList mol; while (mo != 0) { mol.push_front(mo); mo = mo->superClass(); } int ps, pe; QTreeWidgetItem * ti, * tli, * tfi; QVariant value; // QWidget * pw = 0; int chue = 0; QColor bc; font_b = font(); font_b.setBold(true); foreach (const QMetaObject * o, mol) { ps = o->propertyOffset(); pe = o->propertyCount();// - ps; //qDebug() << i->className() << ps << pe; tli = new QTreeWidgetItem(); tli->setText(0, o->className()); tli->setFont(0, font_b); setItemBackColor(tli, Qt::darkGray); setItemForeColor(tli, Qt::white); addTopLevelItem(tli); setFirstItemColumnSpanned(tli, true); tli->setExpanded(true); for (int i = ps; i < pe; ++i) { props << o->property(i); value = o->property(i).read(object); ti = new QTreeWidgetItem(); ti->setSizeHint(1, QSize(20, 20)); bc.setHsv(chue, 60, 245 + (i % 2) * 20 - 10); setItemBackColor(ti, bc); ti->setText(0, o->property(i).name()); if (props.back().isFlagType()) { QMetaEnum menum = props.back().enumerator(); for (int j = 0; j < menum.keyCount(); ++j) { tfi = new QTreeWidgetItem(); tfi->setText(0, menum.key(j)); tfi->setData(1, Qt::UserRole, menum.value(j)); tfi->setData(1, Qt::UserRole + 1, "__flag"); tfi->setData(1, Qt::UserRole + 2, value.toULongLong()); tfi->setData(1, Qt::UserRole + 3, (value.toULongLong() & menum.value(j)) > 0); tfi->setSizeHint(1, QSize(20, 20)); bc.setHsv(chue, 60, 245 + ((i + j + 1) % 2) * 20 - 10); setItemBackColor(tfi, bc); ti->addChild(tfi); } ti->setData(0, Qt::UserRole, value); ti->setData(1, Qt::UserRole, value); ti->setData(1, Qt::UserRole + 2, "__flags"); ti->setData(0, Qt::UserRole + 1, QVariant::fromValue(props.back())); } else if (props.back().isEnumType()) value.setValue(PropertyValuePair(props.back(), value)); //ti->setText(1, value.toString()); ti->setData(1, Qt::UserRole, value); tli->addChild(ti); //const_cast(indexFromItem(ti, 1)).; //if (pw != 0) setItemWidget(ti, 1, pw); } chue += 60; chue %= 360; } active_ = true; } void PropertyEditor::refresh() { }