blob: 67fc955957805308f71fb8b9c0ac06c37933fe4e [file] [log] [blame]
Zack Rusin91065372011-03-26 01:54:10 -04001#include "apitracecall.h"
2
Zack Rusin661842d2011-04-17 01:59:16 -04003#include "apitrace.h"
Zack Rusinebf971e2011-09-06 17:44:43 -04004#include "traceloader.h"
Zack Rusin91065372011-03-26 01:54:10 -04005#include "trace_model.hpp"
6
7#include <QDebug>
Zack Rusin9e292fc2011-04-26 23:03:42 -04008#include <QLocale>
Zack Rusin35451522011-04-02 23:44:53 -04009#include <QObject>
Zack Rusin5e277b02011-04-16 21:52:26 -040010#define QT_USE_FAST_OPERATOR_PLUS
11#include <QStringBuilder>
José Fonsecae8a1aa92011-04-21 09:13:23 +010012#include <QTextDocument>
Zack Rusin91065372011-03-26 01:54:10 -040013
Zack Rusinb53b1612011-04-19 01:33:58 -040014const char * const styleSheet =
15 ".call {\n"
16 " font-weight:bold;\n"
17 // text shadow looks great but doesn't work well in qtwebkit 4.7
18 " /*text-shadow: 0px 2px 3px #555;*/\n"
19 " font-size: 1.2em;\n"
20 "}\n"
21 ".arg-name {\n"
22 " border: 1px solid rgb(238,206,0);\n"
23 " border-radius: 4px;\n"
24 " background: yellow;\n"
25 " padding: 2px;\n"
26 " box-shadow: 0px 1px 3px dimgrey;\n"
27 " -webkit-transition: background 1s linear;\n"
28 "}\n"
29 ".arg-name:hover {\n"
30 " background: white;\n"
31 "}\n"
32 ".arg-value {\n"
33 " color: #0000ff;\n"
34 "}\n"
35 ".error {\n"
Zack Rusincc0b4912011-04-19 01:59:20 -040036 " border: 1px solid rgb(255,0,0);\n"
Zack Rusinb53b1612011-04-19 01:33:58 -040037 " margin: 10px;\n"
Zack Rusincc0b4912011-04-19 01:59:20 -040038 " padding: 1;\n"
39 " border-radius: 4px;\n"
40 // also looks great but qtwebkit doesn't support it
41 //" background: #6fb2e5;\n"
42 //" box-shadow: 0 1px 5px #0061aa, inset 0 10px 20px #b6f9ff;\n"
43 //" -o-box-shadow: 0 1px 5px #0061aa, inset 0 10px 20px #b6f9ff;\n"
44 //" -webkit-box-shadow: 0 1px 5px #0061aa, inset 0 10px 20px #b6f9ff;\n"
45 //" -moz-box-shadow: 0 1px 5px #0061aa, inset 0 10px 20px #b6f9ff;\n"
Zack Rusinb53b1612011-04-19 01:33:58 -040046 "}\n";
47
Zack Rusin91065372011-03-26 01:54:10 -040048
José Fonsecae8a1aa92011-04-21 09:13:23 +010049// Qt::convertFromPlainText doesn't do precisely what we want
50static QString
51plainTextToHTML(const QString & plain, bool multiLine)
52{
53 int col = 0;
54 bool quote = false;
55 QString rich;
56 for (int i = 0; i < plain.length(); ++i) {
57 if (plain[i] == QLatin1Char('\n')){
58 if (multiLine) {
59 rich += QLatin1String("<br>\n");
60 } else {
61 rich += QLatin1String("\\n");
62 }
63 col = 0;
64 quote = true;
65 } else {
66 if (plain[i] == QLatin1Char('\t')){
67 if (multiLine) {
68 rich += QChar(0x00a0U);
69 ++col;
70 while (col % 8) {
71 rich += QChar(0x00a0U);
72 ++col;
73 }
74 } else {
75 rich += QLatin1String("\\t");
76 }
77 quote = true;
78 } else if (plain[i].isSpace()) {
79 rich += QChar(0x00a0U);
80 quote = true;
81 } else if (plain[i] == QLatin1Char('<')) {
82 rich += QLatin1String("&lt;");
83 } else if (plain[i] == QLatin1Char('>')) {
84 rich += QLatin1String("&gt;");
85 } else if (plain[i] == QLatin1Char('&')) {
86 rich += QLatin1String("&amp;");
87 } else {
88 rich += plain[i];
89 }
90 ++col;
91 }
92 }
93
94 if (quote) {
95 return QLatin1Literal("\"") + rich + QLatin1Literal("\"");
96 }
97
98 return rich;
99}
100
Zack Rusina1a3ad52011-08-27 19:19:18 -0400101QString
102apiVariantToString(const QVariant &variant, bool multiLine)
Zack Rusin91065372011-03-26 01:54:10 -0400103{
104 if (variant.userType() == QVariant::Double) {
105 return QString::number(variant.toFloat());
106 }
Zack Rusin35451522011-04-02 23:44:53 -0400107 if (variant.userType() == QVariant::ByteArray) {
Zack Rusin8e7a4ff2011-04-07 01:15:48 -0400108 if (variant.toByteArray().size() < 1024) {
109 int bytes = variant.toByteArray().size();
110 return QObject::tr("[binary data, size = %1 bytes]").arg(bytes);
111 } else {
112 float kb = variant.toByteArray().size()/1024.;
113 return QObject::tr("[binary data, size = %1 kb]").arg(kb);
114 }
Zack Rusin35451522011-04-02 23:44:53 -0400115 }
Zack Rusin91065372011-03-26 01:54:10 -0400116
José Fonsecae8a1aa92011-04-21 09:13:23 +0100117 if (variant.userType() == QVariant::String) {
118 return plainTextToHTML(variant.toString(), multiLine);
119 }
120
Zack Rusin91065372011-03-26 01:54:10 -0400121 if (variant.userType() < QVariant::UserType) {
122 return variant.toString();
123 }
124
125 if (variant.canConvert<ApiPointer>()) {
126 return variant.value<ApiPointer>().toString();
127 }
128 if (variant.canConvert<ApiBitmask>()) {
129 return variant.value<ApiBitmask>().toString();
130 }
131 if (variant.canConvert<ApiStruct>()) {
132 return variant.value<ApiStruct>().toString();
133 }
134 if (variant.canConvert<ApiArray>()) {
135 return variant.value<ApiArray>().toString();
136 }
Zack Rusind54055e2011-04-17 18:27:28 -0400137 if (variant.canConvert<ApiEnum>()) {
138 return variant.value<ApiEnum>().toString();
139 }
Zack Rusin91065372011-03-26 01:54:10 -0400140
141 return QString();
142}
143
Zack Rusina1a3ad52011-08-27 19:19:18 -0400144
145void VariantVisitor::visit(Trace::Null *)
146{
147 m_variant = QVariant::fromValue(ApiPointer(0));
148}
149
150void VariantVisitor::visit(Trace::Bool *node)
151{
152 m_variant = QVariant(node->value);
153}
154
155void VariantVisitor::visit(Trace::SInt *node)
156{
157 m_variant = QVariant(node->value);
158}
159
160void VariantVisitor::visit(Trace::UInt *node)
161{
162 m_variant = QVariant(node->value);
163}
164
165void VariantVisitor::visit(Trace::Float *node)
166{
167 m_variant = QVariant(node->value);
168}
169
170void VariantVisitor::visit(Trace::String *node)
171{
172 m_variant = QVariant(QString::fromStdString(node->value));
173}
174
175void VariantVisitor::visit(Trace::Enum *e)
176{
Zack Rusin35c27932011-08-28 21:16:22 -0400177 ApiTraceEnumSignature *sig = 0;
Zack Rusina1a3ad52011-08-27 19:19:18 -0400178
Zack Rusinebf971e2011-09-06 17:44:43 -0400179 if (m_loader) {
180 sig = m_loader->enumSignature(e->sig->id);
Zack Rusin35c27932011-08-28 21:16:22 -0400181 }
182 if (!sig) {
183 sig = new ApiTraceEnumSignature(
184 QString::fromStdString(e->sig->name),
185 QVariant(e->sig->value));
Zack Rusinebf971e2011-09-06 17:44:43 -0400186 if (m_loader) {
187 m_loader->addEnumSignature(e->sig->id, sig);
Zack Rusin35c27932011-08-28 21:16:22 -0400188 }
189 }
190
191 m_variant = QVariant::fromValue(ApiEnum(sig));
Zack Rusina1a3ad52011-08-27 19:19:18 -0400192}
193
194void VariantVisitor::visit(Trace::Bitmask *bitmask)
195{
196 m_variant = QVariant::fromValue(ApiBitmask(bitmask));
197}
198
199void VariantVisitor::visit(Trace::Struct *str)
200{
201 m_variant = QVariant::fromValue(ApiStruct(str));
202}
203
204void VariantVisitor::visit(Trace::Array *array)
205{
206 m_variant = QVariant::fromValue(ApiArray(array));
207}
208
209void VariantVisitor::visit(Trace::Blob *blob)
210{
211 //XXX
212 //FIXME: this is a nasty hack. Trace::Blob's can't
213 // delete the contents in the destructor because
214 // the data is being used by other calls. We piggy back
215 // on that assumption and don't deep copy the data. If
216 // Blob's will start deleting the data we will need to
217 // start deep copying it or switch to using something like
218 // Boost's shared_ptr or Qt's QSharedPointer to handle it
Zack Rusin0983c322011-08-28 23:28:05 -0400219 blob->toPointer(true);
Zack Rusina1a3ad52011-08-27 19:19:18 -0400220 QByteArray barray = QByteArray::fromRawData(blob->buf, blob->size);
221 m_variant = QVariant(barray);
222}
223
224void VariantVisitor::visit(Trace::Pointer *ptr)
225{
226 m_variant = QVariant::fromValue(ApiPointer(ptr->value));
227}
228
229
Zack Rusin35c27932011-08-28 21:16:22 -0400230ApiEnum::ApiEnum(ApiTraceEnumSignature *sig)
231 : m_sig(sig)
Zack Rusina1a3ad52011-08-27 19:19:18 -0400232{
233}
234
235QString ApiEnum::toString() const
236{
Zack Rusin35c27932011-08-28 21:16:22 -0400237 if (m_sig) {
238 return m_sig->name();
239 }
240 Q_ASSERT(!"should never happen");
241 return QString();
Zack Rusina1a3ad52011-08-27 19:19:18 -0400242}
243
244QVariant ApiEnum::value() const
245{
Zack Rusin35c27932011-08-28 21:16:22 -0400246 if (m_sig) {
247 return m_sig->value();
248 }
249 Q_ASSERT(!"should never happen");
250 return QVariant();
Zack Rusina1a3ad52011-08-27 19:19:18 -0400251}
252
253QString ApiEnum::name() const
254{
Zack Rusin35c27932011-08-28 21:16:22 -0400255 if (m_sig) {
256 return m_sig->name();
257 }
258 Q_ASSERT(!"should never happen");
259 return QString();
Zack Rusina1a3ad52011-08-27 19:19:18 -0400260}
261
262unsigned long long ApiBitmask::value() const
263{
264 return m_value;
265}
266
267ApiBitmask::Signature ApiBitmask::signature() const
268{
269 return m_sig;
270}
271
272ApiStruct::Signature ApiStruct::signature() const
273{
274 return m_sig;
275}
276
277QList<QVariant> ApiStruct::values() const
278{
279 return m_members;
280}
281
282ApiPointer::ApiPointer(unsigned long long val)
283 : m_value(val)
284{
285}
286
287
288unsigned long long ApiPointer::value() const
289{
290 return m_value;
291}
292
293QString ApiPointer::toString() const
294{
295 if (m_value)
296 return QString("0x%1").arg(m_value, 0, 16);
297 else
298 return QLatin1String("NULL");
299}
300
Zack Rusin91065372011-03-26 01:54:10 -0400301ApiBitmask::ApiBitmask(const Trace::Bitmask *bitmask)
302 : m_value(0)
303{
304 init(bitmask);
305}
306
Zack Rusin91065372011-03-26 01:54:10 -0400307void ApiBitmask::init(const Trace::Bitmask *bitmask)
308{
309 if (!bitmask)
310 return;
311
312 m_value = bitmask->value;
José Fonsecafcfbf172011-05-28 13:20:01 +0100313 for (const Trace::BitmaskFlag *it = bitmask->sig->flags;
314 it != bitmask->sig->flags + bitmask->sig->num_flags; ++it) {
José Fonseca31b183a2011-05-28 12:21:15 +0100315 assert(it->value);
Zack Rusin91065372011-03-26 01:54:10 -0400316 QPair<QString, unsigned long long> pair;
317
José Fonseca31b183a2011-05-28 12:21:15 +0100318 pair.first = QString::fromStdString(it->name);
319 pair.second = it->value;
Zack Rusin91065372011-03-26 01:54:10 -0400320
321 m_sig.append(pair);
322 }
323}
324
325QString ApiBitmask::toString() const
326{
327 QString str;
328 unsigned long long value = m_value;
329 bool first = true;
330 for (Signature::const_iterator it = m_sig.begin();
331 value != 0 && it != m_sig.end(); ++it) {
332 Q_ASSERT(it->second);
333 if ((value & it->second) == it->second) {
334 if (!first) {
335 str += QLatin1String(" | ");
336 }
337 str += it->first;
338 value &= ~it->second;
339 first = false;
340 }
341 }
342 if (value || first) {
343 if (!first) {
344 str += QLatin1String(" | ");
345 }
346 str += QString::fromLatin1("0x%1").arg(value, 0, 16);
347 }
348 return str;
349}
350
351ApiStruct::ApiStruct(const Trace::Struct *s)
352{
353 init(s);
354}
355
356QString ApiStruct::toString() const
357{
358 QString str;
359
360 str += QLatin1String("{");
361 for (unsigned i = 0; i < m_members.count(); ++i) {
Zack Rusin5e277b02011-04-16 21:52:26 -0400362 str += m_sig.memberNames[i] %
363 QLatin1Literal(" = ") %
364 apiVariantToString(m_members[i]);
Zack Rusin91065372011-03-26 01:54:10 -0400365 if (i < m_members.count() - 1)
366 str += QLatin1String(", ");
367 }
368 str += QLatin1String("}");
369
370 return str;
371}
372
373void ApiStruct::init(const Trace::Struct *s)
374{
375 if (!s)
376 return;
377
378 m_sig.name = QString::fromStdString(s->sig->name);
José Fonseca1b23ed22011-05-28 13:01:16 +0100379 for (unsigned i = 0; i < s->sig->num_members; ++i) {
Zack Rusin35c27932011-08-28 21:16:22 -0400380 VariantVisitor vis(0);
Zack Rusin91065372011-03-26 01:54:10 -0400381 m_sig.memberNames.append(
382 QString::fromStdString(s->sig->member_names[i]));
383 s->members[i]->visit(vis);
384 m_members.append(vis.variant());
385 }
386}
387
Zack Rusin91065372011-03-26 01:54:10 -0400388ApiArray::ApiArray(const Trace::Array *arr)
389{
390 init(arr);
391}
392
Zack Rusin77ff98a2011-08-28 22:30:35 -0400393ApiArray::ApiArray(const QVector<QVariant> &vals)
Zack Rusinabb3fde2011-04-16 02:16:49 -0400394 : m_array(vals)
395{
396}
397
Zack Rusin77ff98a2011-08-28 22:30:35 -0400398QVector<QVariant> ApiArray::values() const
Zack Rusina1a3ad52011-08-27 19:19:18 -0400399{
400 return m_array;
401}
402
Zack Rusin91065372011-03-26 01:54:10 -0400403QString ApiArray::toString() const
404{
405 QString str;
406 str += QLatin1String("[");
407 for(int i = 0; i < m_array.count(); ++i) {
408 const QVariant &var = m_array[i];
409 str += apiVariantToString(var);
410 if (i < m_array.count() - 1)
411 str += QLatin1String(", ");
412 }
413 str += QLatin1String("]");
414
415 return str;
416}
417
418void ApiArray::init(const Trace::Array *arr)
419{
420 if (!arr)
421 return;
422
Zack Rusin3c70dbf2011-08-28 03:10:01 -0400423 m_array.reserve(arr->values.size());
Zack Rusin91065372011-03-26 01:54:10 -0400424 for (int i = 0; i < arr->values.size(); ++i) {
Zack Rusin35c27932011-08-28 21:16:22 -0400425 VariantVisitor vis(0);
Zack Rusin91065372011-03-26 01:54:10 -0400426 arr->values[i]->visit(vis);
427
428 m_array.append(vis.variant());
429 }
Zack Rusin77ff98a2011-08-28 22:30:35 -0400430 m_array.squeeze();
Zack Rusin91065372011-03-26 01:54:10 -0400431}
Zack Rusin18eade52011-03-26 14:23:35 -0400432
Zack Rusina1a3ad52011-08-27 19:19:18 -0400433ApiTraceState::ApiTraceState()
434{
435}
436
437ApiTraceState::ApiTraceState(const QVariantMap &parsedJson)
438{
439 m_parameters = parsedJson[QLatin1String("parameters")].toMap();
440 QVariantMap attachedShaders =
441 parsedJson[QLatin1String("shaders")].toMap();
442 QVariantMap::const_iterator itr;
443
444
445 for (itr = attachedShaders.constBegin(); itr != attachedShaders.constEnd();
446 ++itr) {
447 QString type = itr.key();
448 QString source = itr.value().toString();
449 m_shaderSources[type] = source;
450 }
451
452 m_uniforms = parsedJson[QLatin1String("uniforms")].toMap();
453
454 QVariantMap textures =
455 parsedJson[QLatin1String("textures")].toMap();
456 for (itr = textures.constBegin(); itr != textures.constEnd(); ++itr) {
457 QVariantMap image = itr.value().toMap();
458 QSize size(image[QLatin1String("__width__")].toInt(),
459 image[QLatin1String("__height__")].toInt());
460 QString cls = image[QLatin1String("__class__")].toString();
461 QString type = image[QLatin1String("__type__")].toString();
462 bool normalized =
463 image[QLatin1String("__normalized__")].toBool();
464 int numChannels =
465 image[QLatin1String("__channels__")].toInt();
466
467 Q_ASSERT(type == QLatin1String("uint8"));
468 Q_ASSERT(normalized == true);
Zack Rusindf95ce02011-08-27 19:46:16 -0400469 Q_UNUSED(normalized);
Zack Rusina1a3ad52011-08-27 19:19:18 -0400470
471 QByteArray dataArray =
472 image[QLatin1String("__data__")].toByteArray();
473
474 ApiTexture tex;
475 tex.setSize(size);
476 tex.setNumChannels(numChannels);
477 tex.setLabel(itr.key());
478 tex.contentsFromBase64(dataArray);
479
480 m_textures.append(tex);
481 }
482
483 QVariantMap fbos =
484 parsedJson[QLatin1String("framebuffer")].toMap();
485 for (itr = fbos.constBegin(); itr != fbos.constEnd(); ++itr) {
486 QVariantMap buffer = itr.value().toMap();
487 QSize size(buffer[QLatin1String("__width__")].toInt(),
488 buffer[QLatin1String("__height__")].toInt());
489 QString cls = buffer[QLatin1String("__class__")].toString();
490 QString type = buffer[QLatin1String("__type__")].toString();
491 bool normalized = buffer[QLatin1String("__normalized__")].toBool();
492 int numChannels = buffer[QLatin1String("__channels__")].toInt();
493
494 Q_ASSERT(type == QLatin1String("uint8"));
495 Q_ASSERT(normalized == true);
Zack Rusindf95ce02011-08-27 19:46:16 -0400496 Q_UNUSED(normalized);
Zack Rusina1a3ad52011-08-27 19:19:18 -0400497
498 QByteArray dataArray =
499 buffer[QLatin1String("__data__")].toByteArray();
500
501 ApiFramebuffer fbo;
502 fbo.setSize(size);
503 fbo.setNumChannels(numChannels);
504 fbo.setType(itr.key());
505 fbo.contentsFromBase64(dataArray);
506 m_framebuffers.append(fbo);
507 }
508}
509
510const QVariantMap & ApiTraceState::parameters() const
511{
512 return m_parameters;
513}
514
515const QMap<QString, QString> & ApiTraceState::shaderSources() const
516{
517 return m_shaderSources;
518}
519
520const QVariantMap & ApiTraceState::uniforms() const
521{
522 return m_uniforms;
523}
524
525bool ApiTraceState::isEmpty() const
526{
527 return m_parameters.isEmpty();
528}
529
530const QList<ApiTexture> & ApiTraceState::textures() const
531{
532 return m_textures;
533}
534
535const QList<ApiFramebuffer> & ApiTraceState::framebuffers() const
536{
537 return m_framebuffers;
538}
539
Zack Rusin353f0532011-09-15 20:23:27 -0400540ApiFramebuffer ApiTraceState::colorBuffer() const
541{
542 foreach (ApiFramebuffer fbo, m_framebuffers) {
543 if (fbo.type() == QLatin1String("GL_BACK")) {
544 return fbo;
545 }
546 }
547 foreach (ApiFramebuffer fbo, m_framebuffers) {
548 if (fbo.type() == QLatin1String("GL_FRONT")) {
549 return fbo;
550 }
551 }
552 return ApiFramebuffer();
553}
554
555
Zack Rusinac4dd9a2011-08-28 00:38:13 -0400556ApiTraceCallSignature::ApiTraceCallSignature(const QString &name,
557 const QStringList &argNames)
558 : m_name(name),
559 m_argNames(argNames)
560{
561}
562
563ApiTraceCallSignature::~ApiTraceCallSignature()
564{
565}
566
567QUrl ApiTraceCallSignature::helpUrl() const
568{
569 return m_helpUrl;
570}
571
572void ApiTraceCallSignature::setHelpUrl(const QUrl &url)
573{
574 m_helpUrl = url;
575}
576
Zack Rusina1a3ad52011-08-27 19:19:18 -0400577ApiTraceEvent::ApiTraceEvent()
578 : m_type(ApiTraceEvent::None),
Zack Rusined40bc62011-08-28 17:11:02 -0400579 m_hasBinaryData(false),
580 m_binaryDataIndex(0),
581 m_state(0),
Zack Rusina1a3ad52011-08-27 19:19:18 -0400582 m_staticText(0)
583{
584}
585
586ApiTraceEvent::ApiTraceEvent(Type t)
587 : m_type(t),
Zack Rusined40bc62011-08-28 17:11:02 -0400588 m_hasBinaryData(false),
589 m_binaryDataIndex(0),
590 m_state(0),
Zack Rusina1a3ad52011-08-27 19:19:18 -0400591 m_staticText(0)
592{
593}
594
595ApiTraceEvent::~ApiTraceEvent()
596{
Zack Rusined40bc62011-08-28 17:11:02 -0400597 delete m_state;
Zack Rusina1a3ad52011-08-27 19:19:18 -0400598 delete m_staticText;
599}
600
601QVariantMap ApiTraceEvent::stateParameters() const
602{
Zack Rusined40bc62011-08-28 17:11:02 -0400603 if (m_state) {
604 return m_state->parameters();
605 } else {
606 return QVariantMap();
607 }
Zack Rusina1a3ad52011-08-27 19:19:18 -0400608}
609
Zack Rusined40bc62011-08-28 17:11:02 -0400610ApiTraceState *ApiTraceEvent::state() const
Zack Rusina1a3ad52011-08-27 19:19:18 -0400611{
612 return m_state;
613}
614
Zack Rusined40bc62011-08-28 17:11:02 -0400615void ApiTraceEvent::setState(ApiTraceState *state)
Zack Rusina1a3ad52011-08-27 19:19:18 -0400616{
617 m_state = state;
618}
619
Zack Rusinebf971e2011-09-06 17:44:43 -0400620ApiTraceCall::ApiTraceCall(ApiTraceFrame *parentFrame,
621 TraceLoader *loader,
622 const Trace::Call *call)
Zack Rusina1a3ad52011-08-27 19:19:18 -0400623 : ApiTraceEvent(ApiTraceEvent::Call),
Zack Rusined40bc62011-08-28 17:11:02 -0400624 m_parentFrame(parentFrame)
Zack Rusina1a3ad52011-08-27 19:19:18 -0400625{
Zack Rusina1a3ad52011-08-27 19:19:18 -0400626 m_index = call->no;
627
Zack Rusinebf971e2011-09-06 17:44:43 -0400628 m_signature = loader->signature(call->sig->id);
Zack Rusinac4dd9a2011-08-28 00:38:13 -0400629
630 if (!m_signature) {
Zack Rusinb31e2142011-08-28 19:38:00 -0400631 QString name = QString::fromStdString(call->sig->name);
Zack Rusinac4dd9a2011-08-28 00:38:13 -0400632 QStringList argNames;
Zack Rusinf22d7992011-08-28 02:23:47 -0400633 argNames.reserve(call->sig->num_args);
Zack Rusinac4dd9a2011-08-28 00:38:13 -0400634 for (int i = 0; i < call->sig->num_args; ++i) {
Zack Rusinf22d7992011-08-28 02:23:47 -0400635 argNames += QString::fromStdString(call->sig->arg_names[i]);
Zack Rusinac4dd9a2011-08-28 00:38:13 -0400636 }
637 m_signature = new ApiTraceCallSignature(name, argNames);
Zack Rusinebf971e2011-09-06 17:44:43 -0400638 loader->addSignature(call->sig->id, m_signature);
Zack Rusina1a3ad52011-08-27 19:19:18 -0400639 }
640 if (call->ret) {
Zack Rusinebf971e2011-09-06 17:44:43 -0400641 VariantVisitor retVisitor(loader);
Zack Rusina1a3ad52011-08-27 19:19:18 -0400642 call->ret->visit(retVisitor);
643 m_returnValue = retVisitor.variant();
644 }
Zack Rusinf22d7992011-08-28 02:23:47 -0400645 m_argValues.reserve(call->args.size());
Zack Rusina1a3ad52011-08-27 19:19:18 -0400646 for (int i = 0; i < call->args.size(); ++i) {
Zack Rusinebf971e2011-09-06 17:44:43 -0400647 VariantVisitor argVisitor(loader);
Zack Rusina1a3ad52011-08-27 19:19:18 -0400648 call->args[i]->visit(argVisitor);
Zack Rusinf22d7992011-08-28 02:23:47 -0400649 m_argValues.append(argVisitor.variant());
Zack Rusina1a3ad52011-08-27 19:19:18 -0400650 if (m_argValues[i].type() == QVariant::ByteArray) {
651 m_hasBinaryData = true;
652 m_binaryDataIndex = i;
653 }
654 }
Zack Rusinf736a622011-08-28 22:19:46 -0400655 m_argValues.squeeze();
Zack Rusina1a3ad52011-08-27 19:19:18 -0400656}
657
658ApiTraceCall::~ApiTraceCall()
659{
660}
661
662
663bool ApiTraceCall::hasError() const
664{
665 return !m_error.isEmpty();
666}
667
668QString ApiTraceCall::error() const
669{
670 return m_error;
671}
672
673void ApiTraceCall::setError(const QString &msg)
674{
675 if (m_error != msg) {
Zack Rusina1a3ad52011-08-27 19:19:18 -0400676 m_error = msg;
677 m_richText = QString();
Zack Rusina1a3ad52011-08-27 19:19:18 -0400678 }
679}
680
681ApiTrace * ApiTraceCall::parentTrace() const
682{
683 if (m_parentFrame)
684 return m_parentFrame->parentTrace();
685 return NULL;
686}
687
Zack Rusinf736a622011-08-28 22:19:46 -0400688QVector<QVariant> ApiTraceCall::originalValues() const
Zack Rusina1a3ad52011-08-27 19:19:18 -0400689{
690 return m_argValues;
691}
692
Zack Rusinf736a622011-08-28 22:19:46 -0400693void ApiTraceCall::setEditedValues(const QVector<QVariant> &lst)
Zack Rusina1a3ad52011-08-27 19:19:18 -0400694{
695 ApiTrace *trace = parentTrace();
696
697 m_editedValues = lst;
698 //lets regenerate data
699 m_richText = QString();
Zack Rusindc792082011-08-27 23:29:19 -0400700 m_searchText = QString();
Zack Rusina1a3ad52011-08-27 19:19:18 -0400701 delete m_staticText;
702 m_staticText = 0;
703
704 if (trace) {
705 if (!lst.isEmpty()) {
706 trace->callEdited(this);
707 } else {
708 trace->callReverted(this);
709 }
710 }
711}
712
Zack Rusinf736a622011-08-28 22:19:46 -0400713QVector<QVariant> ApiTraceCall::editedValues() const
Zack Rusina1a3ad52011-08-27 19:19:18 -0400714{
715 return m_editedValues;
716}
717
718bool ApiTraceCall::edited() const
719{
720 return !m_editedValues.isEmpty();
721}
722
723void ApiTraceCall::revert()
724{
Zack Rusinf736a622011-08-28 22:19:46 -0400725 setEditedValues(QVector<QVariant>());
Zack Rusina1a3ad52011-08-27 19:19:18 -0400726}
727
728void ApiTraceCall::setHelpUrl(const QUrl &url)
729{
Zack Rusinac4dd9a2011-08-28 00:38:13 -0400730 m_signature->setHelpUrl(url);
Zack Rusina1a3ad52011-08-27 19:19:18 -0400731}
732
733void ApiTraceCall::setParentFrame(ApiTraceFrame *frame)
734{
735 m_parentFrame = frame;
736}
737
738ApiTraceFrame * ApiTraceCall::parentFrame()const
739{
740 return m_parentFrame;
741}
742
743int ApiTraceCall::index() const
744{
745 return m_index;
746}
747
748QString ApiTraceCall::name() const
749{
Zack Rusinac4dd9a2011-08-28 00:38:13 -0400750 return m_signature->name();
Zack Rusina1a3ad52011-08-27 19:19:18 -0400751}
752
753QStringList ApiTraceCall::argNames() const
754{
Zack Rusinac4dd9a2011-08-28 00:38:13 -0400755 return m_signature->argNames();
Zack Rusina1a3ad52011-08-27 19:19:18 -0400756}
757
Zack Rusinf736a622011-08-28 22:19:46 -0400758QVector<QVariant> ApiTraceCall::arguments() const
Zack Rusina1a3ad52011-08-27 19:19:18 -0400759{
760 if (m_editedValues.isEmpty())
761 return m_argValues;
762 else
763 return m_editedValues;
764}
765
766QVariant ApiTraceCall::returnValue() const
767{
768 return m_returnValue;
769}
770
771QUrl ApiTraceCall::helpUrl() const
772{
Zack Rusinac4dd9a2011-08-28 00:38:13 -0400773 return m_signature->helpUrl();
Zack Rusina1a3ad52011-08-27 19:19:18 -0400774}
775
776bool ApiTraceCall::hasBinaryData() const
777{
778 return m_hasBinaryData;
779}
780
781int ApiTraceCall::binaryDataIndex() const
782{
783 return m_binaryDataIndex;
784}
785
Zack Rusin18eade52011-03-26 14:23:35 -0400786QStaticText ApiTraceCall::staticText() const
787{
Zack Rusin53484b22011-04-16 11:56:19 -0400788 if (m_staticText && !m_staticText->text().isEmpty())
789 return *m_staticText;
Zack Rusin18eade52011-03-26 14:23:35 -0400790
Zack Rusinf736a622011-08-28 22:19:46 -0400791 QVector<QVariant> argValues = arguments();
Zack Rusin9af5bff2011-04-18 01:05:50 -0400792
Zack Rusin53484b22011-04-16 11:56:19 -0400793 QString richText = QString::fromLatin1(
Zack Rusinac4dd9a2011-08-28 00:38:13 -0400794 "<span style=\"font-weight:bold\">%1</span>(").arg(
795 m_signature->name());
796 QStringList argNames = m_signature->argNames();
797 for (int i = 0; i < argNames.count(); ++i) {
Zack Rusin27cb2c42011-03-27 23:53:36 -0400798 richText += QLatin1String("<span style=\"color:#0000ff\">");
Zack Rusin9af5bff2011-04-18 01:05:50 -0400799 QString argText = apiVariantToString(argValues[i]);
Zack Rusindd7f2302011-03-31 22:55:57 -0400800
801 //if arguments are really long (e.g. shader text), cut them
802 // and elide it
803 if (argText.length() > 40) {
804 QString shortened = argText.mid(0, 40);
805 shortened[argText.length() - 5] = '.';
806 shortened[argText.length() - 4] = '.';
807 shortened[argText.length() - 3] = '.';
Zack Rusindf95ce02011-08-27 19:46:16 -0400808 shortened[argText.length() - 2] = argText.at(argText.length() - 2);
809 shortened[argText.length() - 1] = argText.at(argText.length() - 1);
Zack Rusindd7f2302011-03-31 22:55:57 -0400810 richText += shortened;
811 } else {
812 richText += argText;
813 }
Zack Rusin27cb2c42011-03-27 23:53:36 -0400814 richText += QLatin1String("</span>");
Zack Rusinac4dd9a2011-08-28 00:38:13 -0400815 if (i < argNames.count() - 1)
Zack Rusin5e277b02011-04-16 21:52:26 -0400816 richText += QLatin1String(", ");
Zack Rusin27cb2c42011-03-27 23:53:36 -0400817 }
818 richText += QLatin1String(")");
Zack Rusinead6aad2011-04-15 22:16:18 -0400819 if (m_returnValue.isValid()) {
Zack Rusin5e277b02011-04-16 21:52:26 -0400820 richText +=
821 QLatin1Literal(" = ") %
822 QLatin1Literal("<span style=\"color:#0000ff\">") %
823 apiVariantToString(m_returnValue) %
824 QLatin1Literal("</span>");
José Fonseca908f38d2011-03-31 10:09:14 +0100825 }
Zack Rusin27cb2c42011-03-27 23:53:36 -0400826
Zack Rusin53484b22011-04-16 11:56:19 -0400827 if (!m_staticText)
828 m_staticText = new QStaticText(richText);
Zack Rusin9af5bff2011-04-18 01:05:50 -0400829 else
830 m_staticText->setText(richText);
Zack Rusin27cb2c42011-03-27 23:53:36 -0400831 QTextOption opt;
832 opt.setWrapMode(QTextOption::NoWrap);
Zack Rusin53484b22011-04-16 11:56:19 -0400833 m_staticText->setTextOption(opt);
834 m_staticText->prepare();
Zack Rusin27cb2c42011-03-27 23:53:36 -0400835
Zack Rusin53484b22011-04-16 11:56:19 -0400836 return *m_staticText;
Zack Rusin27cb2c42011-03-27 23:53:36 -0400837}
838
839QString ApiTraceCall::toHtml() const
840{
841 if (!m_richText.isEmpty())
842 return m_richText;
843
Zack Rusinb53b1612011-04-19 01:33:58 -0400844 m_richText = QLatin1String("<div class=\"call\">");
845
Zack Rusinac4dd9a2011-08-28 00:38:13 -0400846 QUrl helpUrl = m_signature->helpUrl();
847 if (helpUrl.isEmpty()) {
Zack Rusinb53b1612011-04-19 01:33:58 -0400848 m_richText += QString::fromLatin1(
849 "%1) <span class=\"callName\">%2</span>(")
850 .arg(m_index)
Zack Rusinac4dd9a2011-08-28 00:38:13 -0400851 .arg(m_signature->name());
Zack Rusinc97fadc2011-04-07 15:16:59 -0400852 } else {
Zack Rusinb53b1612011-04-19 01:33:58 -0400853 m_richText += QString::fromLatin1(
854 "%1) <span class=\"callName\"><a href=\"%2\">%3</a></span>(")
Zack Rusinead6aad2011-04-15 22:16:18 -0400855 .arg(m_index)
Zack Rusinac4dd9a2011-08-28 00:38:13 -0400856 .arg(helpUrl.toString())
857 .arg(m_signature->name());
Zack Rusinc97fadc2011-04-07 15:16:59 -0400858 }
859
Zack Rusinf736a622011-08-28 22:19:46 -0400860 QVector<QVariant> argValues = arguments();
Zack Rusinac4dd9a2011-08-28 00:38:13 -0400861 QStringList argNames = m_signature->argNames();
862 for (int i = 0; i < argNames.count(); ++i) {
Zack Rusinb53b1612011-04-19 01:33:58 -0400863 m_richText +=
864 QLatin1String("<span class=\"arg-name\">") +
Zack Rusinac4dd9a2011-08-28 00:38:13 -0400865 argNames[i] +
Zack Rusinb53b1612011-04-19 01:33:58 -0400866 QLatin1String("</span>") +
867 QLatin1Literal(" = ") +
868 QLatin1Literal("<span class=\"arg-value\">") +
José Fonsecae8a1aa92011-04-21 09:13:23 +0100869 apiVariantToString(argValues[i], true) +
Zack Rusinb53b1612011-04-19 01:33:58 -0400870 QLatin1Literal("</span>");
Zack Rusinac4dd9a2011-08-28 00:38:13 -0400871 if (i < argNames.count() - 1)
Zack Rusin5e277b02011-04-16 21:52:26 -0400872 m_richText += QLatin1String(", ");
Zack Rusin18eade52011-03-26 14:23:35 -0400873 }
874 m_richText += QLatin1String(")");
875
Zack Rusinead6aad2011-04-15 22:16:18 -0400876 if (m_returnValue.isValid()) {
Zack Rusin5e277b02011-04-16 21:52:26 -0400877 m_richText +=
878 QLatin1String(" = ") +
879 QLatin1String("<span style=\"color:#0000ff\">") +
José Fonsecae8a1aa92011-04-21 09:13:23 +0100880 apiVariantToString(m_returnValue, true) +
Zack Rusin5e277b02011-04-16 21:52:26 -0400881 QLatin1String("</span>");
Zack Rusin18eade52011-03-26 14:23:35 -0400882 }
Zack Rusinb53b1612011-04-19 01:33:58 -0400883 m_richText += QLatin1String("</div>");
884
Zack Rusincc0b4912011-04-19 01:59:20 -0400885 if (hasError()) {
886 QString errorStr =
887 QString::fromLatin1(
888 "<div class=\"error\">%1</div>")
889 .arg(m_error);
890 m_richText += errorStr;
891 }
892
Zack Rusinb53b1612011-04-19 01:33:58 -0400893 m_richText =
894 QString::fromLatin1(
895 "<html><head><style type=\"text/css\" media=\"all\">"
896 "%1</style></head><body>%2</body></html>")
897 .arg(styleSheet)
898 .arg(m_richText);
Zack Rusin5e277b02011-04-16 21:52:26 -0400899 m_richText.squeeze();
Zack Rusinb53b1612011-04-19 01:33:58 -0400900
901 //qDebug()<<m_richText;
Zack Rusin18eade52011-03-26 14:23:35 -0400902 return m_richText;
903}
Zack Rusinba3c1bf2011-03-27 17:12:06 -0400904
Zack Rusindc792082011-08-27 23:29:19 -0400905QString ApiTraceCall::searchText() const
Zack Rusinba3c1bf2011-03-27 17:12:06 -0400906{
Zack Rusindc792082011-08-27 23:29:19 -0400907 if (!m_searchText.isEmpty())
908 return m_searchText;
Zack Rusinba3c1bf2011-03-27 17:12:06 -0400909
Zack Rusinf736a622011-08-28 22:19:46 -0400910 QVector<QVariant> argValues = arguments();
Zack Rusinac4dd9a2011-08-28 00:38:13 -0400911 m_searchText = m_signature->name() + QLatin1Literal("(");
912 QStringList argNames = m_signature->argNames();
913 for (int i = 0; i < argNames.count(); ++i) {
914 m_searchText += argNames[i] +
Zack Rusin5e277b02011-04-16 21:52:26 -0400915 QLatin1Literal(" = ") +
Zack Rusin9af5bff2011-04-18 01:05:50 -0400916 apiVariantToString(argValues[i]);
Zack Rusinac4dd9a2011-08-28 00:38:13 -0400917 if (i < argNames.count() - 1)
Zack Rusindc792082011-08-27 23:29:19 -0400918 m_searchText += QLatin1String(", ");
Zack Rusinba3c1bf2011-03-27 17:12:06 -0400919 }
Zack Rusindc792082011-08-27 23:29:19 -0400920 m_searchText += QLatin1String(")");
Zack Rusinba3c1bf2011-03-27 17:12:06 -0400921
Zack Rusinead6aad2011-04-15 22:16:18 -0400922 if (m_returnValue.isValid()) {
Zack Rusindc792082011-08-27 23:29:19 -0400923 m_searchText += QLatin1Literal(" = ") +
Zack Rusin5e277b02011-04-16 21:52:26 -0400924 apiVariantToString(m_returnValue);
Zack Rusinba3c1bf2011-03-27 17:12:06 -0400925 }
Zack Rusindc792082011-08-27 23:29:19 -0400926 m_searchText.squeeze();
927 return m_searchText;
Zack Rusinba3c1bf2011-03-27 17:12:06 -0400928}
Zack Rusinf6667d12011-03-30 11:03:37 -0400929
Zack Rusina1a3ad52011-08-27 19:19:18 -0400930int ApiTraceCall::numChildren() const
931{
932 return 0;
933}
934
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400935bool ApiTraceCall::contains(const QString &str,
936 Qt::CaseSensitivity sensitivity) const
937{
938 QString txt = searchText();
939 return txt.contains(str, sensitivity);
940}
941
942
Zack Rusinac4dd9a2011-08-28 00:38:13 -0400943ApiTraceFrame::ApiTraceFrame(ApiTrace *parentTrace)
Zack Rusina1a3ad52011-08-27 19:19:18 -0400944 : ApiTraceEvent(ApiTraceEvent::Frame),
Zack Rusinac4dd9a2011-08-28 00:38:13 -0400945 m_parentTrace(parentTrace),
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400946 m_binaryDataSize(0),
947 m_loaded(false),
Zack Rusin851d0b02011-09-14 22:04:07 -0400948 m_callsToLoad(0),
949 m_lastCallIndex(0)
Zack Rusina1a3ad52011-08-27 19:19:18 -0400950{
951}
952
Zack Rusinc1743432011-09-13 17:58:58 -0400953ApiTraceFrame::~ApiTraceFrame()
954{
955 qDeleteAll(m_calls);
956}
957
Zack Rusinf6667d12011-03-30 11:03:37 -0400958QStaticText ApiTraceFrame::staticText() const
959{
Zack Rusin53484b22011-04-16 11:56:19 -0400960 if (m_staticText && !m_staticText->text().isEmpty())
961 return *m_staticText;
Zack Rusinf6667d12011-03-30 11:03:37 -0400962
Zack Rusin45e094f2011-09-14 17:36:53 -0400963 QString richText = QObject::tr(
964 "<span style=\"font-weight:bold\">Frame %1</span>"
965 "&nbsp;&nbsp;&nbsp;"
966 "<span style=\"font-style:italic;font-size:small;font-weight:lighter;\"> "
967 "(%2 calls)</span>")
968 .arg(number)
969 .arg(m_loaded ? m_calls.count() : m_callsToLoad);
Zack Rusin9e292fc2011-04-26 23:03:42 -0400970
971 //mark the frame if it uploads more than a meg a frame
972 if (m_binaryDataSize > (1024*1024)) {
973 richText =
974 QObject::tr(
Zack Rusin45e094f2011-09-14 17:36:53 -0400975 "%1"
Zack Rusin9e292fc2011-04-26 23:03:42 -0400976 "<span style=\"font-style:italic;\">"
977 "&nbsp;&nbsp;&nbsp;&nbsp;(%2MB)</span>")
Zack Rusin45e094f2011-09-14 17:36:53 -0400978 .arg(richText)
Zack Rusin9e292fc2011-04-26 23:03:42 -0400979 .arg(double(m_binaryDataSize / (1024.*1024.)), 0, 'g', 2);
Zack Rusin9e292fc2011-04-26 23:03:42 -0400980 }
Zack Rusinf6667d12011-03-30 11:03:37 -0400981
Zack Rusin53484b22011-04-16 11:56:19 -0400982 if (!m_staticText)
983 m_staticText = new QStaticText(richText);
984
Zack Rusinf6667d12011-03-30 11:03:37 -0400985 QTextOption opt;
986 opt.setWrapMode(QTextOption::NoWrap);
Zack Rusin53484b22011-04-16 11:56:19 -0400987 m_staticText->setTextOption(opt);
988 m_staticText->prepare();
Zack Rusinf6667d12011-03-30 11:03:37 -0400989
Zack Rusin53484b22011-04-16 11:56:19 -0400990 return *m_staticText;
Zack Rusinf6667d12011-03-30 11:03:37 -0400991}
992
Zack Rusinf6667d12011-03-30 11:03:37 -0400993int ApiTraceFrame::numChildren() const
994{
Zack Rusin3176ebe2011-09-06 21:11:36 -0400995 return m_calls.count();
Zack Rusinf6667d12011-03-30 11:03:37 -0400996}
997
Zack Rusin7c1793e2011-04-16 23:14:25 -0400998ApiTrace * ApiTraceFrame::parentTrace() const
999{
1000 return m_parentTrace;
1001}
1002
Zack Rusin1d31b6c2011-04-26 22:30:25 -04001003void ApiTraceFrame::addCall(ApiTraceCall *call)
1004{
1005 m_calls.append(call);
Zack Rusin9e292fc2011-04-26 23:03:42 -04001006 if (call->hasBinaryData()) {
1007 QByteArray data =
1008 call->arguments()[call->binaryDataIndex()].toByteArray();
1009 m_binaryDataSize += data.size();
1010 }
Zack Rusin1d31b6c2011-04-26 22:30:25 -04001011}
1012
Zack Rusin4d0ef5d2011-08-28 22:05:31 -04001013QVector<ApiTraceCall*> ApiTraceFrame::calls() const
Zack Rusin1d31b6c2011-04-26 22:30:25 -04001014{
1015 return m_calls;
1016}
1017
1018ApiTraceCall * ApiTraceFrame::call(int idx) const
1019{
1020 return m_calls.value(idx);
1021}
1022
Zack Rusinda7579b2011-09-13 17:33:05 -04001023
1024ApiTraceCall * ApiTraceFrame::callWithIndex(int index) const
1025{
1026 QVector<ApiTraceCall*>::const_iterator itr;
1027 for (itr = m_calls.constBegin(); itr != m_calls.constEnd(); ++itr) {
1028 if ((*itr)->index() == index) {
1029 return *itr;
1030 }
1031 }
1032 return 0;
1033}
1034
Zack Rusin1d31b6c2011-04-26 22:30:25 -04001035int ApiTraceFrame::callIndex(ApiTraceCall *call) const
1036{
1037 return m_calls.indexOf(call);
1038}
1039
1040bool ApiTraceFrame::isEmpty() const
1041{
Zack Rusin3176ebe2011-09-06 21:11:36 -04001042 if (m_loaded) {
1043 return m_calls.isEmpty();
1044 } else {
1045 return m_callsToLoad == 0;
1046 }
Zack Rusin1d31b6c2011-04-26 22:30:25 -04001047}
1048
Zack Rusin9e292fc2011-04-26 23:03:42 -04001049int ApiTraceFrame::binaryDataSize() const
1050{
1051 return m_binaryDataSize;
1052}
Zack Rusin4d0ef5d2011-08-28 22:05:31 -04001053
1054void ApiTraceFrame::setCalls(const QVector<ApiTraceCall*> &calls,
1055 quint64 binaryDataSize)
1056{
1057 m_calls = calls;
1058 m_binaryDataSize = binaryDataSize;
Zack Rusin20b1f6d2011-09-06 11:50:07 -04001059 m_loaded = true;
Zack Rusin45e094f2011-09-14 17:36:53 -04001060 delete m_staticText;
1061 m_staticText = 0;
Zack Rusin20b1f6d2011-09-06 11:50:07 -04001062}
1063
Zack Rusin1a9f7af2011-09-18 19:40:47 -04001064bool ApiTraceFrame::isLoaded() const
Zack Rusin20b1f6d2011-09-06 11:50:07 -04001065{
1066 return m_loaded;
1067}
1068
1069void ApiTraceFrame::setLoaded(bool l)
1070{
1071 m_loaded = l;
1072}
1073
1074void ApiTraceFrame::setNumChildren(int num)
1075{
1076 m_callsToLoad = num;
Zack Rusin4d0ef5d2011-08-28 22:05:31 -04001077}
Zack Rusinebf971e2011-09-06 17:44:43 -04001078
1079void ApiTraceFrame::setParentTrace(ApiTrace *parent)
1080{
1081 m_parentTrace = parent;
1082}
Zack Rusin3176ebe2011-09-06 21:11:36 -04001083
1084int ApiTraceFrame::numChildrenToLoad() const
1085{
1086 return m_callsToLoad;
1087}
Zack Rusin8f98c3a2011-09-11 18:21:29 -04001088
1089ApiTraceCall *
1090ApiTraceFrame::findNextCall(ApiTraceCall *from,
1091 const QString &str,
1092 Qt::CaseSensitivity sensitivity) const
1093{
1094 Q_ASSERT(m_loaded);
1095
1096 int callIndex = 0;
1097
1098 if (from) {
1099 callIndex = m_calls.indexOf(from) + 1;
1100 }
1101
1102 for (int i = callIndex; i < m_calls.count(); ++i) {
1103 ApiTraceCall *call = m_calls[i];
1104 if (call->contains(str, sensitivity)) {
1105 return call;
1106 }
1107 }
1108 return 0;
1109}
1110
1111ApiTraceCall *
1112ApiTraceFrame::findPrevCall(ApiTraceCall *from,
1113 const QString &str,
1114 Qt::CaseSensitivity sensitivity) const
1115{
1116 Q_ASSERT(m_loaded);
1117
1118 int callIndex = m_calls.count() - 1;
1119
1120 if (from) {
1121 callIndex = m_calls.indexOf(from) - 1;
1122 }
1123
1124 for (int i = callIndex; i >= 0; --i) {
1125 ApiTraceCall *call = m_calls[i];
1126 if (call->contains(str, sensitivity)) {
1127 return call;
1128 }
1129 }
1130 return 0;
1131}
Zack Rusin851d0b02011-09-14 22:04:07 -04001132
1133void ApiTraceFrame::setLastCallIndex(unsigned index)
1134{
1135 m_lastCallIndex = index;
1136}
1137
1138unsigned ApiTraceFrame::lastCallIndex() const
1139{
1140 if (m_loaded && !m_calls.isEmpty()) {
1141 return m_calls.last()->index();
1142 } else {
1143 return m_lastCallIndex;
1144 }
1145}