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