]> git.cworth.org Git - apitrace/commitdiff
Implement find next for the on-demand-loaded files.
authorZack Rusin <zack@kde.org>
Sun, 11 Sep 2011 22:21:29 +0000 (18:21 -0400)
committerZack Rusin <zack@kde.org>
Mon, 12 Sep 2011 05:50:45 +0000 (01:50 -0400)
Find next now works. Find previous hasn't been implemented yet
but the entire infrastructure is there.

gui/apitrace.cpp
gui/apitrace.h
gui/apitracecall.cpp
gui/apitracecall.h
gui/main.cpp
gui/mainwindow.cpp
gui/mainwindow.h
gui/traceloader.cpp
gui/traceloader.h

index 958009b7e383ff6a8b3ccd0984586c4174d52ee2..bff1686a9a3076add8058fcad199a483b9b5e873 100644 (file)
@@ -19,10 +19,21 @@ ApiTrace::ApiTrace()
             m_loader, SLOT(loadFrame(ApiTraceFrame*)));
     connect(m_loader, SIGNAL(framesLoaded(const QList<ApiTraceFrame*>)),
             this, SLOT(addFrames(const QList<ApiTraceFrame*>)));
-    connect(m_loader, SIGNAL(frameLoaded(ApiTraceFrame*)),
-            this, SLOT(frameLoadFinished(ApiTraceFrame*)));
+    connect(m_loader,
+            SIGNAL(frameContentsLoaded(ApiTraceFrame*,QVector<ApiTraceCall*>,quint64)),
+            this,
+            SLOT(loaderFrameLoaded(ApiTraceFrame*,QVector<ApiTraceCall*>,quint64)));
     connect(m_loader, SIGNAL(finishedParsing()),
             this, SLOT(finishedParsing()));
+    connect(this, SIGNAL(loaderSearchNext(int,QString,Qt::CaseSensitivity)),
+            m_loader, SLOT(searchNext(int,QString,Qt::CaseSensitivity)));
+    connect(this, SIGNAL(loaderSearchPrev(int,QString,Qt::CaseSensitivity)),
+            m_loader, SLOT(searchPrev(int,QString,Qt::CaseSensitivity)));
+    connect(m_loader,
+            SIGNAL(searchResult(ApiTrace::SearchResult,ApiTraceCall*)),
+            this,
+            SLOT(loaderSearchResult(ApiTrace::SearchResult,ApiTraceCall*)));
+
 
     connect(m_loader, SIGNAL(startedParsing()),
             this, SIGNAL(startedLoadingTrace()));
@@ -306,7 +317,6 @@ bool ApiTrace::hasErrors() const
 void ApiTrace::loadFrame(ApiTraceFrame *frame)
 {
     Q_ASSERT(!frame->loaded());
-    emit beginLoadingFrame(frame, frame->numChildrenToLoad());
     emit requestFrame(frame);
 }
 
@@ -318,9 +328,92 @@ void ApiTrace::finishedParsing()
     }
 }
 
-void ApiTrace::frameLoadFinished(ApiTraceFrame *frame)
+void ApiTrace::loaderFrameLoaded(ApiTraceFrame *frame,
+                                 const QVector<ApiTraceCall*> &calls,
+                                 quint64 binaryDataSize)
 {
+    Q_ASSERT(frame->numChildrenToLoad() == calls.size());
+    emit beginLoadingFrame(frame, calls.size());
+    frame->setCalls(calls, binaryDataSize);
     emit endLoadingFrame(frame);
 }
 
