C++ Detach the CppEditor from code-model internals.

- Moved document update handling into CppTools.
- Moved semantic info calculation into CppTools.
- Moved semantic highlighting into CppTools.

Change-Id: I253861bf074a64b1f657f7a4a8e6583871b5285f
Reviewed-by: Nikolai Kosjar <nikolai.kosjar@digia.com>
This commit is contained in:
Erik Verbruggen
2013-04-17 10:58:20 +02:00
committed by Nikolai Kosjar
parent e8d59fb76f
commit 0c27b27658
11 changed files with 641 additions and 640 deletions

View File

@@ -30,63 +30,154 @@
#ifndef CPPTOOLSEDITORSUPPORT_H
#define CPPTOOLSEDITORSUPPORT_H
#include "cpphighlightingsupport.h"
#include "cppmodelmanager.h"
#include "cppsemanticinfo.h"
#include <cplusplus/CppDocument.h>
#include <QFuture>
#include <QObject>
#include <QPointer>
#include <QFuture>
QT_BEGIN_NAMESPACE
class QTimer;
QT_END_NAMESPACE
#include <QTimer>
namespace CPlusPlus { class AST; }
namespace TextEditor {
class ITextEditor;
class BaseTextEditor;
class ITextMark;
} // namespace TextEditor
namespace CppTools {
namespace Internal {
class CppModelManager;
class CppEditorSupport: public QObject
/**
* \brief The CppEditorSupport class oversees the actions that happen when a C++ text editor updates
* its document.
*
* The following steps are taken:
* 1. the text editor fires a contentsChanged() signal that triggers updateDocument
* 2. update document will start a timer, or reset the timer if it was already running. This way
* subsequent updates (e.g. keypresses) get bunched together instead of running the subsequent
* actions for every key press
* 3. when the timer from step 2 fires, updateDocumentNow() is triggered. That tells the
* model-manager to update the CPlusPlus::Document by re-indexing it.
* 4. when the model-manager finishes, it fires a documentUpdated(CPlusPlus::Document::Ptr) signal,
* that is connected to onDocumentUpdated(CPlusPlus::Document::Ptr), which does 4 things:
* a) updates the ifdeffed-out blocks in the EditorUpdate
* b) calls setExtraDiagnostics with the diagnostics from the parser, which in turn calls
* onDiagnosticsChanged on the UI thread, and that schedules an editor update timer. When this
* timer fires, updateEditorNow() is called, which will apply the updates to the editor.
* c) a semantic-info recalculation is started in a future
* d) the documentUpdated() signal is emitted, which can be used by a widget to do things
* 5. semantic-info calculation from 4c is done by a future that calls recalculateSemanticInfoNow(),
* which emits semanticInfoUpdated() when it is finished. Editors can also listen in on this
* signal to do things like highlighting the local usages.
* 6. the semanticInfoUpdated() is connected to the startHighlighting() slot, which will start
* another future for doing the semantic highlighting. The highlighterStarted signal is emitted,
* with the highlighting future as a parameter, so editors can hook it up to a QFutureWatcher
* and get notifications.
*
* Both the semantic info calculation and the highlighting calculation will cancel an already running
* future. They will also check that the result of a previous step is not already outdated, meaning
* that they check the revision of the editor document to see if a user changed the document while
* the calculation was running.
*/
class CPPTOOLS_EXPORT CppEditorSupport: public QObject
{
Q_OBJECT
public:
CppEditorSupport(CppModelManager *modelManager);
CppEditorSupport(Internal::CppModelManager *modelManager, TextEditor::BaseTextEditor *textEditor);
virtual ~CppEditorSupport();
TextEditor::ITextEditor *textEditor() const;
void setTextEditor(TextEditor::ITextEditor *textEditor);
QString fileName() const;
int updateDocumentInterval() const;
void setUpdateDocumentInterval(int updateDocumentInterval);
QString contents();
QString contents() const;
unsigned editorRevision() const;
Q_SIGNALS:
void contentsChanged();
void setExtraDiagnostics(const QString &key,
const QList<CPlusPlus::Document::DiagnosticMessage> &messages);
private Q_SLOTS:
/// Retrieve the semantic info, which will get recalculated on the current
/// thread if it is outdate.
SemanticInfo recalculateSemanticInfo(bool emitSignalWhenFinished = true);
/// Recalculates the semantic info in a future, and will emit the semanticInfoUpdated() signal
/// when finished.
/// \param force do not check if the old semantic info is still valid
void recalculateSemanticInfoDetached(bool force = false);
signals:
void documentUpdated();
void diagnosticsChanged();
void semanticInfoUpdated(CppTools::SemanticInfo);
void highlighterStarted(QFuture<TextEditor::HighlightingResult>, unsigned revision);
private slots:
void updateDocument();
void updateDocumentNow();
private:
enum { UPDATE_DOCUMENT_DEFAULT_INTERVAL = 150 };
void onDocumentUpdated(CPlusPlus::Document::Ptr doc);
void startHighlighting();
CppModelManager *_modelManager;
QPointer<TextEditor::ITextEditor> _textEditor;
QTimer *_updateDocumentTimer;
int _updateDocumentInterval;
unsigned _revision;
QFuture<void> _documentParser;
QString _cachedContents;
void onDiagnosticsChanged();
void updateEditor();
void updateEditorNow();
private:
typedef TextEditor::BaseTextEditorWidget::BlockRange BlockRange;
struct EditorUpdates {
EditorUpdates()
: revision(-1)
{}
int revision;
QList<QTextEdit::ExtraSelection> selections;
QList<BlockRange> ifdefedOutBlocks;
};
enum {
UpdateDocumentDefaultInterval = 150,
UpdateEditorInterval = 300
};
private:
SemanticInfo::Source currentSource(bool force);
void recalculateSemanticInfoNow(const SemanticInfo::Source &source, bool emitSignalWhenFinished,
CPlusPlus::TopLevelDeclarationProcessor *processor = 0);
void recalculateSemanticInfoDetached_helper(QFutureInterface<void> &future,
SemanticInfo::Source source);
private:
Internal::CppModelManager *m_modelManager;
QPointer<TextEditor::BaseTextEditor> m_textEditor;
QTimer *m_updateDocumentTimer;
int m_updateDocumentInterval;
unsigned m_revision;
QFuture<void> m_documentParser;
// content caching
mutable QString m_cachedContents;
mutable int m_cachedContentsEditorRevision;
QTimer *m_updateEditorTimer;
EditorUpdates m_editorUpdates;
QMutex m_diagnosticsMutex;
QHash<QString, QList<CPlusPlus::Document::DiagnosticMessage> > m_allDiagnostics;
// Semantic info:
bool m_initialized;
mutable QMutex m_lastSemanticInfoLock;
SemanticInfo m_lastSemanticInfo;
QFuture<void> m_futureSemanticInfo;
// Highlighting:
unsigned m_lastHighlightRevision;
QFuture<TextEditor::HighlightingResult> m_highlighter;
QScopedPointer<CppTools::CppHighlightingSupport> m_highlightingSupport;
};
} // namespace Internal
} // namespace CppTools
#endif // CPPTOOLSEDITORSUPPORT_H