]> git.cworth.org Git - apitrace/blob - gui/apitracecall.cpp
Unify Bitmask::Signature with BitmaskSig.
[apitrace] / gui / apitracecall.cpp
1 #include "apitracecall.h"
2
3 #include "apitrace.h"
4 #include "trace_model.hpp"
5
6 #include <QDebug>
7 #include <QLocale>
8 #include <QObject>
9 #define QT_USE_FAST_OPERATOR_PLUS
10 #include <QStringBuilder>
11 #include <QTextDocument>
12
13 const char * const styleSheet =
14     ".call {\n"
15     "    font-weight:bold;\n"
16     // text shadow looks great but doesn't work well in qtwebkit 4.7
17     "    /*text-shadow: 0px 2px 3px #555;*/\n"
18     "    font-size: 1.2em;\n"
19     "}\n"
20     ".arg-name {\n"
21     "    border: 1px solid rgb(238,206,0);\n"
22     "    border-radius: 4px;\n"
23     "    background: yellow;\n"
24     "    padding: 2px;\n"
25     "    box-shadow: 0px 1px 3px dimgrey;\n"
26     "    -webkit-transition: background 1s linear;\n"
27     "}\n"
28     ".arg-name:hover {\n"
29     "    background: white;\n"
30     "}\n"
31     ".arg-value {\n"
32     "    color: #0000ff;\n"
33     "}\n"
34     ".error {\n"
35     "    border: 1px solid rgb(255,0,0);\n"
36     "    margin: 10px;\n"
37     "    padding: 1;\n"
38     "    border-radius: 4px;\n"
39     // also looks great but qtwebkit doesn't support it
40     //"    background: #6fb2e5;\n"
41     //"    box-shadow: 0 1px 5px #0061aa, inset 0 10px 20px #b6f9ff;\n"
42     //"    -o-box-shadow: 0 1px 5px #0061aa, inset 0 10px 20px #b6f9ff;\n"
43     //"    -webkit-box-shadow: 0 1px 5px #0061aa, inset 0 10px 20px #b6f9ff;\n"
44     //"    -moz-box-shadow: 0 1px 5px #0061aa, inset 0 10px 20px #b6f9ff;\n"
45     "}\n";
46
47 ApiPointer::ApiPointer(unsigned long long val)
48     : m_value(val)
49 {
50 }
51
52 QString ApiPointer::toString() const
53 {
54     if (m_value)
55         return QString("0x%1").arg(m_value, 0, 16);
56     else
57         return QLatin1String("NULL");
58 }
59
60 // Qt::convertFromPlainText doesn't do precisely what we want
61 static QString
62 plainTextToHTML(const QString & plain, bool multiLine)
63 {
64     int col = 0;
65     bool quote = false;
66     QString rich;
67     for (int i = 0; i < plain.length(); ++i) {
68         if (plain[i] == QLatin1Char('\n')){
69             if (multiLine) {
70                 rich += QLatin1String("<br>\n");
71             } else {
72                 rich += QLatin1String("\\n");
73             }
74             col = 0;
75             quote = true;
76         } else {
77             if (plain[i] == QLatin1Char('\t')){
78                 if (multiLine) {
79                     rich += QChar(0x00a0U);
80                     ++col;
81                     while (col % 8) {
82                         rich += QChar(0x00a0U);
83                         ++col;
84                     }
85                 } else {
86                     rich += QLatin1String("\\t");
87                 }
88                 quote = true;
89             } else if (plain[i].isSpace()) {
90                 rich += QChar(0x00a0U);
91                 quote = true;
92             } else if (plain[i] == QLatin1Char('<')) {
93                 rich += QLatin1String("&lt;");
94             } else if (plain[i] == QLatin1Char('>')) {
95                 rich += QLatin1String("&gt;");
96             } else if (plain[i] == QLatin1Char('&')) {
97                 rich += QLatin1String("&amp;");
98             } else {
99                 rich += plain[i];
100             }
101             ++col;
102         }
103     }
104
105     if (quote) {
106         return QLatin1Literal("\"") + rich + QLatin1Literal("\"");
107     }
108
109     return rich;
110 }
111
112 QString apiVariantToString(const QVariant &variant, bool multiLine)
113 {
114     if (variant.userType() == QVariant::Double) {
115         return QString::number(variant.toFloat());
116     }
117     if (variant.userType() == QVariant::ByteArray) {
118         if (variant.toByteArray().size() < 1024) {
119             int bytes = variant.toByteArray().size();
120             return QObject::tr("[binary data, size = %1 bytes]").arg(bytes);
121         } else {
122             float kb = variant.toByteArray().size()/1024.;
123             return QObject::tr("[binary data, size = %1 kb]").arg(kb);
124         }
125     }
126
127     if (variant.userType() == QVariant::String) {
128         return plainTextToHTML(variant.toString(), multiLine);
129     }
130
131     if (variant.userType() < QVariant::UserType) {
132         return variant.toString();
133     }
134
135     if (variant.canConvert<ApiPointer>()) {
136         return variant.value<ApiPointer>().toString();
137     }
138     if (variant.canConvert<ApiBitmask>()) {
139         return variant.value<ApiBitmask>().toString();
140     }
141     if (variant.canConvert<ApiStruct>()) {
142         return variant.value<ApiStruct>().toString();
143     }
144     if (variant.canConvert<ApiArray>()) {
145         return variant.value<ApiArray>().toString();
146     }
147     if (variant.canConvert<ApiEnum>()) {
148         return variant.value<ApiEnum>().toString();
149     }
150
151     return QString();
152 }
153
154 ApiBitmask::ApiBitmask(const Trace::Bitmask *bitmask)
155     : m_value(0)
156 {
157     init(bitmask);
158 }
159
160
161 void ApiBitmask::init(const Trace::Bitmask *bitmask)
162 {
163     if (!bitmask)
164         return;
165
166     m_value = bitmask->value;
167     for (const Trace::BitmaskVal *it = bitmask->sig->values;
168          it != bitmask->sig->values + bitmask->sig->count; ++it) {
169         assert(it->value);
170         QPair<QString, unsigned long long> pair;
171
172         pair.first = QString::fromStdString(it->name);
173         pair.second = it->value;
174
175         m_sig.append(pair);
176     }
177 }
178
179 QString ApiBitmask::toString() const
180 {
181     QString str;
182     unsigned long long value = m_value;
183     bool first = true;
184     for (Signature::const_iterator it = m_sig.begin();
185          value != 0 && it != m_sig.end(); ++it) {
186         Q_ASSERT(it->second);
187         if ((value & it->second) == it->second) {
188             if (!first) {
189                 str += QLatin1String(" | ");
190             }
191             str += it->first;
192             value &= ~it->second;
193             first = false;
194         }
195     }
196     if (value || first) {
197         if (!first) {
198             str += QLatin1String(" | ");
199         }
200         str += QString::fromLatin1("0x%1").arg(value, 0, 16);
201     }
202     return str;
203 }
204
205 ApiStruct::ApiStruct(const Trace::Struct *s)
206 {
207     init(s);
208 }
209
210 QString ApiStruct::toString() const
211 {
212     QString str;
213
214     str += QLatin1String("{");
215     for (unsigned i = 0; i < m_members.count(); ++i) {
216         str += m_sig.memberNames[i] %
217                QLatin1Literal(" = ") %
218                apiVariantToString(m_members[i]);
219         if (i < m_members.count() - 1)
220             str += QLatin1String(", ");
221     }
222     str += QLatin1String("}");
223
224     return str;
225 }
226
227 void ApiStruct::init(const Trace::Struct *s)
228 {
229     if (!s)
230         return;
231
232     m_sig.name = QString::fromStdString(s->sig->name);
233     for (unsigned i = 0; i < s->members.size(); ++i) {
234         VariantVisitor vis;
235         m_sig.memberNames.append(
236             QString::fromStdString(s->sig->member_names[i]));
237         s->members[i]->visit(vis);
238         m_members.append(vis.variant());
239     }
240 }
241
242 void VariantVisitor::visit(Trace::Null *)
243 {
244     m_variant = QVariant::fromValue(ApiPointer(0));
245 }
246
247 void VariantVisitor::visit(Trace::Bool *node)
248 {
249     m_variant = QVariant(node->value);
250 }
251
252 void VariantVisitor::visit(Trace::SInt *node)
253 {
254     m_variant = QVariant(node->value);
255 }
256
257 void VariantVisitor::visit(Trace::UInt *node)
258 {
259     m_variant = QVariant(node->value);
260 }
261
262 void VariantVisitor::visit(Trace::Float *node)
263 {
264     m_variant = QVariant(node->value);
265 }
266
267 void VariantVisitor::visit(Trace::String *node)
268 {
269     m_variant = QVariant(QString::fromStdString(node->value));
270 }
271
272 void VariantVisitor::visit(Trace::Enum *e)
273 {
274     VariantVisitor vis;
275     e->sig->second->visit(vis);
276
277     QVariant val = vis.variant();
278
279     m_variant = QVariant::fromValue(
280         ApiEnum(QString::fromStdString(e->sig->first), val));
281 }
282
283 void VariantVisitor::visit(Trace::Bitmask *bitmask)
284 {
285     m_variant = QVariant::fromValue(ApiBitmask(bitmask));
286 }
287
288 void VariantVisitor::visit(Trace::Struct *str)
289 {
290     m_variant = QVariant::fromValue(ApiStruct(str));
291 }
292
293 void VariantVisitor::visit(Trace::Array *array)
294 {
295     m_variant = QVariant::fromValue(ApiArray(array));
296 }
297
298 void VariantVisitor::visit(Trace::Blob *blob)
299 {
300     //XXX
301     //FIXME: this is a nasty hack. Trace::Blob's can't
302     //   delete the contents in the destructor because
303     //   the data is being used by other calls. We piggy back
304     //   on that assumption and don't deep copy the data. If
305     //   Blob's will start deleting the data we will need to
306     //   start deep copying it or switch to using something like
307     //   Boost's shared_ptr or Qt's QSharedPointer to handle it
308     QByteArray barray = QByteArray::fromRawData(blob->buf, blob->size);
309     m_variant = QVariant(barray);
310 }
311
312 void VariantVisitor::visit(Trace::Pointer *ptr)
313 {
314     m_variant = QVariant::fromValue(ApiPointer(ptr->value));
315 }
316
317 ApiArray::ApiArray(const Trace::Array *arr)
318 {
319     init(arr);
320 }
321
322 ApiArray::ApiArray(const QList<QVariant> &vals)
323     : m_array(vals)
324 {
325 }
326
327 QString ApiArray::toString() const
328 {
329     QString str;
330     str += QLatin1String("[");
331     for(int i = 0; i < m_array.count(); ++i) {
332         const QVariant &var = m_array[i];
333         str += apiVariantToString(var);
334         if (i < m_array.count() - 1)
335             str += QLatin1String(", ");
336     }
337     str += QLatin1String("]");
338
339     return str;
340 }
341
342 void ApiArray::init(const Trace::Array *arr)
343 {
344     if (!arr)
345         return;
346
347     for (int i = 0; i < arr->values.size(); ++i) {
348         VariantVisitor vis;
349         arr->values[i]->visit(vis);
350
351         m_array.append(vis.variant());
352     }
353 }
354
355 QStaticText ApiTraceCall::staticText() const
356 {
357     if (m_staticText && !m_staticText->text().isEmpty())
358         return *m_staticText;
359
360     QVariantList argValues = arguments();
361
362     QString richText = QString::fromLatin1(
363         "<span style=\"font-weight:bold\">%1</span>(").arg(m_name);
364     for (int i = 0; i < m_argNames.count(); ++i) {
365         richText += QLatin1String("<span style=\"color:#0000ff\">");
366         QString argText = apiVariantToString(argValues[i]);
367
368         //if arguments are really long (e.g. shader text), cut them
369         // and elide it
370         if (argText.length() > 40) {
371             QString shortened = argText.mid(0, 40);
372             shortened[argText.length() - 5] = '.';
373             shortened[argText.length() - 4] = '.';
374             shortened[argText.length() - 3] = '.';
375             shortened[argText.length() - 2] = argText[argText.length() - 2];
376             shortened[argText.length() - 1] = argText[argText.length() - 1];
377             richText += shortened;
378         } else {
379             richText += argText;
380         }
381         richText += QLatin1String("</span>");
382         if (i < m_argNames.count() - 1)
383             richText += QLatin1String(", ");
384     }
385     richText += QLatin1String(")");
386     if (m_returnValue.isValid()) {
387         richText +=
388             QLatin1Literal(" = ") %
389             QLatin1Literal("<span style=\"color:#0000ff\">") %
390             apiVariantToString(m_returnValue) %
391             QLatin1Literal("</span>");
392     }
393
394     if (!m_staticText)
395         m_staticText = new QStaticText(richText);
396     else
397         m_staticText->setText(richText);
398     QTextOption opt;
399     opt.setWrapMode(QTextOption::NoWrap);
400     m_staticText->setTextOption(opt);
401     m_staticText->prepare();
402
403     return *m_staticText;
404 }
405
406 QString ApiTraceCall::toHtml() const
407 {
408     if (!m_richText.isEmpty())
409         return m_richText;
410
411     m_richText = QLatin1String("<div class=\"call\">");
412
413     if (m_helpUrl.isEmpty()) {
414         m_richText += QString::fromLatin1(
415             "%1) <span class=\"callName\">%2</span>(")
416                       .arg(m_index)
417                       .arg(m_name);
418     } else {
419         m_richText += QString::fromLatin1(
420             "%1) <span class=\"callName\"><a href=\"%2\">%3</a></span>(")
421                       .arg(m_index)
422                       .arg(m_helpUrl.toString())
423                       .arg(m_name);
424     }
425
426     QVariantList argValues = arguments();
427     for (int i = 0; i < m_argNames.count(); ++i) {
428         m_richText +=
429             QLatin1String("<span class=\"arg-name\">") +
430             m_argNames[i] +
431             QLatin1String("</span>") +
432             QLatin1Literal(" = ") +
433             QLatin1Literal("<span class=\"arg-value\">") +
434             apiVariantToString(argValues[i], true) +
435             QLatin1Literal("</span>");
436         if (i < m_argNames.count() - 1)
437             m_richText += QLatin1String(", ");
438     }
439     m_richText += QLatin1String(")");
440
441     if (m_returnValue.isValid()) {
442         m_richText +=
443             QLatin1String(" = ") +
444             QLatin1String("<span style=\"color:#0000ff\">") +
445             apiVariantToString(m_returnValue, true) +
446             QLatin1String("</span>");
447     }
448     m_richText += QLatin1String("</div>");
449
450     if (hasError()) {
451         QString errorStr =
452             QString::fromLatin1(
453                 "<div class=\"error\">%1</div>")
454             .arg(m_error);
455         m_richText += errorStr;
456     }
457
458     m_richText =
459         QString::fromLatin1(
460             "<html><head><style type=\"text/css\" media=\"all\">"
461             "%1</style></head><body>%2</body></html>")
462         .arg(styleSheet)
463         .arg(m_richText);
464     m_richText.squeeze();
465
466     //qDebug()<<m_richText;
467     return m_richText;
468 }
469
470 QString ApiTraceCall::filterText() const
471 {
472     if (!m_filterText.isEmpty())
473         return m_filterText;
474
475     QVariantList argValues = arguments();
476     m_filterText = m_name + QLatin1Literal("(");
477     for (int i = 0; i < m_argNames.count(); ++i) {
478         m_filterText += m_argNames[i] +
479                         QLatin1Literal(" = ") +
480                         apiVariantToString(argValues[i]);
481         if (i < m_argNames.count() - 1)
482             m_filterText += QLatin1String(", ");
483     }
484     m_filterText += QLatin1String(")");
485
486     if (m_returnValue.isValid()) {
487         m_filterText += QLatin1Literal(" = ") +
488                         apiVariantToString(m_returnValue);
489     }
490     m_filterText.squeeze();
491     return m_filterText;
492 }
493
494 QStaticText ApiTraceFrame::staticText() const
495 {
496     if (m_staticText && !m_staticText->text().isEmpty())
497         return *m_staticText;
498
499     QString richText;
500
501     //mark the frame if it uploads more than a meg a frame
502     if (m_binaryDataSize > (1024*1024)) {
503         richText =
504             QObject::tr(
505                 "<span style=\"font-weight:bold;\">"
506                 "Frame&nbsp;%1</span>"
507                 "<span style=\"font-style:italic;\">"
508                 "&nbsp;&nbsp;&nbsp;&nbsp;(%2MB)</span>")
509             .arg(number)
510             .arg(double(m_binaryDataSize / (1024.*1024.)), 0, 'g', 2);
511     } else {
512         richText =
513             QObject::tr(
514                 "<span style=\"font-weight:bold\">Frame %1</span>")
515             .arg(number);
516     }
517
518     if (!m_staticText)
519         m_staticText = new QStaticText(richText);
520
521     QTextOption opt;
522     opt.setWrapMode(QTextOption::NoWrap);
523     m_staticText->setTextOption(opt);
524     m_staticText->prepare();
525
526     return *m_staticText;
527 }
528
529 int ApiTraceCall::numChildren() const
530 {
531     return 0;
532 }
533
534 int ApiTraceFrame::numChildren() const
535 {
536     return m_calls.count();
537 }
538
539 ApiTraceFrame::ApiTraceFrame()
540     : ApiTraceEvent(ApiTraceEvent::Frame),
541       m_parentTrace(0),
542       m_binaryDataSize(0)
543 {
544 }
545
546 ApiTraceCall::ApiTraceCall()
547     : ApiTraceEvent(ApiTraceEvent::Call),
548       m_hasBinaryData(false),
549       m_binaryDataIndex(0)
550 {
551 }
552
553 ApiTraceEvent::ApiTraceEvent()
554     : m_type(ApiTraceEvent::None),
555       m_staticText(0)
556 {
557 }
558
559 ApiTraceEvent::ApiTraceEvent(Type t)
560     : m_type(t),
561       m_staticText(0)
562 {
563 }
564
565 ApiTraceCall::~ApiTraceCall()
566 {
567 }
568
569 QVariantMap ApiTraceEvent::stateParameters() const
570 {
571     return m_state.parameters();
572 }
573
574 ApiTraceState ApiTraceEvent::state() const
575 {
576     return m_state;
577 }
578
579 void ApiTraceEvent::setState(const ApiTraceState &state)
580 {
581     m_state = state;
582 }
583
584 bool ApiTraceCall::hasBinaryData() const
585 {
586     return m_hasBinaryData;
587 }
588
589 int ApiTraceCall::binaryDataIndex() const
590 {
591     return m_binaryDataIndex;
592 }
593
594 ApiTraceState::ApiTraceState()
595 {
596 }
597
598 ApiTraceState::ApiTraceState(const QVariantMap &parsedJson)
599 {
600     m_parameters = parsedJson[QLatin1String("parameters")].toMap();
601     QVariantMap attachedShaders =
602         parsedJson[QLatin1String("shaders")].toMap();
603     QVariantMap::const_iterator itr;
604
605
606     for (itr = attachedShaders.constBegin(); itr != attachedShaders.constEnd();
607          ++itr) {
608         QString type = itr.key();
609         QString source = itr.value().toString();
610         m_shaderSources[type] = source;
611     }
612
613     QVariantMap textures =
614         parsedJson[QLatin1String("textures")].toMap();
615     for (itr = textures.constBegin(); itr != textures.constEnd(); ++itr) {
616         QVariantMap image = itr.value().toMap();
617         QSize size(image[QLatin1String("__width__")].toInt(),
618                    image[QLatin1String("__height__")].toInt());
619         QString cls = image[QLatin1String("__class__")].toString();
620         QString type = image[QLatin1String("__type__")].toString();
621         bool normalized =
622             image[QLatin1String("__normalized__")].toBool();
623         int numChannels =
624             image[QLatin1String("__channels__")].toInt();
625
626         Q_ASSERT(type == QLatin1String("uint8"));
627         Q_ASSERT(normalized == true);
628
629         QByteArray dataArray =
630             image[QLatin1String("__data__")].toByteArray();
631
632         ApiTexture tex;
633         tex.setSize(size);
634         tex.setNumChannels(numChannels);
635         tex.setLabel(itr.key());
636         tex.contentsFromBase64(dataArray);
637
638         m_textures.append(tex);
639     }
640
641     QVariantMap fbos =
642         parsedJson[QLatin1String("framebuffer")].toMap();
643     for (itr = fbos.constBegin(); itr != fbos.constEnd(); ++itr) {
644         QVariantMap buffer = itr.value().toMap();
645         QSize size(buffer[QLatin1String("__width__")].toInt(),
646                    buffer[QLatin1String("__height__")].toInt());
647         QString cls = buffer[QLatin1String("__class__")].toString();
648         QString type = buffer[QLatin1String("__type__")].toString();
649         bool normalized = buffer[QLatin1String("__normalized__")].toBool();
650         int numChannels = buffer[QLatin1String("__channels__")].toInt();
651
652         Q_ASSERT(type == QLatin1String("uint8"));
653         Q_ASSERT(normalized == true);
654
655         QByteArray dataArray =
656             buffer[QLatin1String("__data__")].toByteArray();
657
658         ApiFramebuffer fbo;
659         fbo.setSize(size);
660         fbo.setNumChannels(numChannels);
661         fbo.setType(itr.key());
662         fbo.contentsFromBase64(dataArray);
663         m_framebuffers.append(fbo);
664     }
665 }
666
667 QVariantMap ApiTraceState::parameters() const
668 {
669     return m_parameters;
670 }
671
672 QMap<QString, QString> ApiTraceState::shaderSources() const
673 {
674     return m_shaderSources;
675 }
676
677 bool ApiTraceState::isEmpty() const
678 {
679     return m_parameters.isEmpty();
680 }
681
682 QList<ApiTexture> ApiTraceState::textures() const
683 {
684     return m_textures;
685 }
686
687 QList<ApiFramebuffer> ApiTraceState::framebuffers() const
688 {
689     return m_framebuffers;
690 }
691
692 QList<QVariant> ApiArray::values() const
693 {
694     return m_array;
695 }
696
697 int ApiTraceCall::index() const
698 {
699     return m_index;
700 }
701
702 QString ApiTraceCall::name() const
703 {
704     return m_name;
705 }
706
707 QStringList ApiTraceCall::argNames() const
708 {
709     return m_argNames;
710 }
711
712 QVariantList ApiTraceCall::arguments() const
713 {
714     if (m_editedValues.isEmpty())
715         return m_argValues;
716     else
717         return m_editedValues;
718 }
719
720 QVariant ApiTraceCall::returnValue() const
721 {
722     return m_returnValue;
723 }
724
725 QUrl ApiTraceCall::helpUrl() const
726 {
727     return m_helpUrl;
728 }
729
730 ApiTraceCall::ApiTraceCall(const Trace::Call *call)
731     : ApiTraceEvent(ApiTraceEvent::Call),
732       m_hasBinaryData(false),
733       m_binaryDataIndex(0)
734 {
735     m_name = QString::fromStdString(call->sig->name);
736     m_index = call->no;
737
738     QString argumentsText;
739     for (int i = 0; i < call->sig->arg_names.size(); ++i) {
740         m_argNames +=
741             QString::fromStdString(call->sig->arg_names[i]);
742     }
743     if (call->ret) {
744         VariantVisitor retVisitor;
745         call->ret->visit(retVisitor);
746         m_returnValue = retVisitor.variant();
747     }
748     for (int i = 0; i < call->args.size(); ++i) {
749         VariantVisitor argVisitor;
750         call->args[i]->visit(argVisitor);
751         m_argValues += argVisitor.variant();
752         if (m_argValues[i].type() == QVariant::ByteArray) {
753             m_hasBinaryData = true;
754             m_binaryDataIndex = i;
755         }
756     }
757 }
758
759 void ApiTraceCall::setHelpUrl(const QUrl &url)
760 {
761     m_helpUrl = url;
762 }
763
764 void ApiTraceCall::setParentFrame(ApiTraceFrame *frame)
765 {
766     m_parentFrame = frame;
767 }
768
769 ApiTraceFrame * ApiTraceCall::parentFrame()const
770 {
771     return m_parentFrame;
772 }
773
774 ApiTraceEvent::~ApiTraceEvent()
775 {
776     delete m_staticText;
777 }
778
779 void ApiTraceCall::revert()
780 {
781     setEditedValues(QVariantList());
782 }
783
784 ApiTrace * ApiTraceFrame::parentTrace() const
785 {
786     return m_parentTrace;
787 }
788
789 void ApiTraceFrame::setParentTrace(ApiTrace *trace)
790 {
791     m_parentTrace = trace;
792 }
793
794 QVariantList ApiTraceCall::originalValues() const
795 {
796     return m_argValues;
797 }
798
799 void ApiTraceCall::setEditedValues(const QVariantList &lst)
800 {
801     ApiTrace *trace = parentTrace();
802
803     m_editedValues = lst;
804     //lets regenerate data
805     m_richText = QString();
806     m_filterText = QString();
807     delete m_staticText;
808     m_staticText = 0;
809
810     if (trace) {
811         if (!lst.isEmpty()) {
812             trace->callEdited(this);
813         } else {
814             trace->callReverted(this);
815         }
816     }
817 }
818
819 QVariantList ApiTraceCall::editedValues() const
820 {
821     return m_editedValues;
822 }
823
824 bool ApiTraceCall::edited() const
825 {
826     return !m_editedValues.isEmpty();
827 }
828
829 ApiEnum::ApiEnum(const QString &name, const QVariant &val)
830     : m_name(name),
831       m_value(val)
832 {
833 }
834
835 QString ApiEnum::toString() const
836 {
837     return m_name;
838 }
839
840 QVariant ApiEnum::value() const
841 {
842     return m_value;
843 }
844
845 QString ApiEnum::name() const
846 {
847     return m_name;
848 }
849
850 unsigned long long ApiBitmask::value() const
851 {
852     return m_value;
853 }
854
855 ApiBitmask::Signature ApiBitmask::signature() const
856 {
857     return m_sig;
858 }
859
860 ApiStruct::Signature ApiStruct::signature() const
861 {
862     return m_sig;
863 }
864
865 QList<QVariant> ApiStruct::values() const
866 {
867     return m_members;
868 }
869
870 unsigned long long ApiPointer::value() const
871 {
872     return m_value;
873 }
874
875 bool ApiTraceCall::hasError() const
876 {
877     return !m_error.isEmpty();
878 }
879
880 QString ApiTraceCall::error() const
881 {
882     return m_error;
883 }
884
885 void ApiTraceCall::setError(const QString &msg)
886 {
887     if (m_error != msg) {
888         ApiTrace *trace = parentTrace();
889         m_error = msg;
890         m_richText = QString();
891         if (trace)
892             trace->callError(this);
893     }
894 }
895
896 ApiTrace * ApiTraceCall::parentTrace() const
897 {
898     if (m_parentFrame)
899         return m_parentFrame->parentTrace();
900     return NULL;
901 }
902
903 void ApiTraceFrame::addCall(ApiTraceCall *call)
904 {
905     m_calls.append(call);
906     if (call->hasBinaryData()) {
907         QByteArray data =
908             call->arguments()[call->binaryDataIndex()].toByteArray();
909         m_binaryDataSize += data.size();
910     }
911 }
912
913 QList<ApiTraceCall*> ApiTraceFrame::calls() const
914 {
915     return m_calls;
916 }
917
918 ApiTraceCall * ApiTraceFrame::call(int idx) const
919 {
920     return m_calls.value(idx);
921 }
922
923 int ApiTraceFrame::callIndex(ApiTraceCall *call) const
924 {
925     return m_calls.indexOf(call);
926 }
927
928 bool ApiTraceFrame::isEmpty() const
929 {
930     return m_calls.isEmpty();
931 }
932
933 int ApiTraceFrame::binaryDataSize() const
934 {
935     return m_binaryDataSize;
936 }
937