+void ApiTrace::findNext(ApiTraceFrame *frame,
+                        ApiTraceCall *from,
+                        const QString &str,
+                        Qt::CaseSensitivity sensitivity)
+{
+    ApiTraceCall *foundCall = 0;
+    int frameIdx = m_frames.indexOf(frame);
+
+    if (frame->loaded()) {
+        foundCall = frame->findNextCall(from, str, sensitivity);
+        if (foundCall) {
+            emit findResult(SearchFound, foundCall);
+            return;
+        }
+
+        //if the frame is loaded we already searched it above
+        // so skip it
+        frameIdx += 1;
+    }
+
+    for (int i = frameIdx; i < m_frames.count(); ++i) {
+        ApiTraceFrame *frame = m_frames[i];
+        if (!frame->loaded()) {
+            emit loaderSearchNext(i, str, sensitivity);
+            return;
+        } else {
+            ApiTraceCall *call = frame->findNextCall(0, str, sensitivity);
+            if (call) {
+                emit findResult(SearchFound, call);
+            }
+        }
+    }
+    emit findResult(SearchWrapped, 0);
+}
+
+void ApiTrace::findPrev(ApiTraceFrame *frame,
+                        ApiTraceCall *from,
+                        const QString &str,
+                        Qt::CaseSensitivity sensitivity)
+{
+    ApiTraceCall *foundCall = 0;
+    int frameIdx = m_frames.indexOf(frame);
+
+    if (frame->loaded()) {
+        foundCall = frame->findPrevCall(from, str, sensitivity);
+        if (foundCall) {
+            emit findResult(SearchFound, foundCall);
+            return;
+        }
+
+        //if the frame is loaded we already searched it above
+        // so skip it
+        frameIdx -= 1;
+    }
+
+    for (int i = frameIdx; i <= 0; --i) {
+        ApiTraceFrame *frame = m_frames[i];
+        if (!frame->loaded()) {
+            emit loaderSearchPrev(i, str, sensitivity);
+            return;
+        } else {
+            ApiTraceCall *call = frame->findPrevCall(0, str, sensitivity);
+            if (call) {
+                emit findResult(SearchFound, call);
+            }
+        }
+    }
+    emit findResult(SearchWrapped, 0);
+}
+
+void ApiTrace::loaderSearchResult(ApiTrace::SearchResult result,
+                                  ApiTraceCall *call)
+{
+    //qDebug()<<"Search result = "<<result
+    //       <<", call is = "<<call;
+    emit findResult(result, call);
+}
+
 #include "apitrace.moc"
index d01e7a0cfd81f3770d4157823eca0de538e7495c..3edffef700d573c87a5b2386b860b834bc04fd3a 100644 (file)
@@ -20,6 +20,12 @@ public:
         FrameMarker_Finish,
         FrameMarker_Clear
     };
+    enum SearchResult {
+        SearchNotFound,
+        SearchFound,
+        SearchWrapped
+    };
+
     static bool isCallAFrameMarker(const ApiTraceCall *call,
                                    FrameMarker marker);
 public:
@@ -59,6 +65,15 @@ public slots:
     void setFrameMarker(FrameMarker marker);
     void save();
     void loadFrame(ApiTraceFrame *frame);
+    void findNext(ApiTraceFrame *frame,
+                  ApiTraceCall *call,
+                  const QString &str,
+                  Qt::CaseSensitivity sensitivity);
+    void findPrev(ApiTraceFrame *frame,
+                  ApiTraceCall *call,
+                  const QString &str,
+                  Qt::CaseSensitivity sensitivity);
+
 
 signals:
     void loadTrace(const QString &name);
@@ -71,6 +86,8 @@ signals:
     void changed(ApiTraceCall *call);
     void startedSaving();
     void saved();
+    void findResult(ApiTrace::SearchResult result,
+                    ApiTraceCall *call);
 
     void beginAddingFrames(int oldCount, int numAdded);
     void endAddingFrames();
@@ -78,11 +95,24 @@ signals:
     void beginLoadingFrame(ApiTraceFrame *frame, int numAdded);
     void endLoadingFrame(ApiTraceFrame *frame);
 
+
+signals:
+    void loaderSearchNext(int startFrame,
+                          const QString &str,
+                          Qt::CaseSensitivity sensitivity);
+    void loaderSearchPrev(int startFrame,
+                          const QString &str,
+                          Qt::CaseSensitivity sensitivity);
+
 private slots:
     void addFrames(const QList<ApiTraceFrame*> &frames);
     void slotSaved();
     void finishedParsing();
-    void frameLoadFinished(ApiTraceFrame *frame);
+    void loaderFrameLoaded(ApiTraceFrame *frame,
+                           const QVector<ApiTraceCall*> &calls,
+                           quint64 binaryDataSize);
+    void loaderSearchResult(ApiTrace::SearchResult result,
+                            ApiTraceCall *call);
 
 private:
     void detectFrames();
