]> git.cworth.org Git - apitrace/blob - gui/argumentseditor.cpp
Use skiplist-based FastCallSet within trace::CallSet
[apitrace] / gui / argumentseditor.cpp
1 #include "argumentseditor.h"
2
3 #include "apitracecall.h"
4
5 #include <QDebug>
6 #include <QDoubleSpinBox>
7 #include <QItemEditorFactory>
8 #include <QSpinBox>
9
10 #include <limits.h>
11 #include <float.h>
12
13
14 static bool
15 isVariantEditable(const QVariant &var)
16 {
17     if (var.canConvert<ApiArray>()) {
18         ApiArray array = var.value<ApiArray>();
19         QVector<QVariant> vals = array.values();
20         if (vals.isEmpty())
21             return false;
22         else
23             return isVariantEditable(vals.first());
24     }
25     switch (var.userType()) {
26     case QVariant::Bool:
27     case QVariant::Int:
28     case QVariant::UInt:
29     case QVariant::LongLong:
30     case QVariant::ULongLong:
31     case QMetaType::Float:
32     case QVariant::Double:
33         return true;
34     default:
35         return false;
36     }
37 }
38
39 static bool
40 isVariantStringArray(const QVariant &var)
41 {
42     if (var.isNull() || var.userType() != QMetaType::type("ApiArray"))
43         return false;
44
45     ApiArray array = var.value<ApiArray>();
46     QVector<QVariant> origValues = array.values();
47     if (origValues.isEmpty() ||
48         origValues.first().userType() != QVariant::String)
49         return false;
50
51     return true;
52 }
53
54
55
56 void setArgumentsItemEditorFactory ()
57 {
58     QItemEditorCreatorBase *booleanComboBoxEditorCreator =
59     new QStandardItemEditorCreator<BooleanComboBoxEditorCreator>();
60     QItemEditorCreatorBase *uIntEditorCreator =
61     new QStandardItemEditorCreator<UIntEditorCreator>();
62     QItemEditorCreatorBase *intEditorCreator =
63     new QStandardItemEditorCreator<IntEditorCreator>();
64     QItemEditorCreatorBase *uLongLongEditorCreator =
65     new QStandardItemEditorCreator<ULongLongEditorCreator>();
66     QItemEditorCreatorBase *longLongEditorCreator =
67     new QStandardItemEditorCreator<LongLongEditorCreator>();
68     QItemEditorCreatorBase *pixmapEditorCreator =
69     new QStandardItemEditorCreator<PixmapEditorCreator>();
70     QItemEditorCreatorBase *floatEditorCreator =
71     new QStandardItemEditorCreator<FloatEditorCreator>();
72     QItemEditorCreatorBase *doubleEditorCreator =
73     new QStandardItemEditorCreator<DoubleEditorCreator>();
74     QItemEditorCreatorBase *invalidEditorCreator =
75     new QStandardItemEditorCreator<InvalidEditorCreator>();
76
77     QItemEditorFactory *factory =
78         new QItemEditorFactory();
79
80     QVariant::Type typeFloat = static_cast<QVariant::Type> (qMetaTypeId<float>());
81
82     factory->registerEditor(QVariant::Bool, booleanComboBoxEditorCreator);
83     factory->registerEditor(QVariant::UInt, uIntEditorCreator);
84     factory->registerEditor(QVariant::Int, intEditorCreator);
85     factory->registerEditor(QVariant::ULongLong, uLongLongEditorCreator);
86     factory->registerEditor(QVariant::LongLong, longLongEditorCreator);
87     factory->registerEditor(QVariant::Pixmap, pixmapEditorCreator);
88     factory->registerEditor(typeFloat, floatEditorCreator);
89     factory->registerEditor(QVariant::Double, doubleEditorCreator);
90     factory->registerEditor(QVariant::Invalid, invalidEditorCreator);
91
92     QItemEditorFactory::setDefaultFactory(factory);
93 }
94
95 BooleanComboBox::BooleanComboBox(QWidget *parent)
96     : QComboBox(parent)
97 {
98     addItem(tr("False"));
99     addItem(tr("True"));
100 }
101
102 void BooleanComboBox::setValue(bool value)
103 {
104     setCurrentIndex(value ? 1 : 0);
105 }
106
107 bool BooleanComboBox::value() const
108 {
109     return (currentIndex() == 1);
110 }
111
112 ArgumentsEditor::ArgumentsEditor(QWidget *parent)
113     : QDialog(parent),
114       m_model(new QStandardItemModel()),
115       m_call(0)
116 {
117     init();
118 }
119
120 ArgumentsEditor::~ArgumentsEditor()
121 {
122     delete m_model;
123 }
124
125 void ArgumentsEditor::setCall(ApiTraceCall *call)
126 {
127     m_call = call;
128     setupCall();
129 }
130
131 ApiTraceCall * ArgumentsEditor::call() const
132 {
133     return m_call;
134 }
135
136 void ArgumentsEditor::init()
137 {
138     m_ui.setupUi(this);
139
140     connect(m_ui.selectStringCB, SIGNAL(currentIndexChanged(int)),
141             SLOT(currentSourceChanged(int)));
142     connect(m_ui.glslEdit, SIGNAL(textChanged()),
143             SLOT(sourceChanged()));
144     connect(m_ui.revertButton, SIGNAL(clicked()),
145             SLOT(revert()));
146
147     setArgumentsItemEditorFactory ();
148
149     m_ui.argsTree->setModel(m_model);
150
151 }
152
153 void ArgumentsEditor::setupCall()
154 {
155     m_model->clear();
156
157     QStringList headers;
158     headers.append(tr("Argument"));
159     headers.append(tr("Value"));
160     m_model->setColumnCount(2);
161     m_model->setHorizontalHeaderLabels(headers);
162     m_ui.argsTabWidget->removeTab(
163         m_ui.argsTabWidget->indexOf(m_ui.shaderTab));
164
165     if (!m_call)
166         return;
167
168     m_ui.callLabel->setText(m_call->name());
169     QStandardItem *rootItem = m_model->invisibleRootItem();
170     for (int i = 0; i < m_call->argNames().count(); ++i) {
171         QString argName = m_call->argNames()[i];
172         QVariant val = m_call->arguments()[i];
173         QStandardItem *nameItem = new QStandardItem(argName);
174         nameItem->setFlags(nameItem->flags() ^ Qt::ItemIsEditable);
175         QList<QStandardItem*> topRow;
176         topRow.append(nameItem);
177
178         if (val.canConvert<ApiArray>()) {
179             ApiArray array = val.value<ApiArray>();
180             QVector<QVariant> vals = array.values();
181
182             QVariant firstVal = vals.value(0);
183             if (firstVal.userType() == QVariant::String) {
184                 m_ui.argsTabWidget->addTab(
185                     m_ui.shaderTab, argName);
186                 setupShaderEditor(vals);
187                 delete nameItem;
188                 continue;
189             } else if (isVariantEditable(firstVal)) {
190                 for (int i = 0; i < vals.count(); ++i) {
191                     QList<QStandardItem*> row;
192
193                     QStandardItem *idx = new QStandardItem();
194                     idx->setFlags(idx->flags() ^ Qt::ItemIsEditable);
195                     idx->setText(tr("%1)").arg(i));
196
197                     QStandardItem *col = new QStandardItem();
198                     col->setFlags(col->flags() | Qt::ItemIsEditable);
199                     col->setData(vals[i], Qt::EditRole);
200                     row.append(idx);
201                     row.append(col);
202                     nameItem->appendRow(row);
203                 }
204             } else {
205                 qDebug()<<"\tUnsupported array = "<<firstVal;
206                 delete nameItem;
207                 continue;
208             }
209         } else  if (val.canConvert<ApiPointer>()) {
210             ApiPointer ptr = val.value<ApiPointer>();
211             QStandardItem *item = new QStandardItem();
212             item->setFlags(item->flags() ^ Qt::ItemIsEditable);
213             item->setText(ptr.toString());
214             QIcon icon(":/resources/emblem-locked.png");
215             item->setIcon(icon);
216             item->setToolTip(tr("Argument is read-only"));
217             topRow.append(item);
218         } else if (val.canConvert<ApiEnum>()) {
219             ApiEnum en = val.value<ApiEnum>();
220             QStandardItem *item = new QStandardItem();
221             item->setFlags(item->flags() ^ Qt::ItemIsEditable);
222             item->setText(en.toString());
223             QIcon icon(":/resources/emblem-locked.png");
224             item->setIcon(icon);
225             item->setToolTip(tr("Argument is read-only"));
226             topRow.append(item);
227         } else if (val.canConvert<ApiBitmask>()) {
228             ApiBitmask mask = val.value<ApiBitmask>();
229             QStandardItem *item = new QStandardItem();
230             item->setFlags(item->flags() ^ Qt::ItemIsEditable);
231             item->setText(mask.toString());
232             QIcon icon(":/resources/emblem-locked.png");
233             item->setIcon(icon);
234             item->setToolTip(tr("Argument is read-only"));
235             topRow.append(item);
236         } else if (val.canConvert<ApiStruct>()) {
237             ApiStruct str = val.value<ApiStruct>();
238             QStandardItem *item = new QStandardItem();
239             item->setFlags(item->flags() ^ Qt::ItemIsEditable);
240             item->setText(str.toString());
241             QIcon icon(":/resources/emblem-locked.png");
242             item->setIcon(icon);
243             item->setToolTip(tr("Argument is read-only"));
244             topRow.append(item);
245         } else if (val.userType() == QVariant::ByteArray) {
246             QByteArray ba = val.value<QByteArray>();
247             QStandardItem *item = new QStandardItem();
248             item->setFlags(item->flags() ^ Qt::ItemIsEditable);
249             item->setText(
250                 tr("<binary data, size = %1 bytes>").arg(ba.size()));
251             QIcon icon(":/resources/emblem-locked.png");
252             item->setIcon(icon);
253             item->setToolTip(tr("Argument is read-only"));
254             topRow.append(item);
255         } else {
256             QStandardItem *item
257                 = new QStandardItem();
258
259             if (isVariantEditable(val)) {
260                 item->setFlags(item->flags() | Qt::ItemIsEditable);
261             } else {
262                 QIcon icon(":/resources/emblem-locked.png");
263                 item->setIcon(icon);
264                 item->setFlags(item->flags() ^ Qt::ItemIsEditable);
265                 item->setToolTip(tr("Argument is read-only"));
266             }
267             item->setData(val, Qt::EditRole);
268             topRow.append(item);
269         }
270         rootItem->appendRow(topRow);
271     }
272 }
273
274 void ArgumentsEditor::setupShaderEditor(const QVector<QVariant> &sources)
275 {
276     m_ui.selectStringCB->clear();
277     m_ui.glslEdit->clear();
278     for (int i = 0; i < sources.count(); ++i) {
279         m_ui.selectStringCB->addItem(
280             tr("Shader string: %1").arg(i),
281             sources[i]);
282     }
283     m_ui.selectStringCB->setCurrentIndex(0);
284 }
285
286 void ArgumentsEditor::currentSourceChanged(int idx)
287 {
288     QVariant source = m_ui.selectStringCB->itemData(idx);
289     QString str = source.toString();
290     m_ui.glslEdit->setPlainText(source.toString());
291     m_ui.lengthLabel->setText(
292         tr("%1").arg(str.length()));
293 }
294
295 void ArgumentsEditor::sourceChanged()
296 {
297     QString str = m_ui.glslEdit->toPlainText();
298     m_ui.lengthLabel->setText(
299         tr("%1").arg(str.length()));
300
301     m_ui.selectStringCB->setItemData(
302         m_ui.selectStringCB->currentIndex(),
303         str);
304 }
305
306 void ArgumentsEditor::accept()
307 {
308     QStringList argNames = m_call->argNames();
309     QVector<QVariant> originalValues = m_call->arguments();
310     QVector<QVariant> newValues;
311     bool changed = false;
312     for (int i = 0; i < argNames.count(); ++i) {
313         bool valChanged = false;
314         QString argName = argNames[i];
315         QVariant argValue = originalValues[i];
316         QVariant editorValue = valueForName(argName, argValue, &valChanged);
317
318         newValues.append(editorValue);
319 #if 0
320         qDebug()<<"Arg = "<<argName;
321         qDebug()<<"\toriginal = "<<argValue;
322         qDebug()<<"\teditor   = "<<editorValue;
323         qDebug()<<"\tchanged  = "<<valChanged;
324 #endif
325         if (valChanged)
326             changed = true;
327     }
328     if (changed)
329         m_call->setEditedValues(newValues);
330     QDialog::accept();
331 }
332
333 QVariant ArgumentsEditor::valueForName(const QString &name,
334                                        const QVariant &originalValue,
335                                        bool *changed) const
336 {
337     QVariant val;
338
339     *changed = false;
340
341     //Handle string arrays specially
342     if (isVariantStringArray(originalValue)) {
343         ApiArray array = originalValue.value<ApiArray>();
344         return arrayFromEditor(array, changed);
345     }
346
347     if (!isVariantEditable(originalValue)) {
348         return originalValue;
349     }
350
351     for (int topRow = 0; topRow < m_model->rowCount(); ++topRow) {
352         QModelIndex nameIdx = m_model->index(topRow, 0, QModelIndex());
353         QString argName = nameIdx.data().toString();
354         /* we display shaders in a separate widget so
355          * the ordering might be different */
356         if (argName == name) {
357             if (originalValue.userType() == QMetaType::type("ApiArray")) {
358                 ApiArray array = originalValue.value<ApiArray>();
359                 val = arrayFromIndex(nameIdx, array, changed);
360             } else {
361                 QModelIndex valIdx = m_model->index(topRow, 1, QModelIndex());
362                 val = valIdx.data();
363                 if (val != originalValue)
364                     *changed = true;
365             }
366         }
367     }
368     return val;
369 }
370
371 QVariant ArgumentsEditor::arrayFromIndex(const QModelIndex &parentIndex,
372                                          const ApiArray &origArray,
373                                          bool *changed) const
374 {
375     QVector<QVariant> origValues = origArray.values();
376
377     *changed = false;
378
379     if (origValues.isEmpty())
380         return QVariant::fromValue(ApiArray());
381
382     QVector<QVariant> lst;
383     for (int i = 0; i < origValues.count(); ++i) {
384         QModelIndex valIdx = m_model->index(i, 1, parentIndex);
385         QVariant var = valIdx.data();
386         QVariant origValue = origValues[i];
387         if (var != origValue)
388             *changed = true;
389         //qDebug()<<"\t\tarray "<<i<<") "<<var;
390         lst.append(var);
391     }
392     return QVariant::fromValue(ApiArray(lst));
393 }
394
395 QVariant ArgumentsEditor::arrayFromEditor(const ApiArray &origArray,
396                                           bool *changed) const
397 {
398     QVector<QVariant> vals;
399     QVector<QVariant> origValues = origArray.values();
400
401     Q_ASSERT(isVariantStringArray(QVariant::fromValue(origArray)));
402     *changed = false;
403     //shaders
404     for (int i = 0; i < m_ui.selectStringCB->count(); ++i) {
405         QVariant val = m_ui.selectStringCB->itemData(i);
406         QVariant origValue = origValues[i];
407         if (origValue != val)
408             *changed = true;
409         vals.append(val);
410     }
411     return QVariant::fromValue(ApiArray(vals));
412 }
413
414 void ArgumentsEditor::revert()
415 {
416     m_call->revert();
417     setupCall();
418 }
419
420 #include "argumentseditor.moc"