]> git.cworth.org Git - apitrace/blob - gui/apitracecall.cpp
Unify Enum::Signature into EnumSig.
[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     QVariant val = QVariant(e->sig->value);
275
276     m_variant = QVariant::fromValue(
277         ApiEnum(QString::fromStdString(e->sig->name), val));
278 }
279
280 void VariantVisitor::visit(Trace::Bitmask *bitmask)
281 {
282     m_variant = QVariant::fromValue(ApiBitmask(bitmask));
283 }
284
285 void VariantVisitor::visit(Trace::Struct *str)
286 {
287     m_variant = QVariant::fromValue(ApiStruct(str));
288 }
289
290 void VariantVisitor::visit(Trace::Array *array)
291 {
292     m_variant = QVariant::fromValue(ApiArray(array));
293 }
294
295 void VariantVisitor::visit(Trace::Blob *blob)
296 {
297     //XXX
298     //FIXME: this is a nasty hack. Trace::Blob's can't
299     //   delete the contents in the destructor because
300     //   the data is being used by other calls. We piggy back
301     //   on that assumption and don't deep copy the data. If
302     //   Blob's will start deleting the data we will need to
303     //   start deep copying it or switch to using something like
304     //   Boost's shared_ptr or Qt's QSharedPointer to handle it
305     QByteArray barray = QByteArray::fromRawData(blob->buf, blob->size);
306     m_variant = QVariant(barray);
307 }
308
309 void VariantVisitor::visit(Trace::Pointer *ptr)
310 {
311     m_variant = QVariant::fromValue(ApiPointer(ptr->value));
312 }
313
314 ApiArray::ApiArray(const Trace::Array *arr)
315 {
316     init(arr);
317 }
318
319 ApiArray::ApiArray(const QList<QVariant> &vals)
320     : m_array(vals)
321 {
322 }
323
324 QString ApiArray::toString() const
325 {
326     QString str;
327     str += QLatin1String("[");
328     for(int i = 0; i < m_array.count(); ++i) {
329         const QVariant &var = m_array[i];
330         str += apiVariantToString(var);
331         if (i < m_array.count() - 1)
332             str += QLatin1String(", ");
333     }
334     str += QLatin1String("]");
335
336     return str;
337 }
338
339 void ApiArray::init(const Trace::Array *arr)
340 {
341     if (!arr)
342         return;
343
344     for (int i = 0; i < arr->values.size(); ++i) {
345         VariantVisitor vis;
346         arr->values[i]->visit(vis);
347
348         m_array.append(vis.variant());
349     }
350 }
351
352 QStaticText ApiTraceCall::staticText() const
353 {
354     if (m_staticText && !m_staticText->text().isEmpty())
355         return *m_staticText;
356
357     QVariantList argValues = arguments();
358
359     QString richText = QString::fromLatin1(
360         "<span style=\"font-weight:bold\">%1</span>(").arg(m_name);
361     for (int i = 0; i < m_argNames.count(); ++i) {
362         richText += QLatin1String("<span style=\"color:#0000ff\">");
363         QString argText = apiVariantToString(argValues[i]);
364
365         //if arguments are really long (e.g. shader text), cut them
366         // and elide it
367         if (argText.length() > 40) {
368             QString shortened = argText.mid(0, 40);
369             shortened[argText.length() - 5] = '.';
370             shortened[argText.length() - 4] = '.';
371             shortened[argText.length() - 3] = '.';
372             shortened[argText.length() - 2] = argText[argText.length() - 2];
373             shortened[argText.length() - 1] = argText[argText.length() - 1];
374             richText += shortened;
375         } else {
376             richText += argText;
377         }
378         richText += QLatin1String("</span>");
379         if (i < m_argNames.count() - 1)
380             richText += QLatin1String(", ");
381     }
382     richText += QLatin1String(")");
383     if (m_returnValue.isValid()) {
384         richText +=
385             QLatin1Literal(" = ") %
386             QLatin1Literal("<span style=\"color:#0000ff\">") %
387             apiVariantToString(m_returnValue) %
388             QLatin1Literal("</span>");
389     }
390
391     if (!m_staticText)
392         m_staticText = new QStaticText(richText);
393     else
394         m_staticText->setText(richText);
395     QTextOption opt;
396     opt.setWrapMode(QTextOption::NoWrap);
397     m_staticText->setTextOption(opt);
398     m_staticText->prepare();
399
400     return *m_staticText;
401 }
402
403 QString ApiTraceCall::toHtml() const
404 {
405     if (!m_richText.isEmpty())
406         return m_richText;
407
408     m_richText = QLatin1String("<div class=\"call\">");
409
410     if (m_helpUrl.isEmpty()) {
411         m_richText += QString::fromLatin1(
412             "%1) <span class=\"callName\">%2</span>(")
413                       .arg(m_index)
414                       .arg(m_name);
415     } else {
416         m_richText += QString::fromLatin1(
417             "%1) <span class=\"callName\"><a href=\"%2\">%3</a></span>(")
418                       .arg(m_index)
419                       .arg(m_helpUrl.toString())
420                       .arg(m_name);
421     }
422
423     QVariantList argValues = arguments();
424     for (int i = 0; i < m_argNames.count(); ++i) {
425         m_richText +=
426             QLatin1String("<span class=\"arg-name\">") +
427             m_argNames[i] +
428             QLatin1String("</span>") +
429             QLatin1Literal(" = ") +
430             QLatin1Literal("<span class=\"arg-value\">") +
431             apiVariantToString(argValues[i], true) +
432             QLatin1Literal("</span>");
433         if (i < m_argNames.count() - 1)
434             m_richText += QLatin1String(", ");
435     }
436     m_richText += QLatin1String(")");
437
438     if (m_returnValue.isValid()) {
439         m_richText +=
440             QLatin1String(" = ") +
441             QLatin1String("<span style=\"color:#0000ff\">") +
442             apiVariantToString(m_returnValue, true) +
443             QLatin1String("</span>");
444     }
445     m_richText += QLatin1String("</div>");
446
447     if (hasError()) {
448         QString errorStr =
449             QString::fromLatin1(
450                 "<div class=\"error\">%1</div>")
451             .arg(m_error);
452         m_richText += errorStr;
453     }
454
455     m_richText =
456         QString::fromLatin1(
457             "<html><head><style type=\"text/css\" media=\"all\">"
458             "%1</style></head><body>%2</body></html>")
459         .arg(styleSheet)
460         .arg(m_richText);
461     m_richText.squeeze();
462
463     //qDebug()<<m_richText;
464     return m_richText;
465 }
466
467 QString ApiTraceCall::filterText() const
468 {
469     if (!m_filterText.isEmpty())
470         return m_filterText;
471
472     QVariantList argValues = arguments();
473     m_filterText = m_name + QLatin1Literal("(");
474     for (int i = 0; i < m_argNames.count(); ++i) {
475         m_filterText += m_argNames[i] +
476                         QLatin1Literal(" = ") +
477                         apiVariantToString(argValues[i]);
478         if (i < m_argNames.count() - 1)
479             m_filterText += QLatin1String(", ");
480     }
481     m_filterText += QLatin1String(")");
482
483     if (m_returnValue.isValid()) {
484         m_filterText += QLatin1Literal(" = ") +
485                         apiVariantToString(m_returnValue);
486     }
487     m_filterText.squeeze();
488     return m_filterText;
489 }
490
491 QStaticText ApiTraceFrame::staticText() const
492 {
493     if (m_staticText && !m_staticText->text().isEmpty())
494         return *m_staticText;
495
496     QString richText;
497
498     //mark the frame if it uploads more than a meg a frame
499     if (m_binaryDataSize > (1024*1024)) {
500         richText =
501             QObject::tr(
502                 "<span style=\"font-weight:bold;\">"
503                 "Frame&nbsp;%1</span>"
504                 "<span style=\"font-style:italic;\">"
505                 "&nbsp;&nbsp;&nbsp;&nbsp;(%2MB)</span>")
506             .arg(number)
507             .arg(double(m_binaryDataSize / (1024.*1024.)), 0, 'g', 2);
508     } else {
509         richText =
510             QObject::tr(
511                 "<span style=\"font-weight:bold\">Frame %1</span>")
512             .arg(number);
513     }
514
515     if (!m_staticText)
516         m_staticText = new QStaticText(richText);
517
518     QTextOption opt;
519     opt.setWrapMode(QTextOption::NoWrap);
520     m_staticText->setTextOption(opt);
521     m_staticText->prepare();
522
523     return *m_staticText;
524 }
525
526 int ApiTraceCall::numChildren() const
527 {
528     return 0;
529 }
530
531 int ApiTraceFrame::numChildren() const
532 {
533     return m_calls.count();
534 }
535
536 ApiTraceFrame::ApiTraceFrame()
537     : ApiTraceEvent(ApiTraceEvent::Frame),
538       m_parentTrace(0),
539       m_binaryDataSize(0)
540 {
541 }
542
543 ApiTraceCall::ApiTraceCall()
544     : ApiTraceEvent(ApiTraceEvent::Call),
545       m_hasBinaryData(false),
546       m_binaryDataIndex(0)
547 {
548 }
549
550 ApiTraceEvent::ApiTraceEvent()
551     : m_type(ApiTraceEvent::None),
552       m_staticText(0)
553 {
554 }
555
556 ApiTraceEvent::ApiTraceEvent(Type t)
557     : m_type(t),
558       m_staticText(0)
559 {
560 }
561
562 ApiTraceCall::~ApiTraceCall()
563 {
564 }
565
566 QVariantMap ApiTraceEvent::stateParameters() const
567 {
568     return m_state.parameters();
569 }
570
571 ApiTraceState ApiTraceEvent::state() const
572 {
573     return m_state;
574 }
575
576 void ApiTraceEvent::setState(const ApiTraceState &state)
577 {
578     m_state = state;
579 }
580
581 bool ApiTraceCall::hasBinaryData() const
582 {
583     return m_hasBinaryData;
584 }
585
586 int ApiTraceCall::binaryDataIndex() const
587 {
588     return m_binaryDataIndex;
589 }
590
591 ApiTraceState::ApiTraceState()
592 {
593 }
594
595 ApiTraceState::ApiTraceState(const QVariantMap &parsedJson)
596 {
597     m_parameters = parsedJson[QLatin1String("parameters")].toMap();
598     QVariantMap attachedShaders =
599         parsedJson[QLatin1String("shaders")].toMap();
600     QVariantMap::const_iterator itr;
601
602
603     for (itr = attachedShaders.constBegin(); itr != attachedShaders.constEnd();
604          ++itr) {
605         QString type = itr.key();
606         QString source = itr.value().toString();
607         m_shaderSources[type] = source;
608     }
609
610     QVariantMap textures =
611         parsedJson[QLatin1String("textures")].toMap();
612     for (itr = textures.constBegin(); itr != textures.constEnd(); ++itr) {
613         QVariantMap image = itr.value().toMap();
614         QSize size(image[QLatin1String("__width__")].toInt(),
615                    image[QLatin1String("__height__")].toInt());
616         QString cls = image[QLatin1String("__class__")].toString();
617         QString type = image[QLatin1String("__type__")].toString();
618         bool normalized =
619             image[QLatin1String("__normalized__")].toBool();
620         int numChannels =
621             image[QLatin1String("__channels__")].toInt();
622
623         Q_ASSERT(type == QLatin1String("uint8"));
624         Q_ASSERT(normalized == true);
625
626         QByteArray dataArray =
627             image[QLatin1String("__data__")].toByteArray();
628
629         ApiTexture tex;
630         tex.setSize(size);
631         tex.setNumChannels(numChannels);
632         tex.setLabel(itr.key());
633         tex.contentsFromBase64(dataArray);
634
635         m_textures.append(tex);
636     }
637
638     QVariantMap fbos =
639         parsedJson[QLatin1String("framebuffer")].toMap();
640     for (itr = fbos.constBegin(); itr != fbos.constEnd(); ++itr) {
641         QVariantMap buffer = itr.value().toMap();
642         QSize size(buffer[QLatin1String("__width__")].toInt(),
643                    buffer[QLatin1String("__height__")].toInt());
644         QString cls = buffer[QLatin1String("__class__")].toString();
645         QString type = buffer[QLatin1String("__type__")].toString();
646         bool normalized = buffer[QLatin1String("__normalized__")].toBool();
647         int numChannels = buffer[QLatin1String("__channels__")].toInt();
648
649         Q_ASSERT(type == QLatin1String("uint8"));
650         Q_ASSERT(normalized == true);
651
652         QByteArray dataArray =
653             buffer[QLatin1String("__data__")].toByteArray();
654
655         ApiFramebuffer fbo;
656         fbo.setSize(size);
657         fbo.setNumChannels(numChannels);
658         fbo.setType(itr.key());
659         fbo.contentsFromBase64(dataArray);
660         m_framebuffers.append(fbo);
661     }
662 }
663
664 QVariantMap ApiTraceState::parameters() const
665 {
666     return m_parameters;
667 }
668
669 QMap<QString, QString> ApiTraceState::shaderSources() const
670 {
671     return m_shaderSources;
672 }
673
674 bool ApiTraceState::isEmpty() const
675 {
676     return m_parameters.isEmpty();
677 }
678
679 QList<ApiTexture> ApiTraceState::textures() const
680 {
681     return m_textures;
682 }
683
684 QList<ApiFramebuffer> ApiTraceState::framebuffers() const
685 {
686     return m_framebuffers;
687 }
688
689 QList<QVariant> ApiArray::values() const
690 {
691     return m_array;
692 }
693
694 int ApiTraceCall::index() const
695 {
696     return m_index;
697 }
698
699 QString ApiTraceCall::name() const
700 {
701     return m_name;
702 }
703
704 QStringList ApiTraceCall::argNames() const
705 {
706     return m_argNames;
707 }
708
709 QVariantList ApiTraceCall::arguments() const
710 {
711     if (m_editedValues.isEmpty())
712         return m_argValues;
713     else
714         return m_editedValues;
715 }
716
717 QVariant ApiTraceCall::returnValue() const
718 {
719     return m_returnValue;
720 }
721
722 QUrl ApiTraceCall::helpUrl() const
723 {
724     return m_helpUrl;
725 }
726
727 ApiTraceCall::ApiTraceCall(const Trace::Call *call)
728     : ApiTraceEvent(ApiTraceEvent::Call),
729       m_hasBinaryData(false),
730       m_binaryDataIndex(0)
731 {
732     m_name = QString::fromStdString(call->sig->name);
733     m_index = call->no;
734
735     QString argumentsText;
736     for (int i = 0; i < call->sig->arg_names.size(); ++i) {
737         m_argNames +=
738             QString::fromStdString(call->sig->arg_names[i]);
739     }
740     if (call->ret) {
741         VariantVisitor retVisitor;
742         call->ret->visit(retVisitor);
743         m_returnValue = retVisitor.variant();
744     }
745     for (int i = 0; i < call->args.size(); ++i) {
746         VariantVisitor argVisitor;
747         call->args[i]->visit(argVisitor);
748         m_argValues += argVisitor.variant();
749         if (m_argValues[i].type() == QVariant::ByteArray) {
750             m_hasBinaryData = true;
751             m_binaryDataIndex = i;
752         }
753     }
754 }
755
756 void ApiTraceCall::setHelpUrl(const QUrl &url)
757 {
758     m_helpUrl = url;
759 }
760
761 void ApiTraceCall::setParentFrame(ApiTraceFrame *frame)
762 {
763     m_parentFrame = frame;
764 }
765
766 ApiTraceFrame * ApiTraceCall::parentFrame()const
767 {
768     return m_parentFrame;
769 }
770
771 ApiTraceEvent::~ApiTraceEvent()
772 {
773     delete m_staticText;
774 }
775
776 void ApiTraceCall::revert()
777 {
778     setEditedValues(QVariantList());
779 }
780
781 ApiTrace * ApiTraceFrame::parentTrace() const
782 {
783     return m_parentTrace;
784 }
785
786 void ApiTraceFrame::setParentTrace(ApiTrace *trace)
787 {
788     m_parentTrace = trace;
789 }
790
791 QVariantList ApiTraceCall::originalValues() const
792 {
793     return m_argValues;
794 }
795
796 void ApiTraceCall::setEditedValues(const QVariantList &lst)
797 {
798     ApiTrace *trace = parentTrace();
799
800     m_editedValues = lst;
801     //lets regenerate data
802     m_richText = QString();
803     m_filterText = QString();
804     delete m_staticText;
805     m_staticText = 0;
806
807     if (trace) {
808         if (!lst.isEmpty()) {
809             trace->callEdited(this);
810         } else {
811             trace->callReverted(this);
812         }
813     }
814 }
815
816 QVariantList ApiTraceCall::editedValues() const
817 {
818     return m_editedValues;
819 }
820
821 bool ApiTraceCall::edited() const
822 {
823     return !m_editedValues.isEmpty();
824 }
825
826 ApiEnum::ApiEnum(const QString &name, const QVariant &val)
827     : m_name(name),
828       m_value(val)
829 {
830 }
831
832 QString ApiEnum::toString() const
833 {
834     return m_name;
835 }
836
837 QVariant ApiEnum::value() const
838 {
839     return m_value;
840 }
841
842 QString ApiEnum::name() const
843 {
844     return m_name;
845 }
846
847 unsigned long long ApiBitmask::value() const
848 {
849     return m_value;
850 }
851
852 ApiBitmask::Signature ApiBitmask::signature() const
853 {
854     return m_sig;
855 }
856
857 ApiStruct::Signature ApiStruct::signature() const
858 {
859     return m_sig;
860 }
861
862 QList<QVariant> ApiStruct::values() const
863 {
864     return m_members;
865 }
866
867 unsigned long long ApiPointer::value() const
868 {
869     return m_value;
870 }
871
872 bool ApiTraceCall::hasError() const
873 {
874     return !m_error.isEmpty();
875 }
876
877 QString ApiTraceCall::error() const
878 {
879     return m_error;
880 }
881
882 void ApiTraceCall::setError(const QString &msg)
883 {
884     if (m_error != msg) {
885         ApiTrace *trace = parentTrace();
886         m_error = msg;
887         m_richText = QString();
888         if (trace)
889             trace->callError(this);
890     }
891 }
892
893 ApiTrace * ApiTraceCall::parentTrace() const
894 {
895     if (m_parentFrame)
896         return m_parentFrame->parentTrace();
897     return NULL;
898 }
899
900 void ApiTraceFrame::addCall(ApiTraceCall *call)
901 {
902     m_calls.append(call);
903     if (call->hasBinaryData()) {
904         QByteArray data =
905             call->arguments()[call->binaryDataIndex()].toByteArray();
906         m_binaryDataSize += data.size();
907     }
908 }
909
910 QList<ApiTraceCall*> ApiTraceFrame::calls() const
911 {
912     return m_calls;
913 }
914
915 ApiTraceCall * ApiTraceFrame::call(int idx) const
916 {
917     return m_calls.value(idx);
918 }
919
920 int ApiTraceFrame::callIndex(ApiTraceCall *call) const
921 {
922     return m_calls.indexOf(call);
923 }
924
925 bool ApiTraceFrame::isEmpty() const
926 {
927     return m_calls.isEmpty();
928 }
929
930 int ApiTraceFrame::binaryDataSize() const
931 {
932     return m_binaryDataSize;
933 }
934