index 59250452e63f00f24417109d529183fc46647d82..b26514dd3464851e22b8eb020295e05b462b6dfa 100644 (file)
@@ -919,6 +919,14 @@ int ApiTraceCall::numChildren() const
     return 0;
 }
 
+bool ApiTraceCall::contains(const QString &str,
+                            Qt::CaseSensitivity sensitivity) const
+{
+    QString txt = searchText();
+    return txt.contains(str, sensitivity);
+}
+
+
 ApiTraceFrame::ApiTraceFrame(ApiTrace *parentTrace)
     : ApiTraceEvent(ApiTraceEvent::Frame),
       m_parentTrace(parentTrace),
@@ -1044,3 +1052,47 @@ int ApiTraceFrame::numChildrenToLoad() const
 {
     return m_callsToLoad;
 }
+
+ApiTraceCall *
+ApiTraceFrame::findNextCall(ApiTraceCall *from,
+                            const QString &str,
+                            Qt::CaseSensitivity sensitivity) const
+{
+    Q_ASSERT(m_loaded);
+
+    int callIndex = 0;
+
+    if (from) {
+        callIndex = m_calls.indexOf(from) + 1;
+    }
+
+    for (int i = callIndex; i < m_calls.count(); ++i) {
+        ApiTraceCall *call = m_calls[i];
+        if (call->contains(str, sensitivity)) {
+            return call;
+        }
+    }
+    return 0;
+}
+
+ApiTraceCall *
+ApiTraceFrame::findPrevCall(ApiTraceCall *from,
+                            const QString &str,
+                            Qt::CaseSensitivity sensitivity) const
+{
+    Q_ASSERT(m_loaded);
+
+    int callIndex = m_calls.count() - 1;
+
+    if (from) {
+        callIndex = m_calls.indexOf(from) - 1;
+    }
+
+    for (int i = callIndex; i >= 0; --i) {
+        ApiTraceCall *call = m_calls[i];
+        if (call->contains(str, sensitivity)) {
+            return call;
+        }
+    }
+    return 0;
+}
index ca4c354354aad8c2260ca1b30c9b75e3ee056315..adfa1b051d0cb289b8ac3b227effdd5554d65f98 100644 (file)
@@ -259,6 +259,9 @@ public:
     QVector<QVariant> editedValues() const;
     void revert();
 
+    bool contains(const QString &str,
+                  Qt::CaseSensitivity sensitivity) const;
+
     ApiTrace *parentTrace() const;
 
     QString toHtml() const;
@@ -306,6 +309,14 @@ public:
     void setCalls(const QVector<ApiTraceCall*> &calls,
                   quint64 binaryDataSize);
 
+    ApiTraceCall *findNextCall(ApiTraceCall *from,
+                               const QString &str,
+                               Qt::CaseSensitivity sensitivity) const;
+
+    ApiTraceCall *findPrevCall(ApiTraceCall *from,
+                               const QString &str,
+                               Qt::CaseSensitivity sensitivity) const;
+
     int binaryDataSize() const;
 
     bool loaded() const;
index 3f8cfa6b6bcb7b884e4c47ba27da0018dc9fb1b0..6043b750ded5a2b17d513f2e0e67e36e38b24843 100644 (file)
@@ -1,5 +1,6 @@
 #include "mainwindow.h"
 
+#include "apitrace.h"
 #include "apitracecall.h"
 
 #include <QApplication>
@@ -7,13 +8,20 @@
 #include <QVariant>
 
 Q_DECLARE_METATYPE(QList<ApiTraceFrame*>);
