forked from qt-creator/qt-creator
		
	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:
		
				
					committed by
					
						
						Nikolai Kosjar
					
				
			
			
				
	
			
			
			
						parent
						
							e8d59fb76f
						
					
				
				
					commit
					0c27b27658
				
			@@ -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
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user