From 6f5cea2aaafb6475cf725413de04c5cc70d43888 Mon Sep 17 00:00:00 2001
From: ck <qt-info@nokia.com>
Date: Wed, 9 Sep 2009 17:11:00 +0200
Subject: [PATCH] Various improvements for BinEditor.

- Saving to file only takes modified data into account.
- Search functionality does not exhaust memory anymore.
- Searches can be canceled. This required updating the IFindSupport
  interface and all classes implementing it. No functional changes
  were done in those.

Reviewed-by: mae
---
 src/plugins/bineditor/bineditor.cpp           |  97 +++++++++++----
 src/plugins/bineditor/bineditor.h             |   6 +-
 src/plugins/bineditor/bineditorplugin.cpp     | 115 +++++++++++-------
 .../coreplugin/editormanager/ieditor.h        |   1 +
 src/plugins/debugger/debuggeragents.cpp       |   2 +-
 src/plugins/find/basetextfind.cpp             |   8 +-
 src/plugins/find/basetextfind.h               |   4 +-
 src/plugins/find/currentdocumentfind.cpp      |   8 +-
 src/plugins/find/currentdocumentfind.h        |   4 +-
 src/plugins/find/findtoolbar.cpp              |  25 +++-
 src/plugins/find/findtoolbar.h                |   5 +
 src/plugins/find/ifindsupport.h               |   6 +-
 src/plugins/help/helpfindsupport.cpp          |  26 ++--
 src/plugins/help/helpfindsupport.h            |   8 +-
 14 files changed, 209 insertions(+), 106 deletions(-)

diff --git a/src/plugins/bineditor/bineditor.cpp b/src/plugins/bineditor/bineditor.cpp
index 27629a130ea..453e0d2f5b5 100644
--- a/src/plugins/bineditor/bineditor.cpp
+++ b/src/plugins/bineditor/bineditor.cpp
@@ -33,6 +33,9 @@
 #include <texteditor/texteditorconstants.h>
 
 #include <QtCore/QByteArrayMatcher>
+#include <QtCore/QFile>
+#include <QtCore/QTemporaryFile>
+
 #include <QtGui/QApplication>
 #include <QtGui/QClipboard>
 #include <QtGui/QFontMetrics>
@@ -136,6 +139,8 @@ void BinEditor::addLazyData(quint64 block, const QByteArray &data)
     Q_ASSERT(data.size() == m_blockSize);
     const quint64 addr = block * m_blockSize;
     if (addr >= m_baseAddr && addr <= m_baseAddr + m_size - 1) {
+        if (m_lazyData.size() * m_blockSize >= 64 * 1024 * 1024)
+            m_lazyData.clear();
         const int translatedBlock = (addr - m_baseAddr) / m_blockSize;
         m_lazyData.insert(translatedBlock, data);
         m_lazyRequests.remove(translatedBlock);
@@ -149,7 +154,10 @@ bool BinEditor::requestDataAt(int pos, bool synchronous) const
         return true;
 
     int block = pos / m_blockSize;
-    QMap<int, QByteArray>::const_iterator it = m_lazyData.find(block);
+    QMap<int, QByteArray>::const_iterator it = m_modifiedData.find(block);
+    if (it != m_modifiedData.constEnd())
+        return true;
+    it = m_lazyData.find(block);
     if (it == m_lazyData.end()) {
         if (!m_lazyRequests.contains(block)) {
             m_lazyRequests.insert(block);
@@ -168,10 +176,8 @@ char BinEditor::dataAt(int pos) const
 {
     if (!m_inLazyMode)
         return m_data.at(pos);
-
     int block = pos / m_blockSize;
-    return m_lazyData.value(block, m_emptyBlock).at(pos - (block*m_blockSize));
-
+    return blockData(block).at(pos - (block*m_blockSize));
 }
 
 void BinEditor::changeDataAt(int pos, char c)
@@ -181,8 +187,17 @@ void BinEditor::changeDataAt(int pos, char c)
         return;
     }
     int block = pos / m_blockSize;
-    if (m_lazyData.contains(block))
-        m_lazyData[block][pos - (block*m_blockSize)] = c;
+    QMap<int, QByteArray>::iterator it = m_modifiedData.find(block);
+    if (it != m_modifiedData.end()) {
+        it.value()[pos - (block*m_blockSize)] = c;
+    } else {
+        it = m_lazyData.find(block);
+        if (it != m_lazyData.end()) {
+            QByteArray data = it.value();
+            data[pos - (block*m_blockSize)] = c;
+            m_modifiedData.insert(block, data);
+        }
+    }
 }
 
 QByteArray BinEditor::dataMid(int from, int length) const
@@ -195,7 +210,7 @@ QByteArray BinEditor::dataMid(int from, int length) const
 
     QByteArray data;
     do {
-        data += m_lazyData.value(block++, m_emptyBlock);
+        data += blockData(block++);
     } while (block * m_blockSize < end);
 
     return data.mid(from - ((from / m_blockSize) * m_blockSize), length);
@@ -209,7 +224,9 @@ QByteArray BinEditor::blockData(int block) const
             data.resize(m_blockSize);
         return data;
     }
