OSDN Git Service

Editors: Make sure folded blocks remain consistent
authorLeandro Melo <leandro.melo@nokia.com>
Fri, 12 Aug 2011 10:13:23 +0000 (12:13 +0200)
committerLeandro T. C. Melo <leandro.melo@nokia.com>
Mon, 15 Aug 2011 08:21:52 +0000 (10:21 +0200)
When folding indents change and a block becomes no longer
folded we need to update the user data. This patch tries
to handle general inconsistencies that might arise in such
situations. Notice however that there are stil other problems
to be addressed (including issues in Qt).

Task-number: QTCREATORBUG-5771
Change-Id: I38b869832159598d46cde00058308c218ca31f1a
Reviewed-on: http://codereview.qt.nokia.com/2908
Reviewed-by: Robert Löhning <robert.loehning@nokia.com>
Reviewed-by: Matthias Ettrich
src/plugins/cppeditor/cpphighlighter.cpp
src/plugins/texteditor/basetextdocumentlayout.cpp
src/plugins/texteditor/basetextdocumentlayout.h
src/plugins/texteditor/syntaxhighlighter.cpp

index c105e28..a413892 100644 (file)
@@ -239,13 +239,17 @@ void CppHighlighter::highlightBlock(const QString &text)
         int oldState = currentState & 0xff;
         int oldBraceDepth = currentState >> 8;
         if (oldState == tokenize.state() && oldBraceDepth != braceDepth) {
+            BaseTextDocumentLayout::FoldValidator foldValidor;
+            foldValidor.setup(qobject_cast<BaseTextDocumentLayout *>(document()->documentLayout()));
             int delta = braceDepth - oldBraceDepth;
             QTextBlock block = currentBlock().next();
             while (block.isValid() && block.userState() != -1) {
                 BaseTextDocumentLayout::changeBraceDepth(block, delta);
                 BaseTextDocumentLayout::changeFoldingIndent(block, delta);
+                foldValidor.process(block);
                 block = block.next();
             }
+            foldValidor.finalize();
         }
     }
 
index f6357e9..d0d6fe0 100644 (file)
@@ -575,3 +575,69 @@ QSizeF BaseTextDocumentLayout::documentSize() const
     size.setWidth(qMax((qreal)m_requiredWidth, size.width()));
     return size;
 }
+
+BaseTextDocumentLayout::FoldValidator::FoldValidator()
+    : m_layout(0)
+    , m_requestDocUpdate(false)
+    , m_insideFold(0)
+{}
+
+void BaseTextDocumentLayout::FoldValidator::setup(BaseTextDocumentLayout *layout)
+{
+    m_layout = layout;
+}
+
+void BaseTextDocumentLayout::FoldValidator::reset()
+{
+    m_insideFold = 0;
+    m_requestDocUpdate = false;
+}
+
+void BaseTextDocumentLayout::FoldValidator::process(QTextBlock block)
+{
+    if (!m_layout)
+        return;
+
+    const QTextBlock &previous = block.previous();
+    if (!previous.isValid())
+        return;
+
+    if ((BaseTextDocumentLayout::isFolded(previous)
+            && !BaseTextDocumentLayout::canFold(previous))
+            || (!BaseTextDocumentLayout::isFolded(previous)
+                && BaseTextDocumentLayout::canFold(previous)
+                && !block.isVisible())) {
+        BaseTextDocumentLayout::setFolded(previous, !BaseTextDocumentLayout::isFolded(previous));
+    }
+
+    if (BaseTextDocumentLayout::isFolded(previous) && !m_insideFold)
+        m_insideFold = BaseTextDocumentLayout::foldingIndent(block);
+
+    bool toggleVisibility = false;
+    if (m_insideFold) {
+        if (BaseTextDocumentLayout::foldingIndent(block) >= m_insideFold) {
+            if (block.isVisible())
+                toggleVisibility = true;
+        } else {
+            m_insideFold = 0;
+            if (!block.isVisible())
+                toggleVisibility = true;
+        }
+    } else if (!block.isVisible()) {
+        toggleVisibility = true;
+    }
+
+    if (toggleVisibility) {
+        block.setVisible(!block.isVisible());
+        block.setLineCount(block.isVisible() ? qMax(1, block.layout()->lineCount()) : 0);
+        m_requestDocUpdate = true;
+    }
+}
+
+void BaseTextDocumentLayout::FoldValidator::finalize()
+{
+    if (m_requestDocUpdate && m_layout) {
+        m_layout->requestUpdate();
+        m_layout->emitDocumentSizeChanged();
+    }
+}
index fb115bc..6930e5d 100644 (file)
@@ -174,6 +174,22 @@ public:
     static bool isFolded(const QTextBlock &block);
     static void setFolded(const QTextBlock &block, bool folded);
 
+    class TEXTEDITOR_EXPORT FoldValidator
+    {
+    public:
+        FoldValidator();
+
+        void setup(BaseTextDocumentLayout *layout);
+        void reset();
+        void process(QTextBlock block);
+        void finalize();
+
+    private:
+        BaseTextDocumentLayout *m_layout;
+        bool m_requestDocUpdate;
+        int m_insideFold;
+    };
+
     static TextBlockUserData *testUserData(const QTextBlock &block) {
         return static_cast<TextBlockUserData*>(block.userData());
     }
index f10b203..876433e 100644 (file)
@@ -31,6 +31,7 @@
 
 #include "syntaxhighlighter.h"
 #include "basetextdocument.h"
+#include "basetextdocumentlayout.h"
 
 #include <qtextdocument.h>
 #include <qtextlayout.h>
@@ -76,10 +77,12 @@ public:
     }
 
     void applyFormatChanges(int from, int charsRemoved, int charsAdded);
+
     QVector<QTextCharFormat> formatChanges;
     QTextBlock currentBlock;
     bool rehighlightPending;
     bool inReformatBlocks;
+    BaseTextDocumentLayout::FoldValidator foldValidator;
 };
 
 static bool adjustRange(QTextLayout::FormatRange &range, int from, int charsRemoved, int charsAdded) {
@@ -180,6 +183,8 @@ void SyntaxHighlighterPrivate::_q_reformatBlocks(int from, int charsRemoved, int
 
 void SyntaxHighlighterPrivate::reformatBlocks(int from, int charsRemoved, int charsAdded)
 {
+    foldValidator.reset();
+
     rehighlightPending = false;
 
     QTextBlock block = doc->findBlock(from);
@@ -206,6 +211,8 @@ void SyntaxHighlighterPrivate::reformatBlocks(int from, int charsRemoved, int ch
     }
 
     formatChanges.clear();
+
+    foldValidator.finalize();
 }
 
 void SyntaxHighlighterPrivate::reformatBlock(const QTextBlock &block, int from, int charsRemoved, int charsAdded)
@@ -220,6 +227,8 @@ void SyntaxHighlighterPrivate::reformatBlock(const QTextBlock &block, int from,
     q->highlightBlock(block.text());
     applyFormatChanges(from, charsRemoved, charsAdded);
 
+    foldValidator.process(currentBlock);
+
     currentBlock = QTextBlock();
 }
 
@@ -375,6 +384,7 @@ void SyntaxHighlighter::setDocument(QTextDocument *doc)
                 this, SLOT(_q_reformatBlocks(int,int,int)));
         d->rehighlightPending = true;
         QTimer::singleShot(0, this, SLOT(_q_delayedRehighlight()));
+        d->foldValidator.setup(qobject_cast<BaseTextDocumentLayout *>(doc->documentLayout()));
     }
 }