| #include "argumentseditor.h" |
| |
| #include "apitracecall.h" |
| |
| #include <QDebug> |
| #include <QDoubleSpinBox> |
| #include <QItemEditorFactory> |
| #include <QSpinBox> |
| |
| #include <limits.h> |
| #include <float.h> |
| |
| |
| static bool |
| isVariantEditable(const QVariant &var) |
| { |
| if (var.canConvert<ApiArray>()) { |
| ApiArray array = var.value<ApiArray>(); |
| QVector<QVariant> vals = array.values(); |
| if (vals.isEmpty()) |
| return false; |
| else |
| return isVariantEditable(vals.first()); |
| } |
| switch (var.userType()) { |
| case QVariant::Bool: |
| case QVariant::Int: |
| case QVariant::UInt: |
| case QVariant::LongLong: |
| case QVariant::ULongLong: |
| case QMetaType::Float: |
| case QVariant::Double: |
| case QVariant::String: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| static bool |
| isVariantStringArray(const QVariant &var) |
| { |
| if (var.isNull() || var.userType() != QMetaType::type("ApiArray")) |
| return false; |
| |
| ApiArray array = var.value<ApiArray>(); |
| QVector<QVariant> origValues = array.values(); |
| if (origValues.isEmpty() || |
| origValues.first().userType() != QVariant::String) |
| return false; |
| |
| return true; |
| } |
| |
| |
| |
| void setArgumentsItemEditorFactory () |
| { |
| QItemEditorCreatorBase *booleanComboBoxEditorCreator = |
| new QStandardItemEditorCreator<BooleanComboBoxEditorCreator>(); |
| QItemEditorCreatorBase *uIntEditorCreator = |
| new QStandardItemEditorCreator<UIntEditorCreator>(); |
| QItemEditorCreatorBase *intEditorCreator = |
| new QStandardItemEditorCreator<IntEditorCreator>(); |
| QItemEditorCreatorBase *uLongLongEditorCreator = |
| new QStandardItemEditorCreator<ULongLongEditorCreator>(); |
| QItemEditorCreatorBase *longLongEditorCreator = |
| new QStandardItemEditorCreator<LongLongEditorCreator>(); |
| QItemEditorCreatorBase *pixmapEditorCreator = |
| new QStandardItemEditorCreator<PixmapEditorCreator>(); |
| QItemEditorCreatorBase *floatEditorCreator = |
| new QStandardItemEditorCreator<FloatEditorCreator>(); |
| QItemEditorCreatorBase *doubleEditorCreator = |
| new QStandardItemEditorCreator<DoubleEditorCreator>(); |
| QItemEditorCreatorBase *stringEditorCreator = |
| new QStandardItemEditorCreator<StringEditorCreator>(); |
| QItemEditorCreatorBase *invalidEditorCreator = |
| new QStandardItemEditorCreator<InvalidEditorCreator>(); |
| |
| QItemEditorFactory *factory = |
| new QItemEditorFactory(); |
| |
| QVariant::Type typeFloat = static_cast<QVariant::Type> (qMetaTypeId<float>()); |
| |
| factory->registerEditor(QVariant::Bool, booleanComboBoxEditorCreator); |
| factory->registerEditor(QVariant::UInt, uIntEditorCreator); |
| factory->registerEditor(QVariant::Int, intEditorCreator); |
| factory->registerEditor(QVariant::ULongLong, uLongLongEditorCreator); |
| factory->registerEditor(QVariant::LongLong, longLongEditorCreator); |
| factory->registerEditor(QVariant::Pixmap, pixmapEditorCreator); |
| factory->registerEditor(typeFloat, floatEditorCreator); |
| factory->registerEditor(QVariant::Double, doubleEditorCreator); |
| factory->registerEditor(QVariant::String, stringEditorCreator); |
| factory->registerEditor(QVariant::Invalid, invalidEditorCreator); |
| |
| QItemEditorFactory::setDefaultFactory(factory); |
| } |
| |
| BooleanComboBox::BooleanComboBox(QWidget *parent) |
| : QComboBox(parent) |
| { |
| addItem(tr("False")); |
| addItem(tr("True")); |
| } |
| |
| void BooleanComboBox::setValue(bool value) |
| { |
| setCurrentIndex(value ? 1 : 0); |
| } |
| |
| bool BooleanComboBox::value() const |
| { |
| return (currentIndex() == 1); |
| } |
| |
| ArgumentsEditor::ArgumentsEditor(QWidget *parent) |
| : QDialog(parent), |
| m_model(new QStandardItemModel()), |
| m_call(0) |
| { |
| init(); |
| } |
| |
| ArgumentsEditor::~ArgumentsEditor() |
| { |
| delete m_model; |
| } |
| |
| void ArgumentsEditor::setCall(ApiTraceCall *call) |
| { |
| m_call = call; |
| setupCall(); |
| } |
| |
| ApiTraceCall * ArgumentsEditor::call() const |
| { |
| return m_call; |
| } |
| |
| void ArgumentsEditor::init() |
| { |
| m_ui.setupUi(this); |
| |
| connect(m_ui.selectStringCB, SIGNAL(currentIndexChanged(int)), |
| SLOT(currentSourceChanged(int))); |
| connect(m_ui.glslEdit, SIGNAL(textChanged()), |
| SLOT(sourceChanged())); |
| connect(m_ui.revertButton, SIGNAL(clicked()), |
| SLOT(revert())); |
| |
| setArgumentsItemEditorFactory (); |
| |
| m_ui.argsTree->setModel(m_model); |
| |
| } |
| |
| void ArgumentsEditor::setupCall() |
| { |
| m_model->clear(); |
| |
| QStringList headers; |
| headers.append(tr("Argument")); |
| headers.append(tr("Value")); |
| m_model->setColumnCount(2); |
| m_model->setHorizontalHeaderLabels(headers); |
| m_ui.argsTabWidget->removeTab( |
| m_ui.argsTabWidget->indexOf(m_ui.shaderTab)); |
| |
| if (!m_call) |
| return; |
| |
| m_ui.callLabel->setText(m_call->name()); |
| QStandardItem *rootItem = m_model->invisibleRootItem(); |
| for (int i = 0; i < m_call->argNames().count(); ++i) { |
| QString argName = m_call->argNames()[i]; |
| QVariant val = m_call->arguments()[i]; |
| QStandardItem *nameItem = new QStandardItem(argName); |
| nameItem->setFlags(nameItem->flags() ^ Qt::ItemIsEditable); |
| QList<QStandardItem*> topRow; |
| topRow.append(nameItem); |
| |
| if (val.canConvert<ApiArray>()) { |
| ApiArray array = val.value<ApiArray>(); |
| QVector<QVariant> vals = array.values(); |
| |
| QVariant firstVal = vals.value(0); |
| if (firstVal.userType() == QVariant::String) { |
| m_ui.argsTabWidget->addTab( |
| m_ui.shaderTab, argName); |
| setupShaderEditor(vals); |
| delete nameItem; |
| continue; |
| } else if (isVariantEditable(firstVal)) { |
| for (int i = 0; i < vals.count(); ++i) { |
| QList<QStandardItem*> row; |
| |
| QStandardItem *idx = new QStandardItem(); |
| idx->setFlags(idx->flags() ^ Qt::ItemIsEditable); |
| idx->setText(tr("%1)").arg(i)); |
| |
| QStandardItem *col = new QStandardItem(); |
| col->setFlags(col->flags() | Qt::ItemIsEditable); |
| col->setData(vals[i], Qt::EditRole); |
| row.append(idx); |
| row.append(col); |
| nameItem->appendRow(row); |
| } |
| } else { |
| qDebug()<<"\tUnsupported array = "<<firstVal; |
| delete nameItem; |
| continue; |
| } |
| } else if (val.canConvert<ApiPointer>()) { |
| ApiPointer ptr = val.value<ApiPointer>(); |
| QStandardItem *item = new QStandardItem(); |
| item->setFlags(item->flags() ^ Qt::ItemIsEditable); |
| item->setText(ptr.toString()); |
| QIcon icon(":/resources/emblem-locked.png"); |
| item->setIcon(icon); |
| item->setToolTip(tr("Argument is read-only")); |
| topRow.append(item); |
| } else if (val.canConvert<ApiEnum>()) { |
| ApiEnum en = val.value<ApiEnum>(); |
| QStandardItem *item = new QStandardItem(); |
| item->setFlags(item->flags() ^ Qt::ItemIsEditable); |
| item->setText(en.toString()); |
| QIcon icon(":/resources/emblem-locked.png"); |
| item->setIcon(icon); |
| item->setToolTip(tr("Argument is read-only")); |
| topRow.append(item); |
| } else if (val.canConvert<ApiBitmask>()) { |
| ApiBitmask mask = val.value<ApiBitmask>(); |
| QStandardItem *item = new QStandardItem(); |
| item->setFlags(item->flags() ^ Qt::ItemIsEditable); |
| item->setText(mask.toString()); |
| QIcon icon(":/resources/emblem-locked.png"); |
| item->setIcon(icon); |
| item->setToolTip(tr("Argument is read-only")); |
| topRow.append(item); |
| } else if (val.canConvert<ApiStruct>()) { |
| ApiStruct str = val.value<ApiStruct>(); |
| QStandardItem *item = new QStandardItem(); |
| item->setFlags(item->flags() ^ Qt::ItemIsEditable); |
| item->setText(str.toString()); |
| QIcon icon(":/resources/emblem-locked.png"); |
| item->setIcon(icon); |
| item->setToolTip(tr("Argument is read-only")); |
| topRow.append(item); |
| } else if (val.userType() == QVariant::ByteArray) { |
| QByteArray ba = val.value<QByteArray>(); |
| QStandardItem *item = new QStandardItem(); |
| item->setFlags(item->flags() ^ Qt::ItemIsEditable); |
| item->setText( |
| tr("<binary data, size = %1 bytes>").arg(ba.size())); |
| QIcon icon(":/resources/emblem-locked.png"); |
| item->setIcon(icon); |
| item->setToolTip(tr("Argument is read-only")); |
| topRow.append(item); |
| } else { |
| QStandardItem *item |
| = new QStandardItem(); |
| |
| if (isVariantEditable(val)) { |
| item->setFlags(item->flags() | Qt::ItemIsEditable); |
| } else { |
| QIcon icon(":/resources/emblem-locked.png"); |
| item->setIcon(icon); |
| item->setFlags(item->flags() ^ Qt::ItemIsEditable); |
| item->setToolTip(tr("Argument is read-only")); |
| } |
| item->setData(val, Qt::EditRole); |
| topRow.append(item); |
| } |
| rootItem->appendRow(topRow); |
| } |
| } |
| |
| void ArgumentsEditor::setupShaderEditor(const QVector<QVariant> &sources) |
| { |
| m_ui.selectStringCB->clear(); |
| m_ui.glslEdit->clear(); |
| for (int i = 0; i < sources.count(); ++i) { |
| m_ui.selectStringCB->addItem( |
| tr("Shader string: %1").arg(i), |
| sources[i]); |
| } |
| m_ui.selectStringCB->setCurrentIndex(0); |
| } |
| |
| void ArgumentsEditor::currentSourceChanged(int idx) |
| { |
| QVariant source = m_ui.selectStringCB->itemData(idx); |
| QString str = source.toString(); |
| m_ui.glslEdit->setPlainText(source.toString()); |
| m_ui.lengthLabel->setText( |
| tr("%1").arg(str.length())); |
| } |
| |
| void ArgumentsEditor::sourceChanged() |
| { |
| QString str = m_ui.glslEdit->toPlainText(); |
| m_ui.lengthLabel->setText( |
| tr("%1").arg(str.length())); |
| |
| m_ui.selectStringCB->setItemData( |
| m_ui.selectStringCB->currentIndex(), |
| str); |
| } |
| |
| void ArgumentsEditor::accept() |
| { |
| QStringList argNames = m_call->argNames(); |
| QVector<QVariant> originalValues = m_call->arguments(); |
| QVector<QVariant> newValues; |
| bool changed = false; |
| for (int i = 0; i < argNames.count(); ++i) { |
| bool valChanged = false; |
| QString argName = argNames[i]; |
| QVariant argValue = originalValues[i]; |
| QVariant editorValue = valueForName(argName, argValue, &valChanged); |
| |
| newValues.append(editorValue); |
| #if 0 |
| qDebug()<<"Arg = "<<argName; |
| qDebug()<<"\toriginal = "<<argValue; |
| qDebug()<<"\teditor = "<<editorValue; |
| qDebug()<<"\tchanged = "<<valChanged; |
| #endif |
| if (valChanged) |
| changed = true; |
| } |
| if (changed) |
| m_call->setEditedValues(newValues); |
| QDialog::accept(); |
| } |
| |
| QVariant ArgumentsEditor::valueForName(const QString &name, |
| const QVariant &originalValue, |
| bool *changed) const |
| { |
| QVariant val; |
| |
| *changed = false; |
| |
| //Handle string arrays specially |
| if (isVariantStringArray(originalValue)) { |
| ApiArray array = originalValue.value<ApiArray>(); |
| return arrayFromEditor(array, changed); |
| } |
| |
| if (!isVariantEditable(originalValue)) { |
| return originalValue; |
| } |
| |
| for (int topRow = 0; topRow < m_model->rowCount(); ++topRow) { |
| QModelIndex nameIdx = m_model->index(topRow, 0, QModelIndex()); |
| QString argName = nameIdx.data().toString(); |
| /* we display shaders in a separate widget so |
| * the ordering might be different */ |
| if (argName == name) { |
| if (originalValue.userType() == QMetaType::type("ApiArray")) { |
| ApiArray array = originalValue.value<ApiArray>(); |
| val = arrayFromIndex(nameIdx, array, changed); |
| } else { |
| QModelIndex valIdx = m_model->index(topRow, 1, QModelIndex()); |
| val = valIdx.data(); |
| if (val != originalValue) |
| *changed = true; |
| } |
| } |
| } |
| return val; |
| } |
| |
| QVariant ArgumentsEditor::arrayFromIndex(const QModelIndex &parentIndex, |
| const ApiArray &origArray, |
| bool *changed) const |
| { |
| QVector<QVariant> origValues = origArray.values(); |
| |
| *changed = false; |
| |
| if (origValues.isEmpty()) |
| return QVariant::fromValue(ApiArray()); |
| |
| QVector<QVariant> lst; |
| for (int i = 0; i < origValues.count(); ++i) { |
| QModelIndex valIdx = m_model->index(i, 1, parentIndex); |
| QVariant var = valIdx.data(); |
| QVariant origValue = origValues[i]; |
| if (var != origValue) |
| *changed = true; |
| //qDebug()<<"\t\tarray "<<i<<") "<<var; |
| lst.append(var); |
| } |
| return QVariant::fromValue(ApiArray(lst)); |
| } |
| |
| QVariant ArgumentsEditor::arrayFromEditor(const ApiArray &origArray, |
| bool *changed) const |
| { |
| QVector<QVariant> vals; |
| QVector<QVariant> origValues = origArray.values(); |
| |
| Q_ASSERT(isVariantStringArray(QVariant::fromValue(origArray))); |
| *changed = false; |
| //shaders |
| for (int i = 0; i < m_ui.selectStringCB->count(); ++i) { |
| QVariant val = m_ui.selectStringCB->itemData(i); |
| QVariant origValue = origValues[i]; |
| if (origValue != val) |
| *changed = true; |
| vals.append(val); |
| } |
| return QVariant::fromValue(ApiArray(vals)); |
| } |
| |
| void ArgumentsEditor::revert() |
| { |
| m_call->revert(); |
| setupCall(); |
| } |
| |
| #include "argumentseditor.moc" |