+Q_DECLARE_METATYPE(QVector<ApiTraceCall*>);
+Q_DECLARE_METATYPE(Qt::CaseSensitivity);
+Q_DECLARE_METATYPE(ApiTrace::SearchResult);
+
 
 int main(int argc, char **argv)
 {
     QApplication app(argc, argv);
 
     qRegisterMetaType<QList<ApiTraceFrame*> >();
+    qRegisterMetaType<QVector<ApiTraceCall*> >();
     qRegisterMetaType<ApiTraceState>();
+    qRegisterMetaType<Qt::CaseSensitivity>();
+    qRegisterMetaType<ApiTrace::SearchResult>();
     MainWindow window;
 
     window.show();
index e5f6d9b2a4b7852a71d375fac33055940e6cbf8c..9dc530dbf822385f31a8304fd69a8725a38770c1 100644 (file)
@@ -592,10 +592,10 @@ void MainWindow::showSelectedSurface()
     ImageViewer *viewer = new ImageViewer(this);
 
     QString title;
-    if (currentCall()) {
+    if (selectedCall()) {
         title = tr("QApiTrace - Surface at %1 (%2)")
-                .arg(currentCall()->name())
-                .arg(currentCall()->index());
+                .arg(selectedCall()->name())
+                .arg(selectedCall()->index());
     } else {
         title = tr("QApiTrace - Surface Viewer");
     }
@@ -692,6 +692,8 @@ void MainWindow::initConnections()
             this, SLOT(slotSaved()));
     connect(m_trace, SIGNAL(changed(ApiTraceCall*)),
             this, SLOT(slotTraceChanged(ApiTraceCall*)));
+    connect(m_trace, SIGNAL(findResult(ApiTrace::SearchResult,ApiTraceCall*)),
+            this, SLOT(slotSearchResult(ApiTrace::SearchResult,ApiTraceCall*)));
 
     connect(m_retracer, SIGNAL(finished(const QString&)),
             this, SLOT(replayFinished(const QString&)));
@@ -831,103 +833,31 @@ void MainWindow::slotSearch()
 void MainWindow::slotSearchNext(const QString &str,
                                 Qt::CaseSensitivity sensitivity)
 {
-    QModelIndex index = m_ui.callView->currentIndex();
-    ApiTraceEvent *event = 0;
-
-
-    if (!index.isValid()) {
-        index = m_proxyModel->index(0, 0, QModelIndex());
-        if (!index.isValid()) {
-            qDebug()<<"no currently valid index";
-            m_searchWidget->setFound(false);
-            return;
-        }
-    }
-
-    event = index.data(ApiTraceModel::EventRole).value<ApiTraceEvent*>();
-    ApiTraceCall *call = 0;
+    ApiTraceCall *call = currentCall();
+    ApiTraceFrame *frame = currentFrame();
 
-    if (event->type() == ApiTraceCall::Call)
-        call = static_cast<ApiTraceCall*>(event);
-    else {
-        Q_ASSERT(event->type() == ApiTraceCall::Frame);
-        ApiTraceFrame *frame = static_cast<ApiTraceFrame*>(event);
-        call = frame->call(0);
+    Q_ASSERT(call || frame);
+    if (!frame) {
+        frame = call->parentFrame();
     }
+    Q_ASSERT(frame);
 
-    if (!call) {
-        m_searchWidget->setFound(false);
-        return;
-    }
-    const QVector<ApiTraceCall*> &calls = m_trace->calls();
-    int callNum = calls.indexOf(call);
-
-    for (int i = callNum + 1; i < calls.count(); ++i) {
-        ApiTraceCall *testCall = calls[i];
-        QModelIndex index = m_proxyModel->indexForCall(testCall);
-        /* if it's not valid it means that the proxy model has already
-         * filtered it out */
-        if (index.isValid()) {
-            QString txt = testCall->searchText();
-            if (txt.contains(str, sensitivity)) {
-                m_ui.callView->setCurrentIndex(index);
-                m_searchWidget->setFound(true);
-                return;
-            }
-        }
-    }
-    m_searchWidget->setFound(false);
+    m_trace->findNext(frame, call, str, sensitivity);
 }
 
 void MainWindow::slotSearchPrev(const QString &str,
                                 Qt::CaseSensitivity sensitivity)
 {
-    QModelIndex index = m_ui.callView->currentIndex();
-    ApiTraceEvent *event = 0;
-
+    ApiTraceCall *call = currentCall();
+    ApiTraceFrame *frame = currentFrame();
 
-    if (!index.isValid()) {
-        index = m_proxyModel->index(0, 0, QModelIndex());
-        if (!index.isValid()) {
-            qDebug()<<"no currently valid index";
-            m_searchWidget->setFound(false);
-            return;
-        }
+    Q_ASSERT(call || frame);
+    if (!frame) {
+        frame = call->parentFrame();
     }
+    Q_ASSERT(frame);
 
-    event = index.data(ApiTraceModel::EventRole).value<ApiTraceEvent*>();
-    ApiTraceCall *call = 0;
-
-    if (event->type() == ApiTraceCall::Call)
-        call = static_cast<ApiTraceCall*>(event);
-    else {
-        Q_ASSERT(event->type() == ApiTraceCall::Frame);
-        ApiTraceFrame *frame = static_cast<ApiTraceFrame*>(event);
-        call = frame->call(0);
-    }
-
-    if (!call) {
-        m_searchWidget->setFound(false);
-        return;
-    }
-    const QVector<ApiTraceCall*> &calls = m_trace->calls();
-    int callNum = calls.indexOf(call);
-
-    for (int i = callNum - 1; i >= 0; --i) {
-        ApiTraceCall *testCall = calls[i];
-        QModelIndex index = m_proxyModel->indexForCall(testCall);
-        /* if it's not valid it means that the proxy model has already
-         * filtered it out */
-        if (index.isValid()) {
-            QString txt = testCall->searchText();
-            if (txt.contains(str, sensitivity)) {
-                m_ui.callView->setCurrentIndex(index);
-                m_searchWidget->setFound(true);
-                return;
-            }
-        }
-    }
-    m_searchWidget->setFound(false);
+    m_trace->findPrev(frame, call, str, sensitivity);
 }
 
 void MainWindow::fillState(bool nonDefaults)
@@ -1000,7 +930,7 @@ void MainWindow::slotSaved()
 
 void MainWindow::slotGoFrameStart()
 {
-    ApiTraceFrame *frame = currentFrame();
+    ApiTraceFrame *frame = selectedFrame();
     if (!frame || frame->isEmpty()) {
         return;
     }
@@ -1022,7 +952,7 @@ void MainWindow::slotGoFrameStart()
 
 void MainWindow::slotGoFrameEnd()
 {
-    ApiTraceFrame *frame = currentFrame();
+    ApiTraceFrame *frame = selectedFrame();
     if (!frame || frame->isEmpty()) {
         return;
     }
@@ -1041,7 +971,7 @@ void MainWindow::slotGoFrameEnd()
     } while (itr != calls.constBegin());
 }
 
-ApiTraceFrame * MainWindow::currentFrame() const
+ApiTraceFrame * MainWindow::selectedFrame() const
 {
     if (m_selectedEvent) {
         if (m_selectedEvent->type() == ApiTraceEvent::Frame) {
@@ -1099,7 +1029,7 @@ void MainWindow::slotErrorSelected(QTreeWidgetItem *current)
     }
 }
 
-ApiTraceCall * MainWindow::currentCall() const
+ApiTraceCall * MainWindow::selectedCall() const
 {
     if (m_selectedEvent &&
         m_selectedEvent->type() == ApiTraceEvent::Call) {
@@ -1120,11 +1050,11 @@ void MainWindow::saveSelectedSurface()
     QImage img = var.value<QImage>();
 
     QString imageIndex;
-    if (currentCall()) {
+    if (selectedCall()) {
         imageIndex = tr("_call_%1")
-                     .arg(currentCall()->index());
-    } else if (currentFrame()) {
-        ApiTraceCall *firstCall = currentFrame()->call(0);
+                     .arg(selectedCall()->index());
+    } else if (selectedFrame()) {
+        ApiTraceCall *firstCall = selectedFrame()->call(0);
         if (firstCall) {
             imageIndex = tr("_frame_%1")
                          .arg(firstCall->index());
@@ -1166,4 +1096,77 @@ void MainWindow::loadProgess(int percent)
     m_progressBar->setValue(percent);
 }
 
+void MainWindow::slotSearchResult(ApiTrace::SearchResult result,
+                                  ApiTraceCall *call)
+{
+    switch (result) {
+    case ApiTrace::SearchNotFound:
+        m_searchWidget->setFound(false);
+        break;
+    case ApiTrace::SearchFound: {
+        QModelIndex index = m_proxyModel->indexForCall(call);
+        m_ui.callView->setCurrentIndex(index);
+        m_searchWidget->setFound(true);
+    }
+        break;
+    case ApiTrace::SearchWrapped:
+        m_searchWidget->setFound(false);
+        break;
+    }
+}
+
+ApiTraceFrame * MainWindow::currentFrame() const
+{
+    QModelIndex index = m_ui.callView->currentIndex();
+    ApiTraceEvent *event = 0;
+
+    if (!index.isValid()) {
+        index = m_proxyModel->index(0, 0, QModelIndex());
+        if (!index.isValid()) {
+            qDebug()<<"no currently valid index";
+            return 0;
+        }
+    }
+
+    event = index.data(ApiTraceModel::EventRole).value<ApiTraceEvent*>();
+    Q_ASSERT(event);
+    if (!event) {
+        return 0;
+    }
+
+    ApiTraceFrame *frame = 0;
+    if (event->type() == ApiTraceCall::Frame) {
+        frame = static_cast<ApiTraceFrame*>(event);
+    }
+    return frame;
+}
+
+ApiTraceCall * MainWindow::currentCall() const
+{
+    QModelIndex index = m_ui.callView->currentIndex();
+    ApiTraceEvent *event = 0;
+
+    if (!index.isValid()) {
+        index = m_proxyModel->index(0, 0, QModelIndex());
+        if (!index.isValid()) {
+            qDebug()<<"no currently valid index";
+            return 0;
+        }
+    }
+
+    event = index.data(ApiTraceModel::EventRole).value<ApiTraceEvent*>();
+    Q_ASSERT(event);
+    if (!event) {
+        return 0;
+    }
+
+    ApiTraceCall *call = 0;
+    if (event->type() == ApiTraceCall::Call) {
+        call = static_cast<ApiTraceCall*>(event);
+    }
+
+    return call;
+
+}
+
 #include "mainwindow.moc"
index 00fe04b25ce698322e9294eee5e427e2f8f0ed1e..e5b19b44b14b68b90000a9f1e60ce1dff01756ac 100644 (file)
@@ -3,6 +3,8 @@
 
 #include "ui_mainwindow.h"
 
+#include "apitrace.h"
+
 #include <QMainWindow>
 #include <QProcess>
 
@@ -71,6 +73,8 @@ private slots:
     void slotTraceChanged(ApiTraceCall *call);
     void slotRetraceErrors(const QList<RetraceError> &errors);
     void slotErrorSelected(QTreeWidgetItem *current);
+    void slotSearchResult(ApiTrace::SearchResult result,
+                          ApiTraceCall *call);
 
 private:
     void initObjects();
@@ -78,9 +82,17 @@ private:
     void newTraceFile(const QString &fileName);
     void replayTrace(bool dumpState);
     void fillStateForFrame();
+
+    /* there's a difference between selected frame/call and
+     * current call/frame. the former implies actual selection
+     * the latter might be just a highlight, e.g. during searching
+     */
+    ApiTraceFrame *selectedFrame() const;
+    ApiTraceCall *selectedCall() const;
     ApiTraceFrame *currentFrame() const;
     ApiTraceCall *currentCall() const;
 
+
 private:
     Ui_MainWindow m_ui;
     ShadersSourceWidget *m_sourcesWidget;
index a6ffd2978709a11d61c0323b9e687e34421c1520..11847fff975b4ed5386df43ce41c191f9eb5142a 100644 (file)
@@ -56,49 +56,7 @@ void TraceLoader::loadTrace(const QString &filename)
 
 void TraceLoader::loadFrame(ApiTraceFrame *currentFrame)
 {
-    if (m_parser.supportsOffsets()) {
-        unsigned frameIdx = currentFrame->number;
-        int numOfCalls = numberOfCallsInFrame(frameIdx);
-
-        if (numOfCalls) {
-            quint64 binaryDataSize = 0;
-            QVector<ApiTraceCall*> calls(numOfCalls);
-            const FrameBookmark &frameBookmark = m_frameBookmarks[frameIdx];
-
-            m_parser.setBookmark(frameBookmark.start);
-
-            Trace::Call *call;
-            int parsedCalls = 0;
-            while ((call = m_parser.parse_call())) {
-                ApiTraceCall *apiCall =
-                        apiCallFromTraceCall(call, m_helpHash,
-                                             currentFrame, this);
-                calls[parsedCalls] = apiCall;
-                Q_ASSERT(calls[parsedCalls]);
-                if (apiCall->hasBinaryData()) {
-                    QByteArray data =
-                            apiCall->arguments()[
-                            apiCall->binaryDataIndex()].toByteArray();
-                    binaryDataSize += data.size();
-                }
-
-                ++parsedCalls;
-
-                delete call;
-
-                if (ApiTrace::isCallAFrameMarker(apiCall, m_frameMarker)) {
-                    break;
-                }
-
-            }
-            assert(parsedCalls == numOfCalls);
-            Q_ASSERT(parsedCalls == calls.size());
-            Q_ASSERT(parsedCalls == currentFrame->numChildrenToLoad());
-            calls.squeeze();
-            currentFrame->setCalls(calls, binaryDataSize);
-            emit frameLoaded(currentFrame);
-        }
-    }
+    fetchFrameContents(currentFrame);
 }
 
 void TraceLoader::setFrameMarker(ApiTrace::FrameMarker marker)
@@ -188,6 +146,7 @@ void TraceLoader::scanTrace()
             currentFrame->setNumChildren(numOfCalls);
             frames.append(currentFrame);
 
+            m_createdFrames.append(currentFrame);
             m_frameBookmarks[numOfFrames] = frameBookmark;
             ++numOfFrames;
 
@@ -211,6 +170,7 @@ void TraceLoader::scanTrace()
         currentFrame->setNumChildren(numOfCalls);
         frames.append(currentFrame);
 
+        m_createdFrames.append(currentFrame);
         m_frameBookmarks[numOfFrames] = frameBookmark;
         ++numOfFrames;
     }
@@ -312,4 +272,125 @@ void TraceLoader::addEnumSignature(unsigned id, ApiTraceEnumSignature *signature
     m_enumSignatures[id] = signature;
 }
 
+void TraceLoader::searchNext(int startFrame,
+                             const QString &str,
+                             Qt::CaseSensitivity sensitivity)
+{
+    Q_ASSERT(m_parser.supportsOffsets());
+    if (m_parser.supportsOffsets()) {
+        const FrameBookmark &frameBookmark = m_frameBookmarks[startFrame];
+        m_parser.setBookmark(frameBookmark.start);
+        Trace::Call *call = 0;
+        while ((call = m_parser.parse_call())) {
+
+            if (callContains(call, str, sensitivity)) {
+                unsigned frameIdx = callInFrame(call->no);
+                ApiTraceFrame *frame = m_createdFrames[frameIdx];
+                const QVector<ApiTraceCall*> calls =
+                        fetchFrameContents(frame);
+                for (int i = 0; i < calls.count(); ++i) {
+                    if (calls[i]->index() == call->no) {
+                        emit searchResult(ApiTrace::SearchFound, calls[i]);
+                        break;
+                    }
+                }
+                delete call;
+                return;
+            }
+
+            delete call;
+        }
+    }
+    emit searchResult(ApiTrace::SearchNotFound, 0);
+}
+
+void TraceLoader::searchPrev(int startFrame,
+                             const QString &str,
+                             Qt::CaseSensitivity sensitivity)
+{
+}
+
+int TraceLoader::callInFrame(int callIdx) const
+{
+    unsigned numCalls = 0;
+
+    for (int frameIdx = 0; frameIdx <= m_frameBookmarks.size(); ++frameIdx) {
+        const FrameBookmark &frameBookmark = m_frameBookmarks[frameIdx];
+        unsigned firstCall = numCalls;
+        unsigned endCall = numCalls + frameBookmark.numberOfCalls;
+        if (firstCall <= callIdx && endCall > callIdx) {
+            return frameIdx;
+        }
+        numCalls = endCall;
+    }
+    Q_ASSERT(!"call not in the trace");
+    return 0;
+}
+
+bool TraceLoader::callContains(Trace::Call *call,
+                               const QString &str,
+                               Qt::CaseSensitivity sensitivity)
+{
+    /*
+     * FIXME: do string comparison directly on Trace::Call
+     */
+    ApiTraceCall *apiCall = apiCallFromTraceCall(call, m_helpHash,
+                                                 0, this);
+    bool result = apiCall->contains(str, sensitivity);
+    delete apiCall;
+    return result;
+}
+
+QVector<ApiTraceCall*>
+TraceLoader::fetchFrameContents(ApiTraceFrame *currentFrame)
+{
+    Q_ASSERT(currentFrame);
+    if (m_parser.supportsOffsets()) {
+        unsigned frameIdx = currentFrame->number;
+        int numOfCalls = numberOfCallsInFrame(frameIdx);
+
+        if (numOfCalls) {
+            quint64 binaryDataSize = 0;
+            QVector<ApiTraceCall*> calls(numOfCalls);
+            const FrameBookmark &frameBookmark = m_frameBookmarks[frameIdx];
+
+            m_parser.setBookmark(frameBookmark.start);
+
+            Trace::Call *call;
+            int parsedCalls = 0;
+            while ((call = m_parser.parse_call())) {
+                ApiTraceCall *apiCall =
+                    apiCallFromTraceCall(call, m_helpHash,
+                                         currentFrame, this);
+                calls[parsedCalls] = apiCall;
+                Q_ASSERT(calls[parsedCalls]);
+                if (apiCall->hasBinaryData()) {
+                    QByteArray data =
+                        apiCall->arguments()[
+                            apiCall->binaryDataIndex()].toByteArray();
+                    binaryDataSize += data.size();
+                }
+
+                ++parsedCalls;
+
+                delete call;
+
+                if (ApiTrace::isCallAFrameMarker(apiCall, m_frameMarker)) {
+                    break;
+                }
+
+            }
+            assert(parsedCalls == numOfCalls);
+            Q_ASSERT(parsedCalls == calls.size());
+            calls.squeeze();
+
+            Q_ASSERT(parsedCalls == currentFrame->numChildrenToLoad());
+            emit frameContentsLoaded(currentFrame,
+                                     calls, binaryDataSize);
+            return calls;
+        }
+    }
+    return QVector<ApiTraceCall*>();
+}
+
 #include "traceloader.moc"
index 86b7526348eef15ed99c4f4468b96332b8d727a4..c83cf47bef611212898813cd5e6b6674268b9241 100644 (file)
@@ -28,6 +28,12 @@ public slots:
     void loadTrace(const QString &filename);
     void loadFrame(ApiTraceFrame *frame);
     void setFrameMarker(ApiTrace::FrameMarker marker);
+    void searchNext(int startFrame,
+                    const QString &str,
+                    Qt::CaseSensitivity sensitivity);
+    void searchPrev(int startFrame,
+                    const QString &str,
+                    Qt::CaseSensitivity sensitivity);
 
 signals:
     void startedParsing();
@@ -35,8 +41,11 @@ signals:
     void finishedParsing();
 
     void framesLoaded(const QList<ApiTraceFrame*> &frames);
-    void frameLoaded(ApiTraceFrame *frame);
+    void frameContentsLoaded(ApiTraceFrame *frame,
+                             const QVector<ApiTraceCall*> &calls,
+                             quint64 binaryDataSize);
 
+    void searchResult(ApiTrace::SearchResult result, ApiTraceCall *call);
 private:
     struct FrameBookmark {
         FrameBookmark()
@@ -58,6 +67,12 @@ private:
     void scanTrace();
     void parseTrace();
 
+    int callInFrame(int callIdx) const;
+    bool callContains(Trace::Call *call,
+                      const QString &str,
+                      Qt::CaseSensitivity sensitivity);
+     QVector<ApiTraceCall*> fetchFrameContents(ApiTraceFrame *frame);
+
 private:
     Trace::Parser m_parser;
     QString m_fileName;
@@ -65,6 +80,7 @@ private:
 
     typedef QMap<int, FrameBookmark> FrameBookmarks;
     FrameBookmarks m_frameBookmarks;
+    QList<ApiTraceFrame*> m_createdFrames;
 
     QHash<QString, QUrl> m_helpHash;