diff --git a/src/plugins/cppeditor/cpphighlighter.cpp b/src/plugins/cppeditor/cpphighlighter.cpp index c105e2859d0..a413892fb51 100644 --- a/src/plugins/cppeditor/cpphighlighter.cpp +++ b/src/plugins/cppeditor/cpphighlighter.cpp @@ -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(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(); } } diff --git a/src/plugins/texteditor/basetextdocumentlayout.cpp b/src/plugins/texteditor/basetextdocumentlayout.cpp index f6357e9035d..d0d6fe04ba3 100644 --- a/src/plugins/texteditor/basetextdocumentlayout.cpp +++ b/src/plugins/texteditor/basetextdocumentlayout.cpp @@ -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(); + } +} diff --git a/src/plugins/texteditor/basetextdocumentlayout.h b/src/plugins/texteditor/basetextdocumentlayout.h index fb115bc3e4d..6930e5d0a78 100644 --- a/src/plugins/texteditor/basetextdocumentlayout.h +++ b/src/plugins/texteditor/basetextdocumentlayout.h @@ -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(block.userData()); } diff --git a/src/plugins/texteditor/syntaxhighlighter.cpp b/src/plugins/texteditor/syntaxhighlighter.cpp index f10b2037860..876433ea7b2 100644 --- a/src/plugins/texteditor/syntaxhighlighter.cpp +++ b/src/plugins/texteditor/syntaxhighlighter.cpp @@ -31,6 +31,7 @@ #include "syntaxhighlighter.h" #include "basetextdocument.h" +#include "basetextdocumentlayout.h" #include #include @@ -76,10 +77,12 @@ public: } void applyFormatChanges(int from, int charsRemoved, int charsAdded); + QVector 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(doc->documentLayout())); } }