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