-    return m_lazyData.value(block, m_emptyBlock);
+    QMap<int, QByteArray>::const_iterator it = m_modifiedData.find(block);
+    return it != m_modifiedData.constEnd()
+            ? it.value() : m_lazyData.value(block, m_emptyBlock);
 }
 
 
@@ -302,6 +319,7 @@ void BinEditor::setData(const QByteArray &data)
     m_inLazyMode = false;
     m_baseAddr = 0;
     m_lazyData.clear();
+    m_modifiedData.clear();
     m_lazyRequests.clear();
     m_data = data;
     m_size = data.size();
@@ -323,17 +341,45 @@ QByteArray BinEditor::data() const
     return m_data;
 }
 
-bool BinEditor::applyModifications(QByteArray &data) const
+bool BinEditor::save(const QString &oldFileName, const QString &newFileName)
 {
-    if (!m_inLazyMode) {
-        data = m_data;
-        return true;
-    }
-    if (data.size() != m_size)
-        return false;
-    for (QMap<int,QByteArray>::const_iterator it = m_lazyData.begin(); it != m_lazyData.end(); ++it) {
-        ::memcpy(data.data() + m_baseAddr + it.key() * m_blockSize, it->constData(), m_blockSize);
+    if (m_inLazyMode) {
+        if (oldFileName != newFileName) {
+            QString tmpName;
+            {
+                QTemporaryFile tmp;
+                if (!tmp.open())
+                    return false;
+                tmpName = tmp.fileName();
+            }
+            if (!QFile::copy(oldFileName, tmpName))
+                return false;
+            if (QFile::exists(newFileName) && !QFile::remove(newFileName))
+                return false;
+            if (!QFile::rename(tmpName, newFileName))
+                return false;
+        }
+        QFile output(newFileName);
+        if (!output.open(QIODevice::ReadWrite)) // QtBug: WriteOnly truncates.
+            return false;
+        const qint64 size = output.size();
+        for (QMap<int, QByteArray>::const_iterator it = m_modifiedData.constBegin();
+            it != m_modifiedData.constEnd(); ++it) {
+            if (!output.seek(it.key() * m_blockSize))
+                return false;
+            if (output.write(it.value()) < m_blockSize)
+                return false;
+        }
+        if (size % m_blockSize != 0 && !output.resize(size))
+            return false;
+    } else {
+        QFile output(newFileName);
+        if (!output.open(QIODevice::WriteOnly | QIODevice::Truncate))
+            return false;
+        if (output.write(m_data) < m_size)
+            return false;
     }
+    setModified(false);
     return true;
 }
 
@@ -345,6 +391,7 @@ void BinEditor::setLazyData(quint64 startAddr, int range, int blockSize)
     m_emptyBlock = QByteArray(blockSize, '\0');
     m_data.clear();
     m_lazyData.clear();
+    m_modifiedData.clear();
     m_lazyRequests.clear();
 
     // In lazy mode, users can edit data in the range
@@ -485,8 +532,9 @@ int BinEditor::dataIndexOf(const QByteArray &pattern, int from, bool caseSensiti
     QByteArrayMatcher matcher(pattern);
 
     int block = from / m_blockSize;
-
-    while (from < m_size) {
+    const int end =
+        qMin<qint64>(static_cast<qint64>(from) + SearchStride, m_size);
+    while (from < end) {
         if (!requestDataAt(block * m_blockSize, true))
             return -1;
         QByteArray data = blockData(block);
@@ -502,7 +550,7 @@ int BinEditor::dataIndexOf(const QByteArray &pattern, int from, bool caseSensiti
         ++block;
         from = block * m_blockSize - trailing;
     }
-    return -1;
+    return end == m_size ? -1 : -2;
 }
 
 int BinEditor::dataLastIndexOf(const QByteArray &pattern, int from, bool caseSensitive) const
@@ -519,8 +567,8 @@ int BinEditor::dataLastIndexOf(const QByteArray &pattern, int from, bool caseSen
     char *b = buffer.data();
 
     int block = from / m_blockSize;
-
-    while (from > 0) {
+    const int lowerBound = qMax(0, from - SearchStride);
+    while (from > lowerBound) {
         if (!requestDataAt(block * m_blockSize, true))
             return -1;
         QByteArray data = blockData(block);
@@ -536,7 +584,7 @@ int BinEditor::dataLastIndexOf(const QByteArray &pattern, int from, bool caseSen
         --block;
         from = block * m_blockSize + (m_blockSize-1) + trailing;
     }
-    return -1;
+    return lowerBound == 0 ? -1 : -2;
 }
 
 
@@ -564,7 +612,8 @@ int BinEditor::find(const QByteArray &pattern_arg, int from,
                    : dataIndexOf(hexPattern, from);
     }
 
-    int pos = (found >= 0 && (foundHex < 0 || found < foundHex)) ? found : foundHex;
+    int pos = foundHex == -1 || (found >= 0 && (foundHex == -2 || found < foundHex))
+              ? found : foundHex;
 
     if (pos >= m_size)
         pos = -1;
diff --git a/src/plugins/bineditor/bineditor.h b/src/plugins/bineditor/bineditor.h
index dc14fd7e608..4b7aa1653ff 100644
--- a/src/plugins/bineditor/bineditor.h
+++ b/src/plugins/bineditor/bineditor.h
@@ -31,8 +31,10 @@
 #define BINEDITOR_H
 
 #include <QtCore/QBasicTimer>
+#include <QtCore/QMap>
 #include <QtCore/QSet>
 #include <QtCore/QStack>
+#include <QtCore/QString>
 
 #include <QtGui/QAbstractScrollArea>
 #include <QtGui/QTextDocument>
@@ -67,7 +69,7 @@ public:
     Q_INVOKABLE void setLazyData(quint64 startAddr, int range, int blockSize = 4096);
     inline int lazyDataBlockSize() const { return m_blockSize; }
     Q_INVOKABLE void addLazyData(quint64 block, const QByteArray &data);
-    bool applyModifications(QByteArray &data) const;
+    bool save(const QString &oldFileName, const QString &newFileName);
 
     void zoomIn(int range = 1);
     void zoomOut(int range = 1);
@@ -109,6 +111,7 @@ public:
 
     QString addressString(quint64 address);
 
+    static const int SearchStride = 1024 * 1024;
 
 public Q_SLOTS:
     void setFontSettings(const TextEditor::FontSettings &fs);
@@ -143,6 +146,7 @@ private:
     QByteArray m_data;
     QMap <int, QByteArray> m_lazyData;
     int m_blockSize;
+    QMap <int, QByteArray> m_modifiedData;
     mutable QSet<int> m_lazyRequests;
     QByteArray m_emptyBlock;
     QByteArray m_lowerBlock;
diff --git a/src/plugins/bineditor/bineditorplugin.cpp b/src/plugins/bineditor/bineditorplugin.cpp
index 2d0f2054de4..9782b9bb6d4 100644
--- a/src/plugins/bineditor/bineditorplugin.cpp
+++ b/src/plugins/bineditor/bineditorplugin.cpp
@@ -61,7 +61,11 @@ class BinEditorFind : public Find::IFindSupport
 {
     Q_OBJECT
 public:
-    BinEditorFind(BinEditor *editor) { m_editor = editor; m_incrementalStartPos = -1; }
+    BinEditorFind(BinEditor *editor)
+    {
+        m_editor = editor;
+        m_incrementalStartPos = m_contPos = -1;
+    }
     ~BinEditorFind() {}
 
     bool supportsReplace() const { return false; }
@@ -70,7 +74,11 @@ public:
         return IFindSupport::FindBackward | IFindSupport::FindCaseSensitively;
     }
 
-    void resetIncrementalSearch() { m_incrementalStartPos = -1; }
+    void resetIncrementalSearch()
+    {
+        m_incrementalStartPos = m_contPos = -1;
+    }
+
     void clearResults() { m_editor->highlightSearchResults(QByteArray()); }
     QString currentFindString() const { return QString(); }
     QString completedFindString() const { return QString(); }
@@ -82,41 +90,68 @@ public:
             return pos;
         }
 
-        int found = m_editor->find(pattern, pos, Find::IFindSupport::textDocumentFlagsForFindFlags(findFlags));
-        if (found < 0)
-            found = m_editor->find(pattern,
-                                   (findFlags & Find::IFindSupport::FindBackward)?m_editor->dataSize()-1:0,
-                                   Find::IFindSupport::textDocumentFlagsForFindFlags(findFlags));
-        return found;
+        return m_editor->find(pattern, pos, Find::IFindSupport::textDocumentFlagsForFindFlags(findFlags));
     }
 
-    bool findIncremental(const QString &txt, Find::IFindSupport::FindFlags findFlags) {
+    Result findIncremental(const QString &txt, Find::IFindSupport::FindFlags findFlags) {
         QByteArray pattern = txt.toLatin1();
+        if (pattern != m_lastPattern)
+            resetIncrementalSearch(); // Because we don't search for nibbles.
+        m_lastPattern = pattern;
         if (m_incrementalStartPos < 0)
             m_incrementalStartPos = m_editor->selectionStart();
-        int pos = m_incrementalStartPos;
+        if (m_contPos == -1)
+            m_contPos = m_incrementalStartPos;
         findFlags &= ~Find::IFindSupport::FindBackward;
-        int found =  find(pattern, pos, findFlags);
-        if (found >= 0)
+        int found = find(pattern, m_contPos, findFlags);
+        Result result;
+        if (found >= 0) {
+            result = Found;
             m_editor->highlightSearchResults(pattern, Find::IFindSupport::textDocumentFlagsForFindFlags(findFlags));
-        else
-            m_editor->highlightSearchResults(QByteArray(), 0);
-        return found >= 0;
+            m_contPos = -1;
+        } else {
+            if (found == -2) {
+                result = NotYetFound;
+                m_contPos +=
+                        findFlags & Find::IFindSupport::FindBackward
+                        ? -BinEditor::SearchStride : BinEditor::SearchStride;
+            } else {
+                result = NotFound;
+                m_contPos = -1;
+                m_editor->highlightSearchResults(QByteArray(), 0);
+            }
+        }
+        return result;
     }
 
-    bool findStep(const QString &txt, Find::IFindSupport::FindFlags findFlags) {
+    Result findStep(const QString &txt, Find::IFindSupport::FindFlags findFlags) {
         QByteArray pattern = txt.toLatin1();
         bool wasReset = (m_incrementalStartPos < 0);
-        int pos = m_editor->cursorPosition();
-        if (findFlags & Find::IFindSupport::FindBackward)
-            pos = m_editor->selectionStart()-1;
-        int found = find(pattern, pos, findFlags);
-        if (found)
+        if (m_contPos == -1) {
+            m_contPos = m_editor->cursorPosition();
+            if (findFlags & Find::IFindSupport::FindBackward)
+                m_contPos = m_editor->selectionStart()-1;
+        }
+        int found = find(pattern, m_contPos, findFlags);
+        Result result;
+        if (found >= 0) {
+            result = Found;
             m_incrementalStartPos = found;
-        if (wasReset && found >= 0)
-            m_editor->highlightSearchResults(pattern, Find::IFindSupport::textDocumentFlagsForFindFlags(findFlags));
-        return found >= 0;
+            m_contPos = -1;
+            if (wasReset)
+                m_editor->highlightSearchResults(pattern, Find::IFindSupport::textDocumentFlagsForFindFlags(findFlags));
+        } else if (found == -2) {
+            result = NotYetFound;
+            m_contPos += findFlags & Find::IFindSupport::FindBackward
+                         ? -BinEditor::SearchStride : BinEditor::SearchStride;
+        } else {
+            result = NotFound;
+            m_contPos = -1;
+        }
+
+        return result;
     }
+
     bool replaceStep(const QString &, const QString &,
                      Find::IFindSupport::FindFlags) { return false;}
     int replaceAll(const QString &, const QString &,
@@ -125,6 +160,8 @@ public:
 private:
     BinEditor *m_editor;
     int m_incrementalStartPos;
+    int m_contPos; // Only valid if last result was NotYetFound.
+    QByteArray m_lastPattern;
 };
 
 
@@ -144,42 +181,26 @@ public:
     virtual QString mimeType() const { return m_mimeType; }
 
     bool save(const QString &fileName = QString()) {
-        QFile file(fileName);
-
-        QByteArray data;
-        if (m_editor->inLazyMode()) {
-            QFile read(m_fileName);
-            if (!read.open(QIODevice::ReadOnly))
-                return false;
-            data = read.readAll();
-            read.close();
-            if (!m_editor->applyModifications(data))
-                return false;
-        } else {
-            data = m_editor->data();
-        }
-        if (file.open(QIODevice::WriteOnly)) {
-            file.write(data);
-            file.close();
-            m_editor->setModified(false);
-            m_editor->editorInterface()->
-                    setDisplayName(QFileInfo(fileName).fileName());
+        if (m_editor->save(m_fileName, fileName)) {
             m_fileName = fileName;
+            m_editor->editorInterface()->
+                setDisplayName(QFileInfo(fileName).fileName());
             emit changed();
             return true;
+        } else {
+            return false;
         }
-        return false;
     }
 
     bool open(const QString &fileName) {
         QFile file(fileName);
         if (file.open(QIODevice::ReadOnly)) {
             m_fileName = fileName;
-            if (file.isSequential() && file.size() <= INT_MAX) {
+            if (file.isSequential() && file.size() <= 64 * 1024 * 1024) {
                 m_editor->setData(file.readAll());
             } else {
                 m_editor->setLazyData(0, qMin(file.size(),
-                                              static_cast<qint64>(INT_MAX)));
+                                              static_cast<qint64>(INT_MAX-16)));
                 m_editor->editorInterface()->
                         setDisplayName(QFileInfo(fileName).fileName());
             }
diff --git a/src/plugins/coreplugin/editormanager/ieditor.h b/src/plugins/coreplugin/editormanager/ieditor.h
index 56c4e6fbc6d..5248b298a70 100644
--- a/src/plugins/coreplugin/editormanager/ieditor.h
+++ b/src/plugins/coreplugin/editormanager/ieditor.h
@@ -40,6 +40,7 @@ class CORE_EXPORT IEditor : public IContext
 {
     Q_OBJECT
 public:
+
     IEditor(QObject *parent = 0) : IContext(parent) {}
     virtual ~IEditor() {}
 
diff --git a/src/plugins/debugger/debuggeragents.cpp b/src/plugins/debugger/debuggeragents.cpp
index 2b41b39394c..ede60b4c7e0 100644
--- a/src/plugins/debugger/debuggeragents.cpp
+++ b/src/plugins/debugger/debuggeragents.cpp
@@ -95,7 +95,7 @@ void MemoryViewAgent::init(quint64 addr)
         this, SLOT(fetchLazyData(quint64,bool)));
     editorManager->activateEditor(m_editor);
     QMetaObject::invokeMethod(m_editor->widget(), "setLazyData",
-        Q_ARG(quint64, addr), Q_ARG(int, INT_MAX), Q_ARG(int, BinBlockSize));
+        Q_ARG(quint64, addr), Q_ARG(int, 1024 * 1024), Q_ARG(int, BinBlockSize));
 }
 
 void MemoryViewAgent::fetchLazyData(quint64 block, bool sync)
diff --git a/src/plugins/find/basetextfind.cpp b/src/plugins/find/basetextfind.cpp
index 89ec9ccdb3f..5fb4a33d565 100644
--- a/src/plugins/find/basetextfind.cpp
+++ b/src/plugins/find/basetextfind.cpp
@@ -125,7 +125,7 @@ QString BaseTextFind::completedFindString() const
     return cursor.selectedText();
 }
 
-bool BaseTextFind::findIncremental(const QString &txt, IFindSupport::FindFlags findFlags)
+IFindSupport::Result BaseTextFind::findIncremental(const QString &txt, IFindSupport::FindFlags findFlags)
 {
     QTextCursor cursor = textCursor();
     if (m_incrementalStartPos < 0)
@@ -137,15 +137,15 @@ bool BaseTextFind::findIncremental(const QString &txt, IFindSupport::FindFlags f
         emit highlightAll(txt, findFlags);
     else
         emit highlightAll(QString(), 0);
-    return found;
+    return found ? Found : NotFound;
 }
 
-bool BaseTextFind::findStep(const QString &txt, IFindSupport::FindFlags findFlags)
+IFindSupport::Result BaseTextFind::findStep(const QString &txt, IFindSupport::FindFlags findFlags)
 {
     bool found = find(txt, findFlags, textCursor());
     if (found)
         m_incrementalStartPos = textCursor().selectionStart();
-    return found;
+    return found ? Found : NotFound;
 }
 
 namespace {
diff --git a/src/plugins/find/basetextfind.h b/src/plugins/find/basetextfind.h
index ec4cc0b344d..97aca8f4f6c 100644
--- a/src/plugins/find/basetextfind.h
+++ b/src/plugins/find/basetextfind.h
@@ -53,8 +53,8 @@ public:
     QString currentFindString() const;
     QString completedFindString() const;
 
-    bool findIncremental(const QString &txt, IFindSupport::FindFlags findFlags);
-    bool findStep(const QString &txt, IFindSupport::FindFlags findFlags);
+    Result findIncremental(const QString &txt, IFindSupport::FindFlags findFlags);
+    Result findStep(const QString &txt, IFindSupport::FindFlags findFlags);
     bool replaceStep(const QString &before, const QString &after,
         IFindSupport::FindFlags findFlags);
     int replaceAll(const QString &before, const QString &after,
diff --git a/src/plugins/find/currentdocumentfind.cpp b/src/plugins/find/currentdocumentfind.cpp
index 15f6a944b3b..16457382a2f 100644
--- a/src/plugins/find/currentdocumentfind.cpp
+++ b/src/plugins/find/currentdocumentfind.cpp
@@ -106,15 +106,15 @@ void CurrentDocumentFind::highlightAll(const QString &txt, IFindSupport::FindFla
     m_currentFind->highlightAll(txt, findFlags);
 }
 
-bool CurrentDocumentFind::findIncremental(const QString &txt, IFindSupport::FindFlags findFlags)
+IFindSupport::Result CurrentDocumentFind::findIncremental(const QString &txt, IFindSupport::FindFlags findFlags)
 {
-    QTC_ASSERT(m_currentFind, return false);
+    QTC_ASSERT(m_currentFind, return IFindSupport::NotFound);
     return m_currentFind->findIncremental(txt, findFlags);
 }
 
-bool CurrentDocumentFind::findStep(const QString &txt, IFindSupport::FindFlags findFlags)
+IFindSupport::Result CurrentDocumentFind::findStep(const QString &txt, IFindSupport::FindFlags findFlags)
 {
-    QTC_ASSERT(m_currentFind, return false);
+    QTC_ASSERT(m_currentFind, return IFindSupport::NotFound);
     return m_currentFind->findStep(txt, findFlags);
 }
 
diff --git a/src/plugins/find/currentdocumentfind.h b/src/plugins/find/currentdocumentfind.h
index bd0e19e022f..a3b9a7b362b 100644
--- a/src/plugins/find/currentdocumentfind.h
+++ b/src/plugins/find/currentdocumentfind.h
@@ -55,8 +55,8 @@ public:
     bool isEnabled() const;
     bool candidateIsEnabled() const;
     void highlightAll(const QString &txt, IFindSupport::FindFlags findFlags);
-    bool findIncremental(const QString &txt, IFindSupport::FindFlags findFlags);
-    bool findStep(const QString &txt, IFindSupport::FindFlags findFlags);
+    IFindSupport::Result findIncremental(const QString &txt, IFindSupport::FindFlags findFlags);
+    IFindSupport::Result findStep(const QString &txt, IFindSupport::FindFlags findFlags);
     bool replaceStep(const QString &before, const QString &after,
         IFindSupport::FindFlags findFlags);
     int replaceAll(const QString &before, const QString &after,
diff --git a/src/plugins/find/findtoolbar.cpp b/src/plugins/find/findtoolbar.cpp
index 44ecc6fb237..1c2c59ca503 100644
--- a/src/plugins/find/findtoolbar.cpp
+++ b/src/plugins/find/findtoolbar.cpp
@@ -69,7 +69,8 @@ FindToolBar::FindToolBar(FindPlugin *plugin, CurrentDocumentFind *currentDocumen
       m_replaceNextAction(0),
       m_casesensitiveIcon(":/find/images/casesensitively.png"),
       m_regexpIcon(":/find/images/regexp.png"),
-      m_wholewordsIcon(":/find/images/wholewords.png")
+      m_wholewordsIcon(":/find/images/wholewords.png"),
+      m_findIncrementalTimer(this), m_findStepTimer(this)
 {
     //setup ui
     m_ui.setupUi(this);
@@ -215,6 +216,12 @@ FindToolBar::FindToolBar(FindPlugin *plugin, CurrentDocumentFind *currentDocumen
     connect(m_currentDocumentFind, SIGNAL(candidateChanged()), this, SLOT(adaptToCandidate()));
     connect(m_currentDocumentFind, SIGNAL(changed()), this, SLOT(updateToolBar()));
     updateToolBar();
+
+    m_findIncrementalTimer.setSingleShot(true);
+    m_findStepTimer.setSingleShot(true);
+    connect(&m_findIncrementalTimer, SIGNAL(timeout()),
+            this, SLOT(invokeFindIncremental()));
+    connect(&m_findStepTimer, SIGNAL(timeout()), this, SLOT(invokeFindStep()));
 }
 
 FindToolBar::~FindToolBar()
@@ -373,17 +380,27 @@ void FindToolBar::selectFindText()
 
 void FindToolBar::invokeFindStep()
 {
+    m_findStepTimer.stop();
+    m_findIncrementalTimer.stop();
     if (m_currentDocumentFind->isEnabled()) {
         m_plugin->updateFindCompletion(getFindText());
-        m_currentDocumentFind->findStep(getFindText(), effectiveFindFlags());
+        IFindSupport::Result result =
+            m_currentDocumentFind->findStep(getFindText(), effectiveFindFlags());
+        if (result == IFindSupport::NotYetFound)
+            m_findStepTimer.start(50);
     }
 }
 
 void FindToolBar::invokeFindIncremental()
 {
+    m_findIncrementalTimer.stop();
+    m_findStepTimer.stop();
     if (m_currentDocumentFind->isEnabled()) {
         QString text = getFindText();
-        m_currentDocumentFind->findIncremental(text, effectiveFindFlags());
+        IFindSupport::Result result =
+            m_currentDocumentFind->findIncremental(text, effectiveFindFlags());
+        if (result == IFindSupport::NotYetFound)
+            m_findIncrementalTimer.start(50);
         if (text.isEmpty())
             m_currentDocumentFind->clearResults();
     }
@@ -421,6 +438,8 @@ void FindToolBar::invokeReplaceAll()
 
 void FindToolBar::invokeResetIncrementalSearch()
 {
+    m_findIncrementalTimer.stop();
+    m_findStepTimer.stop();
     if (m_currentDocumentFind->isEnabled())
         m_currentDocumentFind->resetIncrementalSearch();
 }
diff --git a/src/plugins/find/findtoolbar.h b/src/plugins/find/findtoolbar.h
index 14dbed88524..cbde5eceb52 100644
--- a/src/plugins/find/findtoolbar.h
+++ b/src/plugins/find/findtoolbar.h
@@ -37,6 +37,8 @@
 #include <coreplugin/findplaceholder.h>
 #include <utils/styledbar.h>
 
+#include <QtCore/QTimer>
+
 #include <QtGui/QStringListModel>
 #include <QtGui/QWidget>
 #include <QtGui/QLabel>
@@ -124,6 +126,9 @@ private:
     QPixmap m_casesensitiveIcon;
     QPixmap m_regexpIcon;
     QPixmap m_wholewordsIcon;
+
+    QTimer m_findIncrementalTimer;
+    QTimer m_findStepTimer;
 };
 
 } // namespace Internal
diff --git a/src/plugins/find/ifindsupport.h b/src/plugins/find/ifindsupport.h
index 0e2d5ef2dc7..35b5c7779ed 100644
--- a/src/plugins/find/ifindsupport.h
+++ b/src/plugins/find/ifindsupport.h
@@ -50,6 +50,8 @@ public:
     };
     Q_DECLARE_FLAGS(FindFlags, FindFlag)
 
+    enum Result { Found, NotFound, NotYetFound };
+
     IFindSupport() : QObject(0) {}
     virtual ~IFindSupport() {}
 
@@ -61,8 +63,8 @@ public:
     virtual QString completedFindString() const = 0;
 
     virtual void highlightAll(const QString &txt, FindFlags findFlags);
-    virtual bool findIncremental(const QString &txt, FindFlags findFlags) = 0;
-    virtual bool findStep(const QString &txt, FindFlags findFlags) = 0;
+    virtual Result findIncremental(const QString &txt, FindFlags findFlags) = 0;
+    virtual Result findStep(const QString &txt, FindFlags findFlags) = 0;
     virtual bool replaceStep(const QString &before, const QString &after,
         FindFlags findFlags) = 0;
     virtual int replaceAll(const QString &before, const QString &after,
diff --git a/src/plugins/help/helpfindsupport.cpp b/src/plugins/help/helpfindsupport.cpp
index d6086858f4b..bfb688db571 100644
--- a/src/plugins/help/helpfindsupport.cpp
+++ b/src/plugins/help/helpfindsupport.cpp
@@ -72,17 +72,19 @@ QString HelpFindSupport::completedFindString() const
     return QString();
 }
 
-bool HelpFindSupport::findIncremental(const QString &txt, Find::IFindSupport::FindFlags findFlags)
+Find::IFindSupport::Result HelpFindSupport::findIncremental(const QString &txt, Find::IFindSupport::FindFlags findFlags)
 {
-    QTC_ASSERT(m_centralWidget, return false);
+    QTC_ASSERT(m_centralWidget, return NotFound);
     findFlags &= ~Find::IFindSupport::FindBackward;
-    return m_centralWidget->find(txt, Find::IFindSupport::textDocumentFlagsForFindFlags(findFlags), true);
+    return m_centralWidget->find(txt, Find::IFindSupport::textDocumentFlagsForFindFlags(findFlags), true)
+            ? Found : NotFound;
 }
 
-bool HelpFindSupport::findStep(const QString &txt, Find::IFindSupport::FindFlags findFlags)
+Find::IFindSupport::Result HelpFindSupport::findStep(const QString &txt, Find::IFindSupport::FindFlags findFlags)
 {
-    QTC_ASSERT(m_centralWidget, return false);
-    return m_centralWidget->find(txt, Find::IFindSupport::textDocumentFlagsForFindFlags(findFlags), false);
+    QTC_ASSERT(m_centralWidget, return NotFound);
+    return m_centralWidget->find(txt, Find::IFindSupport::textDocumentFlagsForFindFlags(findFlags), false)
+            ? Found : NotFound;
 }
 
 HelpViewerFindSupport::HelpViewerFindSupport(HelpViewer *viewer)
@@ -106,17 +108,17 @@ QString HelpViewerFindSupport::currentFindString() const
 #endif
 }
 
-bool HelpViewerFindSupport::findIncremental(const QString &txt, Find::IFindSupport::FindFlags findFlags)
+Find::IFindSupport::Result HelpViewerFindSupport::findIncremental(const QString &txt, Find::IFindSupport::FindFlags findFlags)
 {
-    QTC_ASSERT(m_viewer, return false);
+    QTC_ASSERT(m_viewer, return NotFound);
     findFlags &= ~Find::IFindSupport::FindBackward;
-    return find(txt, findFlags, true);
+    return find(txt, findFlags, true) ? Found : NotFound;
 }
 
-bool HelpViewerFindSupport::findStep(const QString &txt, Find::IFindSupport::FindFlags findFlags)
+Find::IFindSupport::Result HelpViewerFindSupport::findStep(const QString &txt, Find::IFindSupport::FindFlags findFlags)
 {
-    QTC_ASSERT(m_viewer, return false);
-    return find(txt, findFlags, false);
+    QTC_ASSERT(m_viewer, return NotFound);
+    return find(txt, findFlags, false) ? Found : NotFound;
 }
 
 bool HelpViewerFindSupport::find(const QString &txt, Find::IFindSupport::FindFlags findFlags, bool incremental)
diff --git a/src/plugins/help/helpfindsupport.h b/src/plugins/help/helpfindsupport.h
index 94908d39165..1adfb1c9037 100644
--- a/src/plugins/help/helpfindsupport.h
+++ b/src/plugins/help/helpfindsupport.h
@@ -57,8 +57,8 @@ public:
     QString currentFindString() const;
     QString completedFindString() const;
 
-    bool findIncremental(const QString &txt, Find::IFindSupport::FindFlags findFlags);
-    bool findStep(const QString &txt, Find::IFindSupport::FindFlags findFlags);
+    Result findIncremental(const QString &txt, Find::IFindSupport::FindFlags findFlags);
+    Result findStep(const QString &txt, Find::IFindSupport::FindFlags findFlags);
     bool replaceStep(const QString &, const QString &,
         Find::IFindSupport::FindFlags ) { return false; }
     int replaceAll(const QString &, const QString &,
@@ -84,8 +84,8 @@ public:
     QString currentFindString() const;
     QString completedFindString() const { return QString(); }
 
-    bool findIncremental(const QString &txt, Find::IFindSupport::FindFlags findFlags);
-    bool findStep(const QString &txt, Find::IFindSupport::FindFlags findFlags);
+    Result findIncremental(const QString &txt, Find::IFindSupport::FindFlags findFlags);
+    Result findStep(const QString &txt, Find::IFindSupport::FindFlags findFlags);
     bool replaceStep(const QString &, const QString &,
         Find::IFindSupport::FindFlags ) { return false; }
     int replaceAll(const QString &, const QString &,
-- 
GitLab