From 73b74cb6181cfdde7fe5eec9753433107c8dd690 Mon Sep 17 00:00:00 2001 From: Eberhard Graether Date: Mon, 30 Jun 2014 13:50:19 +0200 Subject: [PATCH] ui: basic CodeView with syntax highlighting Added CodeView interface and QtCodeView implementation for showing syntax highlighted code snippets. This change avoids using the GuiElement hierarchy by using directly using QtClasses and creating QtCodeView in the QtElementFactory. --- src/app/CMakeLists.txt | 12 +++- src/app/main.cpp | 11 +-- src/app/qt/QtElementFactory.cpp | 7 ++ src/app/qt/QtElementFactory.h | 5 ++ src/app/qt/utility/QtHighlighter.cpp | 98 ++++++++++++++++++++++++++ src/app/qt/utility/QtHighlighter.h | 38 ++++++++++ src/app/qt/view/QtCodeView.cpp | 50 +++++++++++++ src/app/qt/view/QtCodeView.h | 37 ++++++++++ src/lib/CMakeLists.txt | 6 +- src/lib/component/Component.cpp | 10 +++ src/lib/component/Component.h | 8 ++- src/lib/component/ComponentFactory.cpp | 13 +++- src/lib/component/ComponentFactory.h | 1 + src/lib/component/ComponentManager.cpp | 10 +++ src/lib/component/view/CodeView.cpp | 10 +++ src/lib/component/view/CodeView.h | 20 ++++++ src/lib/gui/GuiElementFactory.h | 6 ++ 17 files changed, 325 insertions(+), 17 deletions(-) create mode 100644 src/app/qt/utility/QtHighlighter.cpp create mode 100644 src/app/qt/utility/QtHighlighter.h create mode 100644 src/app/qt/view/QtCodeView.cpp create mode 100644 src/app/qt/view/QtCodeView.h create mode 100644 src/lib/component/view/CodeView.cpp create mode 100644 src/lib/component/view/CodeView.h diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index 9743d682..a0e952ed 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -7,17 +7,23 @@ add_files( qt/element/QtCanvas.h qt/element/QtLayout.cpp qt/element/QtLayout.h - + + qt/utility/QtHighLighter.cpp + qt/utility/QtHighLighter.h + + qt/view/QtCodeView.cpp + qt/view/QtCodeView.h + qt/QtWidgetWrapper.cpp qt/QtWidgetWrapper.h qt/QtElementFactory.cpp qt/QtElementFactory.h qt/QtWindow.cpp qt/QtWindow.h - + utility/utilityQt.cpp utility/utilityQt.h - + includesWindows.h main.cpp ) diff --git a/src/app/main.cpp b/src/app/main.cpp index ac001b85..f1b26f94 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -1,20 +1,15 @@ #include #include -#include -#include -#include #include "Application.h" #include "includes.h" -#include "qt/element/QtArea.h" -#include "qt/element/QtCanvas.h" #include "qt/QtElementFactory.h" #include "qt/QtWindow.h" -int main(int argv, char **args) +int main(int argc, char *argv[]) { - QApplication qtApp(argv, args); + QApplication qtApp(argc, argv); std::shared_ptr elementFactory = std::make_shared(); std::shared_ptr window = std::make_shared(); @@ -23,4 +18,4 @@ int main(int argv, char **args) app->loadProject(); return qtApp.exec(); -} \ No newline at end of file +} diff --git a/src/app/qt/QtElementFactory.cpp b/src/app/qt/QtElementFactory.cpp index 754425e4..490ddbf3 100644 --- a/src/app/qt/QtElementFactory.cpp +++ b/src/app/qt/QtElementFactory.cpp @@ -1,8 +1,10 @@ #include "qt/QtElementFactory.h" +#include "component/view/CodeView.h" #include "qt/element/QtArea.h" #include "qt/element/QtCanvas.h" #include "qt/element/QtLayout.h" +#include "qt/view/QtCodeView.h" #include "qt/QtWindow.h" QtElementFactory::QtElementFactory() @@ -29,3 +31,8 @@ std::shared_ptr QtElementFactory::createLayout() const { return std::make_shared(); } + +std::shared_ptr QtElementFactory::createCodeView(std::shared_ptr viewManager) const +{ + return std::make_shared(viewManager); +} diff --git a/src/app/qt/QtElementFactory.h b/src/app/qt/QtElementFactory.h index 9d81b00d..f4e777fc 100644 --- a/src/app/qt/QtElementFactory.h +++ b/src/app/qt/QtElementFactory.h @@ -3,6 +3,9 @@ #include "gui/GuiElementFactory.h" +class CodeView; +class ViewManager; + class QtElementFactory: public GuiElementFactory { public: @@ -12,6 +15,8 @@ public: virtual std::shared_ptr createArea() const; virtual std::shared_ptr createCanvas(std::shared_ptr window) const; virtual std::shared_ptr createLayout() const; + + virtual std::shared_ptr createCodeView(std::shared_ptr viewManager) const; }; # endif // QT_ELEMENT_FACTORY_H diff --git a/src/app/qt/utility/QtHighlighter.cpp b/src/app/qt/utility/QtHighlighter.cpp new file mode 100644 index 00000000..ee23e9b1 --- /dev/null +++ b/src/app/qt/utility/QtHighlighter.cpp @@ -0,0 +1,98 @@ +#include "qt/utility/QtHighlighter.h" + +QtHighlighter::QtHighlighter(QTextDocument *parent) + : QSyntaxHighlighter(parent) +{ + HighlightingRule rule; + + keywordFormat.setForeground(Qt::darkBlue); + keywordFormat.setFontWeight(QFont::Bold); + + QStringList keywordPatterns; + keywordPatterns + << "\\bchar\\b" << "\\bclass\\b" << "\\bconst\\b" + << "\\bdouble\\b" << "\\benum\\b" << "\\bexplicit\\b" + << "\\bfriend\\b" << "\\binline\\b" << "\\bint\\b" + << "\\blong\\b" << "\\bnamespace\\b" << "\\boperator\\b" + << "\\bprivate\\b" << "\\bprotected\\b" << "\\bpublic\\b" + << "\\bshort\\b" << "\\bsignals\\b" << "\\bsigned\\b" + << "\\bslots\\b" << "\\bstatic\\b" << "\\bstruct\\b" + << "\\btemplate\\b" << "\\btypedef\\b" << "\\btypename\\b" + << "\\bunion\\b" << "\\bunsigned\\b" << "\\bvirtual\\b" + << "\\bvoid\\b" << "\\bvolatile\\b"; + + foreach (const QString &pattern, keywordPatterns) + { + rule.pattern = QRegExp(pattern); + rule.format = keywordFormat; + highlightingRules.append(rule); + } + + classFormat.setFontWeight(QFont::Bold); + classFormat.setForeground(Qt::darkMagenta); + rule.pattern = QRegExp("\\bQ[A-Za-z]+\\b"); + rule.format = classFormat; + highlightingRules.append(rule); + + singleLineCommentFormat.setForeground(Qt::red); + rule.pattern = QRegExp("//[^\n]*"); + rule.format = singleLineCommentFormat; + highlightingRules.append(rule); + + multiLineCommentFormat.setForeground(Qt::red); + + quotationFormat.setForeground(Qt::darkGreen); + rule.pattern = QRegExp("\".*\""); + rule.format = quotationFormat; + highlightingRules.append(rule); + + functionFormat.setFontItalic(true); + functionFormat.setForeground(Qt::blue); + rule.pattern = QRegExp("\\b[A-Za-z0-9_]+(?=\\()"); + rule.format = functionFormat; + highlightingRules.append(rule); + + commentStartExpression = QRegExp("/\\*"); + commentEndExpression = QRegExp("\\*/"); +} + +void QtHighlighter::highlightBlock(const QString &text) +{ + foreach (const HighlightingRule &rule, highlightingRules) + { + QRegExp expression(rule.pattern); + int index = expression.indexIn(text); + while (index >= 0) + { + int length = expression.matchedLength(); + setFormat(index, length, rule.format); + index = expression.indexIn(text, index + length); + } + } + setCurrentBlockState(0); + + int startIndex = 0; + if (previousBlockState() != 1) + { + startIndex = commentStartExpression.indexIn(text); + } + + while (startIndex >= 0) + { + int endIndex = commentEndExpression.indexIn(text, startIndex); + int commentLength; + + if (endIndex == -1) + { + setCurrentBlockState(1); + commentLength = text.length() - startIndex; + } + else + { + commentLength = endIndex - startIndex + commentEndExpression.matchedLength(); + } + + setFormat(startIndex, commentLength, multiLineCommentFormat); + startIndex = commentStartExpression.indexIn(text, startIndex + commentLength); + } +} diff --git a/src/app/qt/utility/QtHighlighter.h b/src/app/qt/utility/QtHighlighter.h new file mode 100644 index 00000000..eba008c9 --- /dev/null +++ b/src/app/qt/utility/QtHighlighter.h @@ -0,0 +1,38 @@ +#ifndef QT_HIGHLIGHTER_H +#define QT_HIGHLIGHTER_H + +#include +#include + +class QTextDocument; + +class QtHighlighter : public QSyntaxHighlighter +{ + Q_OBJECT + +public: + QtHighlighter(QTextDocument *parent = 0); + +protected: + void highlightBlock(const QString &text); + +private: + struct HighlightingRule + { + QRegExp pattern; + QTextCharFormat format; + }; + QVector highlightingRules; + + QRegExp commentStartExpression; + QRegExp commentEndExpression; + + QTextCharFormat keywordFormat; + QTextCharFormat classFormat; + QTextCharFormat singleLineCommentFormat; + QTextCharFormat multiLineCommentFormat; + QTextCharFormat quotationFormat; + QTextCharFormat functionFormat; +}; + +#endif // QT_HIGHLIGHTER_H diff --git a/src/app/qt/view/QtCodeView.cpp b/src/app/qt/view/QtCodeView.cpp new file mode 100644 index 00000000..e1660165 --- /dev/null +++ b/src/app/qt/view/QtCodeView.cpp @@ -0,0 +1,50 @@ +#include "qt/view/QtCodeView.h" + +#include + +#include "qt/element/QtArea.h" +#include "qt/QtWidgetWrapper.h" +#include "qt/utility/QtHighLighter.h" + +QtCodeView::QtCodeView(std::shared_ptr viewManager) + : CodeView(viewManager, std::make_shared()) +{ + getRootElement()->setBackgroundColor(255, 125, 0, 255); + + std::shared_ptr widget = QtWidgetWrapper::getWidgetOfElement(getRootElement()); + QBoxLayout* layout = new QBoxLayout(QBoxLayout::TopToBottom); + layout->setSpacing(3); + layout->setContentsMargins(3, 3, 3, 3); + widget->setLayout(layout); + + m_font.setFamily("Courier"); + m_font.setFixedPitch(true); + m_font.setPointSize(10); +} + +QtCodeView::~QtCodeView() +{ +} + +void QtCodeView::addCodeSnippet(std::string str) +{ + std::shared_ptr snippet = std::make_shared(); + + snippet->textField = std::make_shared(); + snippet->textField->setReadOnly(true); + snippet->textField->setFont(m_font); + + snippet->highlighter = std::make_shared(snippet->textField->document()); + + snippet->textField->setPlainText(QString::fromUtf8(str.c_str())); + + std::shared_ptr widget = QtWidgetWrapper::getWidgetOfElement(getRootElement()); + widget->layout()->addWidget(snippet->textField.get()); + + m_snippets.push_back(snippet); +} + +void QtCodeView::clearCodeSnippets() +{ + m_snippets.clear(); +} diff --git a/src/app/qt/view/QtCodeView.h b/src/app/qt/view/QtCodeView.h new file mode 100644 index 00000000..db09ba0c --- /dev/null +++ b/src/app/qt/view/QtCodeView.h @@ -0,0 +1,37 @@ +#ifndef QT_CODE_VIEW_H +#define QT_CODE_VIEW_H + +#include +#include +#include + +#include + +#include "component/view/CodeView.h" + +class QtHighlighter; +class QTextEdit; +class ViewManager; + +class QtCodeView: public CodeView +{ +public: + QtCodeView(std::shared_ptr viewManager); + ~QtCodeView(); + + // CodeView implementation + virtual void addCodeSnippet(std::string str); + virtual void clearCodeSnippets(); + +private: + struct Snippet + { + std::shared_ptr textField; + std::shared_ptr highlighter; + }; + std::vector> m_snippets; + + QFont m_font; +}; + +# endif // QT_CODE_VIEW_H diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index b51fe965..c906d4c0 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -23,6 +23,8 @@ add_files( component/controller/DummyController.cpp component/controller/DummyController.h + component/view/CodeView.cpp + component/view/CodeView.h component/view/DummyView.cpp component/view/DummyView.h component/view/View.cpp @@ -114,10 +116,10 @@ add_files( utility/messaging/MessageListenerBase.h utility/messaging/MessageQueue.cpp utility/messaging/MessageQueue.h - + utility/text/TextAccess.cpp utility/text/TextAccess.h - + utility/ConfigManager.cpp utility/ConfigManager.h utility/FileSystem.cpp diff --git a/src/lib/component/Component.cpp b/src/lib/component/Component.cpp index a4823ee6..2165d18f 100644 --- a/src/lib/component/Component.cpp +++ b/src/lib/component/Component.cpp @@ -9,3 +9,13 @@ Component::Component(std::shared_ptr view, std::shared_ptr con Component::~Component() { } + +Controller* Component::getController() const +{ + return m_controller.get(); +} + +View* Component::getView() const +{ + return m_view.get(); +} diff --git a/src/lib/component/Component.h b/src/lib/component/Component.h index 3a32b501..f5e7fe14 100644 --- a/src/lib/component/Component.h +++ b/src/lib/component/Component.h @@ -10,12 +10,14 @@ class Component { public: Component(std::shared_ptr view, std::shared_ptr controller); - ~Component(); + Controller* getController() const; + View* getView() const; + private: - std::shared_ptr m_controller; - std::shared_ptr m_view; + const std::shared_ptr m_controller; + const std::shared_ptr m_view; }; diff --git a/src/lib/component/ComponentFactory.cpp b/src/lib/component/ComponentFactory.cpp index 5a7bed9c..4ca7e08b 100644 --- a/src/lib/component/ComponentFactory.cpp +++ b/src/lib/component/ComponentFactory.cpp @@ -1,7 +1,9 @@ #include "component/ComponentFactory.h" -#include "component/view/DummyView.h" +#include "component/controller/CodeController.h" #include "component/controller/DummyController.h" +#include "component/view/CodeView.h" +#include "component/view/DummyView.h" std::shared_ptr ComponentFactory::create( std::shared_ptr viewManager, @@ -30,6 +32,15 @@ std::shared_ptr ComponentFactory::createDummyComponent() return component; } +std::shared_ptr ComponentFactory::createCodeComponent() +{ + std::shared_ptr view = m_guiElementFactory->createCodeView(m_viewManger); + std::shared_ptr controller = std::make_shared(); + + std::shared_ptr component = std::make_shared(view, controller); + return component; +} + ComponentFactory::ComponentFactory() { } diff --git a/src/lib/component/ComponentFactory.h b/src/lib/component/ComponentFactory.h index 73a1c6f2..ba098cef 100644 --- a/src/lib/component/ComponentFactory.h +++ b/src/lib/component/ComponentFactory.h @@ -21,6 +21,7 @@ public: ~ComponentFactory(); std::shared_ptr createDummyComponent(); + std::shared_ptr createCodeComponent(); private: ComponentFactory(); diff --git a/src/lib/component/ComponentManager.cpp b/src/lib/component/ComponentManager.cpp index dd926506..93bc88e7 100644 --- a/src/lib/component/ComponentManager.cpp +++ b/src/lib/component/ComponentManager.cpp @@ -1,5 +1,7 @@ #include "component/ComponentManager.h" +#include "component/view/CodeView.h" + std::shared_ptr ComponentManager::create( std::shared_ptr viewManager, std::shared_ptr guiElementFactory, @@ -14,6 +16,14 @@ std::shared_ptr ComponentManager::create( void ComponentManager::setup() { m_components.push_back(m_componentFactory->createDummyComponent()); + + std::shared_ptr codeComponent = m_componentFactory->createCodeComponent(); + m_components.push_back(codeComponent); + + CodeView* codeView = dynamic_cast(codeComponent->getView()); + codeView->addCodeSnippet("class HelloWorld;"); + codeView->addCodeSnippet("static int n = 42; // the answer."); + // codeView->clearCodeSnippets(); } ComponentManager::ComponentManager() diff --git a/src/lib/component/view/CodeView.cpp b/src/lib/component/view/CodeView.cpp new file mode 100644 index 00000000..4b7f01b7 --- /dev/null +++ b/src/lib/component/view/CodeView.cpp @@ -0,0 +1,10 @@ +#include "component/view/CodeView.h" + +CodeView::CodeView(std::shared_ptr viewManager, std::shared_ptr rootElement) + : View(viewManager, rootElement, Vec2i(100, 100)) +{ +} + +CodeView::~CodeView() +{ +} diff --git a/src/lib/component/view/CodeView.h b/src/lib/component/view/CodeView.h new file mode 100644 index 00000000..be91d3db --- /dev/null +++ b/src/lib/component/view/CodeView.h @@ -0,0 +1,20 @@ +#ifndef CODE_VIEW_H +#define CODE_VIEW_H + +#include + +#include "component/view/View.h" + +class GuiElementFactory; + +class CodeView: public View +{ +public: + CodeView(std::shared_ptr viewManager, std::shared_ptr rootElement); + virtual ~CodeView(); + + virtual void addCodeSnippet(std::string str) = 0; + virtual void clearCodeSnippets() = 0; +}; + +#endif // CODE_VIEW_H diff --git a/src/lib/gui/GuiElementFactory.h b/src/lib/gui/GuiElementFactory.h index 34ca532c..cf41731c 100644 --- a/src/lib/gui/GuiElementFactory.h +++ b/src/lib/gui/GuiElementFactory.h @@ -3,11 +3,15 @@ #include +class CodeView; + class GuiArea; class GuiCanvas; class GuiLayout; class GuiWindow; +class ViewManager; + class GuiElementFactory { public: @@ -16,6 +20,8 @@ public: virtual std::shared_ptr createArea() const = 0; virtual std::shared_ptr createCanvas(std::shared_ptr window) const = 0; virtual std::shared_ptr createLayout() const = 0; + + virtual std::shared_ptr createCodeView(std::shared_ptr viewManager) const = 0; }; #endif // GUI_ELEMENT_FACTORY_H