blob: 4310d2ec112642802ff04ae64b6c23c783785b9f [file] [log] [blame]
#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"