]> git.cworth.org Git - apitrace/blob - gui/apitracecall.cpp
Show the size of binary data uploaded in a frame.
[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 (Trace::Bitmask::Signature::const_iterator it = bitmask->sig->begin();
168          it != bitmask->sig->end(); ++it) {
169         assert(it->second);
170         QPair<QString, unsigned long long> pair;
171
172         pair.first = QString::fromStdString(it->first);
173         pair.second = it->second;
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     QVariantList textureUnits =
614         parsedJson[QLatin1String("textures")].toList();
615     for (int i = 0; i < textureUnits.count(); ++i) {
616         QVariantMap unit = textureUnits[i].toMap();
617         for (itr = unit.constBegin(); itr != unit.constEnd(); ++itr) {
618             QVariantMap target = itr.value().toMap();
619             if (target.count()) {
620                 QVariantList levels = target[QLatin1String("levels")].toList();
621                 for (int j = 0; j < levels.count(); ++j) {
622                     QVariantMap level = levels[j].toMap();
623                     QVariantMap image = level[QLatin1String("image")].toMap();
624                     QSize size(image[QLatin1String("__width__")].toInt(),
625                                image[QLatin1String("__height__")].toInt());
626                     QString cls = image[QLatin1String("__class__")].toString();
627                     QString type = image[QLatin1String("__type__")].toString();
628                     bool normalized =
629                         image[QLatin1String("__normalized__")].toBool();
630                     int numChannels =
631                         image[QLatin1String("__channels__")].toInt();
632
633                     Q_ASSERT(type == QLatin1String("uint8"));
634                     Q_ASSERT(normalized == true);
635
636                     QByteArray dataArray =
637                         image[QLatin1String("__data__")].toByteArray();
638
639                     ApiTexture tex;
640                     tex.setSize(size);
641                     tex.setNumChannels(numChannels);
642                     tex.setLevel(j);
643                     tex.setUnit(i);
644                     tex.setTarget(itr.key());
645                     tex.contentsFromBase64(dataArray);
646
647                     m_textures.append(tex);
648                 }
649             }
650         }
651     }
652
653     QVariantMap fbos =
654         parsedJson[QLatin1String("framebuffer")].toMap();
655     for (itr = fbos.constBegin(); itr != fbos.constEnd(); ++itr) {
656         QVariantMap buffer = itr.value().toMap();
657         QSize size(buffer[QLatin1String("__width__")].toInt(),
658                    buffer[QLatin1String("__height__")].toInt());
659         QString cls = buffer[QLatin1String("__class__")].toString();
660         QString type = buffer[QLatin1String("__type__")].toString();
661         bool normalized = buffer[QLatin1String("__normalized__")].toBool();
662         int numChannels = buffer[QLatin1String("__channels__")].toInt();
663
664         Q_ASSERT(type == QLatin1String("uint8"));
665         Q_ASSERT(normalized == true);
666
667         QByteArray dataArray =
668             buffer[QLatin1String("__data__")].toByteArray();
669
670         ApiFramebuffer fbo;
671         fbo.setSize(size);
672         fbo.setNumChannels(numChannels);
673         fbo.setType(itr.key());
674         fbo.contentsFromBase64(dataArray);
675         m_framebuffers.append(fbo);
676     }
677 }
678
679 QVariantMap ApiTraceState::parameters() const
680 {
681     return m_parameters;
682 }
683
684 QMap<QString, QString> ApiTraceState::shaderSources() const
685 {
686     return m_shaderSources;
687 }
688
689 bool ApiTraceState::isEmpty() const
690 {
691     return m_parameters.isEmpty();
692 }
693
694 QList<ApiTexture> ApiTraceState::textures() const
695 {
696     return m_textures;
697 }
698
699 QList<ApiFramebuffer> ApiTraceState::framebuffers() const
700 {
701     return m_framebuffers;
702 }
703
704 QList<QVariant> ApiArray::values() const
705 {
706     return m_array;
707 }
708
709 int ApiTraceCall::index() const
710 {
711     return m_index;
712 }
713
714 QString ApiTraceCall::name() const
715 {
716     return m_name;
717 }
718
719 QStringList ApiTraceCall::argNames() const
720 {
721     return m_argNames;
722 }
723
724 QVariantList ApiTraceCall::arguments() const
725 {
726     if (m_editedValues.isEmpty())
727         return m_argValues;
728     else
729         return m_editedValues;
730 }
731
732 QVariant ApiTraceCall::returnValue() const
733 {
734     return m_returnValue;
735 }
736
737 QUrl ApiTraceCall::helpUrl() const
738 {
739     return m_helpUrl;
740 }
741
742 ApiTraceCall::ApiTraceCall(const Trace::Call *call)
743     : ApiTraceEvent(ApiTraceEvent::Call),
744       m_hasBinaryData(false),
745       m_binaryDataIndex(0)
746 {
747     m_name = QString::fromStdString(call->sig->name);
748     m_index = call->no;
749
750     QString argumentsText;
751     for (int i = 0; i < call->sig->arg_names.size(); ++i) {
752         m_argNames +=
753             QString::fromStdString(call->sig->arg_names[i]);
754     }
755     if (call->ret) {
756         VariantVisitor retVisitor;
757         call->ret->visit(retVisitor);
758         m_returnValue = retVisitor.variant();
759     }
760     for (int i = 0; i < call->args.size(); ++i) {
761         VariantVisitor argVisitor;
762         call->args[i]->visit(argVisitor);
763         m_argValues += argVisitor.variant();
764         if (m_argValues[i].type() == QVariant::ByteArray) {
765             m_hasBinaryData = true;
766             m_binaryDataIndex = i;
767         }
768     }
769 }
770
771 void ApiTraceCall::setHelpUrl(const QUrl &url)
772 {
773     m_helpUrl = url;
774 }
775
776 void ApiTraceCall::setParentFrame(ApiTraceFrame *frame)
777 {
778     m_parentFrame = frame;
779 }
780
781 ApiTraceFrame * ApiTraceCall::parentFrame()const
782 {
783     return m_parentFrame;
784 }
785
786 ApiTraceEvent::~ApiTraceEvent()
787 {
788     delete m_staticText;
789 }
790
791 void ApiTraceCall::revert()
792 {
793     setEditedValues(QVariantList());
794 }
795
796 ApiTrace * ApiTraceFrame::parentTrace() const
797 {
798     return m_parentTrace;
799 }
800
801 void ApiTraceFrame::setParentTrace(ApiTrace *trace)
802 {
803     m_parentTrace = trace;
804 }
805
806 QVariantList ApiTraceCall::originalValues() const
807 {
808     return m_argValues;
809 }
810
811 void ApiTraceCall::setEditedValues(const QVariantList &lst)
812 {
813     ApiTrace *trace = parentTrace();
814
815     m_editedValues = lst;
816     //lets regenerate data
817     m_richText = QString();
818     m_filterText = QString();
819     delete m_staticText;
820     m_staticText = 0;
821
822     if (trace) {
823         if (!lst.isEmpty()) {
824             trace->callEdited(this);
825         } else {
826             trace->callReverted(this);
827         }
828     }
829 }
830
831 QVariantList ApiTraceCall::editedValues() const
832 {
833     return m_editedValues;
834 }
835
836 bool ApiTraceCall::edited() const
837 {
838     return !m_editedValues.isEmpty();
839 }
840
841 ApiEnum::ApiEnum(const QString &name, const QVariant &val)
842     : m_name(name),
843       m_value(val)
844 {
845 }
846
847 QString ApiEnum::toString() const
848 {
849     return m_name;
850 }
851
852 QVariant ApiEnum::value() const
853 {
854     return m_value;
855 }
856
857 QString ApiEnum::name() const
858 {
859     return m_name;
860 }
861
862 unsigned long long ApiBitmask::value() const
863 {
864     return m_value;
865 }
866
867 ApiBitmask::Signature ApiBitmask::signature() const
868 {
869     return m_sig;
870 }
871
872 ApiStruct::Signature ApiStruct::signature() const
873 {
874     return m_sig;
875 }
876
877 QList<QVariant> ApiStruct::values() const
878 {
879     return m_members;
880 }
881
882 unsigned long long ApiPointer::value() const
883 {
884     return m_value;
885 }
886
887 bool ApiTraceCall::hasError() const
888 {
889     return !m_error.isEmpty();
890 }
891
892 QString ApiTraceCall::error() const
893 {
894     return m_error;
895 }
896
897 void ApiTraceCall::setError(const QString &msg)
898 {
899     if (m_error != msg) {
900         ApiTrace *trace = parentTrace();
901         m_error = msg;
902         m_richText = QString();
903         if (trace)
904             trace->callError(this);
905     }
906 }
907
908 ApiTrace * ApiTraceCall::parentTrace() const
909 {
910     if (m_parentFrame)
911         return m_parentFrame->parentTrace();
912     return NULL;
913 }
914
915 void ApiTraceFrame::addCall(ApiTraceCall *call)
916 {
917     m_calls.append(call);
918     if (call->hasBinaryData()) {
919         QByteArray data =
920             call->arguments()[call->binaryDataIndex()].toByteArray();
921         m_binaryDataSize += data.size();
922     }
923 }
924
925 QList<ApiTraceCall*> ApiTraceFrame::calls() const
926 {
927     return m_calls;
928 }
929
930 ApiTraceCall * ApiTraceFrame::call(int idx) const
931 {
932     return m_calls.value(idx);
933 }
934
935 int ApiTraceFrame::callIndex(ApiTraceCall *call) const
936 {
937     return m_calls.indexOf(call);
938 }
939
940 bool ApiTraceFrame::isEmpty() const
941 {
942     return m_calls.isEmpty();
943 }
944
945 int ApiTraceFrame::binaryDataSize() const
946 {
947     return m_binaryDataSize;
948 }
949