Browse Source

add MindMap editor

Le Tan 2 years ago
parent
commit
5229be4687
53 changed files with 1242 additions and 202 deletions
  1. 5 2
      src/core/buffer/buffer.pri
  2. 16 0
      src/core/buffer/filetypehelper.cpp
  3. 1 0
      src/core/buffer/filetypehelper.h
  4. 17 0
      src/core/buffer/mindmapbuffer.cpp
  5. 21 0
      src/core/buffer/mindmapbuffer.h
  6. 16 0
      src/core/buffer/mindmapbufferfactory.cpp
  7. 19 0
      src/core/buffer/mindmapbufferfactory.h
  8. 0 1
      src/core/buffer/pdfbuffer.h
  9. 0 3
      src/core/buffer/urlbasedbufferprovider.cpp
  10. 5 0
      src/core/buffermgr.cpp
  11. 2 0
      src/core/core.pri
  12. 15 1
      src/core/editorconfig.cpp
  13. 6 0
      src/core/editorconfig.h
  14. 42 1
      src/core/htmltemplatehelper.cpp
  15. 12 1
      src/core/htmltemplatehelper.h
  16. 61 0
      src/core/mindmapeditorconfig.cpp
  17. 31 0
      src/core/mindmapeditorconfig.h
  18. 39 0
      src/data/core/vnotex.json
  19. 5 2
      src/data/extra/extra.qrc
  20. 4 0
      src/data/extra/web/js/markjs.js
  21. 0 0
      src/data/extra/web/js/mind-elixir/MindElixir.js
  22. 0 6
      src/data/extra/web/js/mind-elixir/MindElixir.min.js
  23. 1 1
      src/data/extra/web/js/mind-elixir/README.md
  24. 0 0
      src/data/extra/web/js/mind-elixir/painter.js
  25. 33 0
      src/data/extra/web/js/mindmapeditor.js
  26. 38 0
      src/data/extra/web/js/mindmapeditorcore.js
  27. 33 0
      src/data/extra/web/mindmap-editor-template.html
  28. 2 2
      src/widgets/editors/markdownviewer.cpp
  29. 24 93
      src/widgets/editors/markdownvieweradapter.cpp
  30. 3 38
      src/widgets/editors/markdownvieweradapter.h
  31. 44 0
      src/widgets/editors/mindmapeditor.cpp
  32. 35 0
      src/widgets/editors/mindmapeditor.h
  33. 39 0
      src/widgets/editors/mindmapeditoradapter.cpp
  34. 45 0
      src/widgets/editors/mindmapeditoradapter.h
  35. 0 1
      src/widgets/editors/pdfviewer.cpp
  36. 3 20
      src/widgets/editors/pdfvieweradapter.cpp
  37. 2 14
      src/widgets/editors/pdfvieweradapter.h
  38. 92 0
      src/widgets/editors/webviewadapter.cpp
  39. 71 0
      src/widgets/editors/webviewadapter.h
  40. 16 0
      src/widgets/findandreplacewidget.cpp
  41. 2 0
      src/widgets/findandreplacewidget.h
  42. 3 3
      src/widgets/markdownviewwindow.cpp
  43. 292 0
      src/widgets/mindmapviewwindow.cpp
  44. 93 0
      src/widgets/mindmapviewwindow.h
  45. 10 1
      src/widgets/pdfviewwindow.cpp
  46. 2 1
      src/widgets/pdfviewwindow.h
  47. 0 5
      src/widgets/textviewwindow.cpp
  48. 0 5
      src/widgets/textviewwindow.h
  49. 5 0
      src/widgets/viewwindow.cpp
  50. 6 1
      src/widgets/viewwindow.h
  51. 19 0
      src/widgets/webviewer.cpp
  52. 4 0
      src/widgets/webviewer.h
  53. 8 0
      src/widgets/widgets.pri

+ 5 - 2
src/core/buffer/buffer.pri

@@ -5,12 +5,13 @@ SOURCES += \
     $$PWD/markdownbuffer.cpp \
     $$PWD/markdownbufferfactory.cpp \
     $$PWD/filetypehelper.cpp \
+    $$PWD/mindmapbuffer.cpp \
+    $$PWD/mindmapbufferfactory.cpp \
     $$PWD/nodebufferprovider.cpp \
     $$PWD/pdfbuffer.cpp \
     $$PWD/pdfbufferfactory.cpp \
     $$PWD/textbuffer.cpp \
-    $$PWD/textbufferfactory.cpp \
-    $$PWD/urlbasedbufferprovider.cpp
+    $$PWD/textbufferfactory.cpp
 
 HEADERS += \
     $$PWD/bufferprovider.h \
@@ -20,6 +21,8 @@ HEADERS += \
     $$PWD/markdownbuffer.h \
     $$PWD/markdownbufferfactory.h \
     $$PWD/filetypehelper.h \
+    $$PWD/mindmapbuffer.h \
+    $$PWD/mindmapbufferfactory.h \
     $$PWD/nodebufferprovider.h \
     $$PWD/pdfbuffer.h \
     $$PWD/pdfbufferfactory.h \

+ 16 - 0
src/core/buffer/filetypehelper.cpp

@@ -91,6 +91,22 @@ void FileTypeHelper::setupBuiltInTypes()
         m_fileTypes.push_back(type);
     }
 
+    {
+        FileType type;
+        type.m_type = FileType::MindMap;
+        type.m_typeName = QStringLiteral("MindMap");
+        type.m_displayName = Buffer::tr("Mind Map");
+
+        auto suffixes = coreConfig.findFileTypeSuffix(type.m_typeName);
+        if (suffixes && !suffixes->isEmpty()) {
+            type.m_suffixes = *suffixes;
+        } else {
+            type.m_suffixes << QStringLiteral("emind");
+        }
+
+        m_fileTypes.push_back(type);
+    }
+
     {
         FileType type;
         type.m_type = FileType::Others;

+ 1 - 0
src/core/buffer/filetypehelper.h

@@ -16,6 +16,7 @@ namespace vnotex
             Markdown = 0,
             Text,
             Pdf,
+            MindMap,
             Others
         };
 

+ 17 - 0
src/core/buffer/mindmapbuffer.cpp

@@ -0,0 +1,17 @@
+#include "mindmapbuffer.h"
+
+#include <widgets/mindmapviewwindow.h>
+
+using namespace vnotex;
+
+MindMapBuffer::MindMapBuffer(const BufferParameters &p_parameters,
+                             QObject *p_parent)
+    : Buffer(p_parameters, p_parent)
+{
+}
+
+ViewWindow *MindMapBuffer::createViewWindowInternal(const QSharedPointer<FileOpenParameters> &p_paras, QWidget *p_parent)
+{
+    Q_UNUSED(p_paras);
+    return new MindMapViewWindow(p_parent);
+}

+ 21 - 0
src/core/buffer/mindmapbuffer.h

@@ -0,0 +1,21 @@
+#ifndef MINDMAPBUFFER_H
+#define MINDMAPBUFFER_H
+
+#include "buffer.h"
+
+namespace vnotex
+{
+    class MindMapBuffer : public Buffer
+    {
+        Q_OBJECT
+    public:
+        MindMapBuffer(const BufferParameters &p_parameters,
+                      QObject *p_parent = nullptr);
+
+    protected:
+        ViewWindow *createViewWindowInternal(const QSharedPointer<FileOpenParameters> &p_paras,
+                                             QWidget *p_parent) Q_DECL_OVERRIDE;
+    };
+}
+
+#endif // MINDMAPBUFFER_H

+ 16 - 0
src/core/buffer/mindmapbufferfactory.cpp

@@ -0,0 +1,16 @@
+#include "mindmapbufferfactory.h"
+
+#include "mindmapbuffer.h"
+
+using namespace vnotex;
+
+Buffer *MindMapBufferFactory::createBuffer(const BufferParameters &p_parameters,
+                                           QObject *p_parent)
+{
+    return new MindMapBuffer(p_parameters, p_parent);
+}
+
+bool MindMapBufferFactory::isBufferCreatedByFactory(const Buffer *p_buffer) const
+{
+    return dynamic_cast<const MindMapBuffer *>(p_buffer) != nullptr;
+}

+ 19 - 0
src/core/buffer/mindmapbufferfactory.h

@@ -0,0 +1,19 @@
+#ifndef MINDMAPBUFFERFACTORY_H
+#define MINDMAPBUFFERFACTORY_H
+
+#include "ibufferfactory.h"
+
+namespace vnotex
+{
+    // Buffer factory for MindMap file.
+    class MindMapBufferFactory : public IBufferFactory
+    {
+    public:
+        Buffer *createBuffer(const BufferParameters &p_parameters,
+                             QObject *p_parent) Q_DECL_OVERRIDE;
+
+        bool isBufferCreatedByFactory(const Buffer *p_buffer) const Q_DECL_OVERRIDE;
+    };
+}
+
+#endif // MINDMAPBUFFERFACTORY_H

+ 0 - 1
src/core/buffer/pdfbuffer.h

@@ -15,7 +15,6 @@ namespace vnotex
     protected:
         ViewWindow *createViewWindowInternal(const QSharedPointer<FileOpenParameters> &p_paras,
                                              QWidget *p_parent) Q_DECL_OVERRIDE;
-
     };
 } // ns vnotex
 

+ 0 - 3
src/core/buffer/urlbasedbufferprovider.cpp

@@ -1,3 +0,0 @@
-#include "urlbasedbufferprovider.h"
-
-using namespace vnotex;

+ 5 - 0
src/core/buffermgr.cpp

@@ -8,6 +8,7 @@
 #include <buffer/markdownbufferfactory.h>
 #include <buffer/textbufferfactory.h>
 #include <buffer/pdfbufferfactory.h>
+#include <buffer/mindmapbufferfactory.h>
 #include <buffer/buffer.h>
 #include <buffer/nodebufferprovider.h>
 #include <buffer/filebufferprovider.h>
@@ -57,6 +58,10 @@ void BufferMgr::initBufferServer()
     // Pdf.
     auto pdfFactory = QSharedPointer<PdfBufferFactory>::create();
     m_bufferServer->registerItem(helper.getFileType(FileType::Pdf).m_typeName, pdfFactory);
+
+    // MindMap.
+    auto mindMapFactory = QSharedPointer<MindMapBufferFactory>::create();
+    m_bufferServer->registerItem(helper.getFileType(FileType::MindMap).m_typeName, mindMapFactory);
 }
 
 void BufferMgr::open(Node *p_node, const QSharedPointer<FileOpenParameters> &p_paras)

+ 2 - 0
src/core/core.pri

@@ -24,6 +24,7 @@ SOURCES += \
     $$PWD/logger.cpp \
     $$PWD/mainconfig.cpp \
     $$PWD/markdowneditorconfig.cpp \
+    $$PWD/mindmapeditorconfig.cpp \
     $$PWD/pdfviewerconfig.cpp \
     $$PWD/quickaccesshelper.cpp \
     $$PWD/singleinstanceguard.cpp \
@@ -54,6 +55,7 @@ HEADERS += \
     $$PWD/logger.h \
     $$PWD/mainconfig.h \
     $$PWD/markdowneditorconfig.h \
+    $$PWD/mindmapeditorconfig.h \
     $$PWD/noncopyable.h \
     $$PWD/pdfviewerconfig.h \
     $$PWD/quickaccesshelper.h \

+ 15 - 1
src/core/editorconfig.cpp

@@ -6,6 +6,7 @@
 #include "texteditorconfig.h"
 #include "markdowneditorconfig.h"
 #include "pdfviewerconfig.h"
+#include "mindmapeditorconfig.h"
 
 #include <vtextedit/viconfig.h>
 
@@ -43,7 +44,8 @@ EditorConfig::EditorConfig(ConfigMgr *p_mgr, IConfig *p_topConfig)
     : IConfig(p_mgr, p_topConfig),
       m_textEditorConfig(new TextEditorConfig(p_mgr, p_topConfig)),
       m_markdownEditorConfig(new MarkdownEditorConfig(p_mgr, p_topConfig, m_textEditorConfig)),
-      m_pdfViewerConfig(new PdfViewerConfig(p_mgr, p_topConfig))
+      m_pdfViewerConfig(new PdfViewerConfig(p_mgr, p_topConfig)),
+      m_mindMapEditorConfig(new MindMapEditorConfig(p_mgr, p_topConfig))
 {
     m_sessionName = QStringLiteral("editor");
 }
@@ -68,6 +70,7 @@ void EditorConfig::init(const QJsonObject &p_app,
     m_textEditorConfig->init(appObj, userObj);
     m_markdownEditorConfig->init(appObj, userObj);
     m_pdfViewerConfig->init(appObj, userObj);
+    m_mindMapEditorConfig->init(appObj, userObj);
 }
 
 void EditorConfig::loadCore(const QJsonObject &p_app, const QJsonObject &p_user)
@@ -152,6 +155,7 @@ QJsonObject EditorConfig::toJson() const
     obj[m_textEditorConfig->getSessionName()] = m_textEditorConfig->toJson();
     obj[m_markdownEditorConfig->getSessionName()] = m_markdownEditorConfig->toJson();
     obj[m_pdfViewerConfig->getSessionName()] = m_pdfViewerConfig->toJson();
+    obj[m_mindMapEditorConfig->getSessionName()] = m_mindMapEditorConfig->toJson();
     obj[QStringLiteral("core")] = saveCore();
     obj[QStringLiteral("image_host")] = saveImageHost();
 
@@ -192,6 +196,16 @@ const PdfViewerConfig &EditorConfig::getPdfViewerConfig() const
     return *m_pdfViewerConfig;
 }
 
+MindMapEditorConfig &EditorConfig::getMindMapEditorConfig()
+{
+    return *m_mindMapEditorConfig;
+}
+
+const MindMapEditorConfig &EditorConfig::getMindMapEditorConfig() const
+{
+    return *m_mindMapEditorConfig;
+}
+
 int EditorConfig::getToolBarIconSize() const
 {
     return m_toolBarIconSize;

+ 6 - 0
src/core/editorconfig.h

@@ -20,6 +20,7 @@ namespace vnotex
     class TextEditorConfig;
     class MarkdownEditorConfig;
     class PdfViewerConfig;
+    class MindMapEditorConfig;
 
     class EditorConfig : public IConfig
     {
@@ -109,6 +110,9 @@ namespace vnotex
         PdfViewerConfig &getPdfViewerConfig();
         const PdfViewerConfig &getPdfViewerConfig() const;
 
+        MindMapEditorConfig &getMindMapEditorConfig();
+        const MindMapEditorConfig &getMindMapEditorConfig() const;
+
         void init(const QJsonObject &p_app, const QJsonObject &p_user) Q_DECL_OVERRIDE;
 
         QJsonObject toJson() const Q_DECL_OVERRIDE;
@@ -182,6 +186,8 @@ namespace vnotex
 
         QScopedPointer<PdfViewerConfig> m_pdfViewerConfig;
 
+        QScopedPointer<MindMapEditorConfig> m_mindMapEditorConfig;
+
         bool m_spellCheckAutoDetectLanguageEnabled = false;
 
         QString m_spellCheckDefaultDictionary;

+ 42 - 1
src/core/htmltemplatehelper.cpp

@@ -4,6 +4,7 @@
 
 #include <core/markdowneditorconfig.h>
 #include <core/pdfviewerconfig.h>
+#include <core/mindmapeditorconfig.h>
 #include <core/configmgr.h>
 #include <utils/utils.h>
 #include <utils/fileutils.h>
@@ -19,6 +20,8 @@ HtmlTemplateHelper::Template HtmlTemplateHelper::s_markdownViewerTemplate;
 
 HtmlTemplateHelper::Template HtmlTemplateHelper::s_pdfViewerTemplate;
 
+HtmlTemplateHelper::Template HtmlTemplateHelper::s_mindMapEditorTemplate;
+
 QString MarkdownWebGlobalOptions::toJavascriptObject() const
 {
     return QStringLiteral("window.vxOptions = {\n")
@@ -339,7 +342,7 @@ const QString &HtmlTemplateHelper::getPdfViewerTemplatePath()
 
 void HtmlTemplateHelper::updatePdfViewerTemplate(const PdfViewerConfig &p_config, bool p_force)
 {
-    if (!p_force && p_config.revision() == s_markdownViewerTemplate.m_revision) {
+    if (!p_force && p_config.revision() == s_pdfViewerTemplate.m_revision) {
         return;
     }
 
@@ -361,3 +364,41 @@ void HtmlTemplateHelper::generatePdfViewerTemplate(const PdfViewerConfig &p_conf
 
     fillResources(p_template.m_template, viewerResource);
 }
+
+const QString &HtmlTemplateHelper::getMindMapEditorTemplate()
+{
+    return s_mindMapEditorTemplate.m_template;
+}
+
+void HtmlTemplateHelper::updateMindMapEditorTemplate(const MindMapEditorConfig &p_config, bool p_force)
+{
+    if (!p_force && p_config.revision() == s_mindMapEditorTemplate.m_revision) {
+        return;
+    }
+
+    s_mindMapEditorTemplate.m_revision = p_config.revision();
+
+    const auto &themeMgr = VNoteX::getInst().getThemeMgr();
+    generateMindMapEditorTemplate(p_config,
+                                  themeMgr.getFile(Theme::File::WebStyleSheet),
+                                  s_mindMapEditorTemplate);
+}
+
+void HtmlTemplateHelper::generateMindMapEditorTemplate(const MindMapEditorConfig &p_config,
+                                                       const QString &p_webStyleSheetFile,
+                                                       Template& p_template)
+{
+    const auto &editorResource = p_config.getEditorResource();
+    p_template.m_templatePath = ConfigMgr::getInst().getUserOrAppFile(editorResource.m_template);
+    try {
+        p_template.m_template = FileUtils::readTextFile(p_template.m_templatePath);
+    } catch (Exception &p_e) {
+        qWarning() << "failed to read HTML template" << p_template.m_templatePath << p_e.what();
+        p_template.m_template = errorPage();
+        return;
+    }
+
+    fillThemeStyles(p_template.m_template, p_webStyleSheetFile, QString());
+
+    fillResources(p_template.m_template, editorResource);
+}

+ 12 - 1
src/core/htmltemplatehelper.h

@@ -7,6 +7,7 @@ namespace vnotex
 {
     class MarkdownEditorConfig;
     class PdfViewerConfig;
+    class MindMapEditorConfig;
     struct WebResource;
 
     // Global options to be passed to Web side at the very beginning for Markdown.
@@ -91,7 +92,7 @@ namespace vnotex
 
         HtmlTemplateHelper() = delete;
 
-        // For Markdown.
+        // For MarkdownViewer.
         static const QString &getMarkdownViewerTemplate();
         static void updateMarkdownViewerTemplate(const MarkdownEditorConfig &p_config, bool p_force = false);
 
@@ -119,6 +120,10 @@ namespace vnotex
 
         static const QString &getPdfViewerTemplatePath();
 
+        // For MindMapEditor.
+        static const QString &getMindMapEditorTemplate();
+        static void updateMindMapEditorTemplate(const MindMapEditorConfig &p_config, bool p_force = false);
+
     private:
         struct Template
         {
@@ -131,9 +136,15 @@ namespace vnotex
 
         static void generatePdfViewerTemplate(const PdfViewerConfig &p_config, Template& p_template);
 
+        static void generateMindMapEditorTemplate(const MindMapEditorConfig &p_config,
+                                                  const QString &p_webStyleSheetFile,
+                                                  Template& p_template);
+
         static Template s_markdownViewerTemplate;
 
         static Template s_pdfViewerTemplate;
+
+        static Template s_mindMapEditorTemplate;
     };
 }
 

+ 61 - 0
src/core/mindmapeditorconfig.cpp

@@ -0,0 +1,61 @@
+#include "mindmapeditorconfig.h"
+
+#include "mainconfig.h"
+
+#define READSTR(key) readString(appObj, userObj, (key))
+#define READBOOL(key) readBool(appObj, userObj, (key))
+#define READINT(key) readInt(appObj, userObj, (key))
+
+using namespace vnotex;
+
+MindMapEditorConfig::MindMapEditorConfig(ConfigMgr *p_mgr, IConfig *p_topConfig)
+    : IConfig(p_mgr, p_topConfig)
+{
+    m_sessionName = QStringLiteral("mindmap_editor");
+}
+
+void MindMapEditorConfig::init(const QJsonObject &p_app,
+                               const QJsonObject &p_user)
+{
+    const auto appObj = p_app.value(m_sessionName).toObject();
+    const auto userObj = p_user.value(m_sessionName).toObject();
+
+    loadEditorResource(appObj, userObj);
+}
+
+QJsonObject MindMapEditorConfig::toJson() const
+{
+    QJsonObject obj;
+    obj[QStringLiteral("editor_resource")] = saveEditorResource();
+    return obj;
+}
+
+void MindMapEditorConfig::loadEditorResource(const QJsonObject &p_app, const QJsonObject &p_user)
+{
+    const QString name(QStringLiteral("editor_resource"));
+
+    if (MainConfig::isVersionChanged()) {
+        bool needOverride = p_app[QStringLiteral("override_editor_resource")].toBool();
+        if (needOverride) {
+            qInfo() << "override \"editor_resource\" in user configuration due to version change";
+            m_editorResource.init(p_app[name].toObject());
+            return;
+        }
+    }
+
+    if (p_user.contains(name)) {
+        m_editorResource.init(p_user[name].toObject());
+    } else {
+        m_editorResource.init(p_app[name].toObject());
+    }
+}
+
+QJsonObject MindMapEditorConfig::saveEditorResource() const
+{
+    return m_editorResource.toJson();
+}
+
+const WebResource &MindMapEditorConfig::getEditorResource() const
+{
+    return m_editorResource;
+}

+ 31 - 0
src/core/mindmapeditorconfig.h

@@ -0,0 +1,31 @@
+#ifndef MINDMAPEDITORCONFIG_H
+#define MINDMAPEDITORCONFIG_H
+
+#include "iconfig.h"
+
+#include "webresource.h"
+
+namespace vnotex
+{
+    class MindMapEditorConfig : public IConfig
+    {
+    public:
+        MindMapEditorConfig(ConfigMgr *p_mgr, IConfig *p_topConfig);
+
+        void init(const QJsonObject &p_app, const QJsonObject &p_user) Q_DECL_OVERRIDE;
+
+        QJsonObject toJson() const Q_DECL_OVERRIDE;
+
+        const WebResource &getEditorResource() const;
+
+    private:
+        friend class MainConfig;
+
+        void loadEditorResource(const QJsonObject &p_app, const QJsonObject &p_user);
+        QJsonObject saveEditorResource() const;
+
+        WebResource m_editorResource;
+    };
+}
+
+#endif // MINDMAPEDITORCONFIG_H

+ 39 - 0
src/data/core/vnotex.json

@@ -94,6 +94,12 @@
                 "suffixes" : [
                     "pdf"
                 ]
+            },
+            {
+                "name" : "MindMap",
+                "suffixes" : [
+                    "emind"
+                ]
             }
         ],
         "shortcut_leader_key" : "Ctrl+G",
@@ -519,6 +525,39 @@
                 ]
             }
         },
+        "mindmap_editor" : {
+            "override_editor_resource" : true,
+            "editor_resource" : {
+                "template" : "web/mindmap-editor-template.html",
+                "resources" : [
+                    {
+                        "name" : "built_in",
+                        "enabled" : true,
+                        "scripts" : [
+                            "web/js/qwebchannel.js",
+                            "web/js/eventemitter.js",
+                            "web/js/utils.js",
+                            "web/js/vxcore.js",
+                            "web/js/mindmapeditorcore.js"
+                        ]
+                    },
+                    {
+                        "name" : "mind_elixir",
+                        "enabled" : true,
+                        "scripts" : [
+                            "web/js/mind-elixir/MindElixir.js"
+                        ]
+                    },
+                    {
+                        "name" : "mindmap_editor",
+                        "enabled" : true,
+                        "scripts" : [
+                            "web/js/mindmapeditor.js"
+                        ]
+                    }
+                ]
+            }
+        },
         "image_host" : {
             "hosts" : [
             ],

+ 5 - 2
src/data/extra/extra.qrc

@@ -79,8 +79,6 @@
         <file>web/js/turndown.js</file>
         <file>web/js/mark.js/mark.min.js</file>
         <file>web/js/markjs.js</file>
-        <file>web/js/mind-elixir/MindElixir.min.js</file>
-        <file>web/js/mind-elixir/painter.js</file>
 
         <file>web/pdf.js/pdfviewer.js</file>
         <file>web/pdf.js/pdfviewer.css</file>
@@ -327,6 +325,11 @@
         <file>web/pdf.js/web/cmaps/V.bcmap</file>
         <file>web/pdf.js/web/cmaps/WP-Symbol.bcmap</file>
 
+        <file>web/js/mind-elixir/MindElixir.js</file>
+        <file>web/mindmap-editor-template.html</file>
+        <file>web/js/mindmapeditorcore.js</file>
+        <file>web/js/mindmapeditor.js</file>
+
         <file>dicts/en_US.aff</file>
         <file>dicts/en_US.dic</file>
         <file>themes/native/text-editor.theme</file>

+ 4 - 0
src/data/extra/web/js/markjs.js

@@ -12,6 +12,10 @@ class MarkJs {
         this.adapter.on('basicMarkdownRendered', () => {
             this.clearCache();
         });
+
+        this.adapter.on('rendered', () => {
+            this.clearCache();
+        });
     }
 
     // @p_options: {

File diff suppressed because it is too large
+ 0 - 0
src/data/extra/web/js/mind-elixir/MindElixir.js


File diff suppressed because it is too large
+ 0 - 6
src/data/extra/web/js/mind-elixir/MindElixir.min.js


+ 1 - 1
src/data/extra/web/js/mind-elixir/README.md

@@ -1,2 +1,2 @@
 # [mind-elixir](https://github.com/ssshooter/mind-elixir-core)
-v0.19.3
+v1.1.3

File diff suppressed because it is too large
+ 0 - 0
src/data/extra/web/js/mind-elixir/painter.js


+ 33 - 0
src/data/extra/web/js/mindmapeditor.js

@@ -0,0 +1,33 @@
+/* Main script file for MindMapEditor. */
+
+new QWebChannel(qt.webChannelTransport,
+    function(p_channel) {
+        let adapter = p_channel.objects.vxAdapter;
+        // Export the adapter globally.
+        window.vxAdapter = adapter;
+
+        // Connect signals from CPP side.
+        adapter.saveDataRequested.connect(function(p_id) {
+            window.vxcore.saveData(p_id);
+        });
+
+        adapter.dataUpdated.connect(function(p_data) {
+            window.vxcore.setData(p_data);
+        });
+
+        adapter.findTextRequested.connect(function(p_texts, p_options, p_currentMatchLine) {
+            window.vxcore.findText(p_texts, p_options, p_currentMatchLine);
+        });
+
+        console.log('QWebChannel has been set up');
+
+        if (window.vxcore.initialized) {
+            window.vxAdapter.setReady(true);
+        }
+    });
+
+window.vxcore.on('ready', function() {
+    if (window.vxAdapter) {
+        window.vxAdapter.setReady(true);
+    }
+});

+ 38 - 0
src/data/extra/web/js/mindmapeditorcore.js

@@ -0,0 +1,38 @@
+class MindMapEditorCore extends VXCore {
+    constructor() {
+        super();
+    }
+
+    initOnLoad() {
+        let options = {
+          el: '#vx-mindmap',
+          direction: MindElixir.LEFT,
+        }
+
+        this.mind = new MindElixir(options);
+
+        this.mind.bus.addListener('operation', operation => {
+            if (operation === 'beginEdit') {
+                return;
+            }
+            window.vxAdapter.notifyContentsChanged();
+        });
+    }
+
+    saveData(p_id) {
+        let data = this.mind.getAllDataString();
+        window.vxAdapter.setSavedData(p_id, data);
+    }
+
+    setData(p_data) {
+        if (p_data && p_data !== "") {
+            this.mind.init(JSON.parse(p_data));
+        } else {
+            const data = MindElixir.new('New Topic')
+            this.mind.init(data)
+        }
+        this.emit('rendered');
+    }
+}
+
+window.vxcore = new MindMapEditorCore();

+ 33 - 0
src/data/extra/web/mindmap-editor-template.html

@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="utf-8">
+    <title>VNoteX MindMap Viewer</title>
+
+    <style type="text/css">
+    /* VX_GLOBAL_STYLES_PLACEHOLDER */
+        #vx-mindmap {
+            height: 100vh;
+            width: 100%;
+        }
+
+        body {
+            margin: 0px !important;
+            padding: 0px !important;
+        }
+    </style>
+
+    <!-- VX_THEME_STYLES_PLACEHOLDER -->
+
+    <!-- VX_STYLES_PLACEHOLDER -->
+
+    <script type="text/javascript">
+        /* VX_GLOBAL_OPTIONS_PLACEHOLDER */
+    </script>
+
+    <!-- VX_SCRIPTS_PLACEHOLDER -->
+</head>
+<body>
+    <div id="vx-mindmap"></div>
+</body>
+</html>

+ 2 - 2
src/widgets/editors/markdownviewer.cpp

@@ -84,7 +84,7 @@ void MarkdownViewer::setPreviewHelper(PreviewHelper *p_previewHelper)
                                           TimeStamp p_timeStamp,
                                           const QString &p_lang,
                                           const QString &p_text) {
-                if (m_adapter->isViewerReady()) {
+                if (m_adapter->isReady()) {
                     m_adapter->graphPreviewRequested(p_id, p_timeStamp, p_lang, p_text);
                 } else {
                     p_previewHelper->handleGraphPreviewData(MarkdownViewerAdapter::PreviewData());
@@ -94,7 +94,7 @@ void MarkdownViewer::setPreviewHelper(PreviewHelper *p_previewHelper)
             this, [this, p_previewHelper](quint64 p_id,
                                           TimeStamp p_timeStamp,
                                           const QString &p_text) {
-                if (m_adapter->isViewerReady()) {
+                if (m_adapter->isReady()) {
                     m_adapter->mathPreviewRequested(p_id, p_timeStamp, p_text);
                 } else {
                     p_previewHelper->handleMathPreviewData(MarkdownViewerAdapter::PreviewData());

+ 24 - 93
src/widgets/editors/markdownvieweradapter.cpp

@@ -50,16 +50,6 @@ MarkdownViewerAdapter::Heading MarkdownViewerAdapter::Heading::fromJson(const QJ
                    p_obj.value(QStringLiteral("anchor")).toString());
 }
 
-QJsonObject MarkdownViewerAdapter::FindOption::toJson() const
-{
-    QJsonObject obj;
-    obj["findBackward"] = m_findBackward;
-    obj["caseSensitive"] = m_caseSensitive;
-    obj["wholeWordOnly"] = m_wholeWordOnly;
-    obj["regularExpression"] = m_regularExpression;
-    return obj;
-}
-
 MarkdownViewerAdapter::CssRuleStyle MarkdownViewerAdapter::CssRuleStyle::fromJson(const QJsonObject &p_obj)
 {
     CssRuleStyle style;
@@ -90,7 +80,7 @@ QTextCharFormat MarkdownViewerAdapter::CssRuleStyle::toTextCharFormat() const
 }
 
 MarkdownViewerAdapter::MarkdownViewerAdapter(QObject *p_parent)
-    : QObject(p_parent)
+    : WebViewAdapter(p_parent)
 {
 }
 
@@ -108,15 +98,16 @@ void MarkdownViewerAdapter::setText(int p_revision,
         return;
     }
 
-    m_revision = p_revision;
-    if (m_viewerReady) {
+    if (isReady()) {
+        m_revision = p_revision;
         emit textUpdated(p_text);
         scrollToPosition(Position(p_lineNumber, ""));
     } else {
-        m_pendingActions.append([this, p_text, p_lineNumber]() {
-            emit textUpdated(p_text);
-            scrollToPosition(Position(p_lineNumber, ""));
-        });
+        pendAction(std::bind(QOverload<int, const QString &, int>::of(&MarkdownViewerAdapter::setText),
+                             this,
+                             p_revision,
+                             p_text,
+                             p_lineNumber));
     }
 }
 
@@ -125,37 +116,18 @@ void MarkdownViewerAdapter::setText(const QString &p_text, int p_lineNumber)
     setText(0, p_text, p_lineNumber);
 }
 
-void MarkdownViewerAdapter::setReady(bool p_ready)
-{
-    if (m_viewerReady == p_ready) {
-        return;
-    }
-
-    m_viewerReady = p_ready;
-    if (m_viewerReady) {
-        for (auto &act : m_pendingActions) {
-            act();
-        }
-        m_pendingActions.clear();
-        emit viewerReady();
-    }
-}
-
 void MarkdownViewerAdapter::scrollToLine(int p_lineNumber)
 {
     if (p_lineNumber == -1) {
         return;
     }
 
-    if (!m_viewerReady) {
-        m_pendingActions.append([this, p_lineNumber]() {
-            scrollToPosition(Position(p_lineNumber, ""));
-        });
-        return;
+    if (isReady()) {
+        m_topLineNumber = p_lineNumber;
+        emit editLineNumberUpdated(p_lineNumber);
+    } else {
+        pendAction(std::bind(&MarkdownViewerAdapter::scrollToLine, this, p_lineNumber));
     }
-
-    m_topLineNumber = p_lineNumber;
-    emit editLineNumberUpdated(p_lineNumber);
 }
 
 void MarkdownViewerAdapter::setTopLineNumber(int p_lineNumber)
@@ -196,11 +168,6 @@ void MarkdownViewerAdapter::setGraphPreviewData(quint64 p_id,
     emit graphPreviewDataReady(PreviewData(p_id, p_timeStamp, p_format, ba, p_needScale));
 }
 
-bool MarkdownViewerAdapter::isViewerReady() const
-{
-    return m_viewerReady;
-}
-
 void MarkdownViewerAdapter::setMathPreviewData(quint64 p_id,
                                                quint64 p_timeStamp,
                                                const QString &p_format,
@@ -272,7 +239,7 @@ void MarkdownViewerAdapter::scrollToAnchor(const QString &p_anchor)
     if (p_anchor.isEmpty()) {
         return;
     }
-    Q_ASSERT(m_viewerReady);
+    Q_ASSERT(isReady());
     m_currentHeadingIndex = -1;
     emit anchorScrollRequested(p_anchor);
 }
@@ -340,38 +307,6 @@ void MarkdownViewerAdapter::setCrossCopyResult(quint64 p_id, quint64 p_timeStamp
     emit crossCopyReady(p_id, p_timeStamp, p_html);
 }
 
-void MarkdownViewerAdapter::findText(const QStringList &p_texts, FindOptions p_options, int p_currentMatchLine)
-{
-    FindOption opts;
-    if (p_options & vnotex::FindOption::FindBackward) {
-        opts.m_findBackward = true;
-    }
-    if (p_options & vnotex::FindOption::CaseSensitive) {
-        opts.m_caseSensitive = true;
-    }
-    if (p_options & vnotex::FindOption::WholeWordOnly) {
-        opts.m_wholeWordOnly = true;
-    }
-    if (p_options & vnotex::FindOption::RegularExpression) {
-        opts.m_regularExpression = true;
-    }
-
-    if (m_viewerReady) {
-        emit findTextRequested(p_texts, opts.toJson(), p_currentMatchLine);
-    } else {
-        m_pendingActions.append([this, p_texts, opts, p_currentMatchLine]() {
-            // FIXME: highlights will be clear once the page is ready. Add a delay here.
-            Utils::sleepWait(1000);
-            emit findTextRequested(p_texts, opts.toJson(), p_currentMatchLine);
-        });
-    }
-}
-
-void MarkdownViewerAdapter::setFindText(const QStringList &p_texts, int p_totalMatches, int p_currentMatchIndex)
-{
-    emit findTextReady(p_texts, p_totalMatches, p_currentMatchIndex);
-}
-
 void MarkdownViewerAdapter::setWorkFinished()
 {
     emit workFinished();
@@ -393,8 +328,7 @@ void MarkdownViewerAdapter::setSavedContent(const QString &p_headContent,
 void MarkdownViewerAdapter::reset()
 {
     m_revision = 0;
-    m_viewerReady = false;
-    m_pendingActions.clear();
+    setReady(false);
     m_topLineNumber = -1;
     m_headings.clear();
     m_currentHeadingIndex = -1;
@@ -437,12 +371,10 @@ void MarkdownViewerAdapter::renderGraph(quint64 p_id,
 
 void MarkdownViewerAdapter::highlightCodeBlock(int p_idx, quint64 p_timeStamp, const QString &p_text)
 {
-    if (m_viewerReady) {
+    if (isReady()) {
         emit highlightCodeBlockRequested(p_idx, p_timeStamp, p_text);
     } else {
-        m_pendingActions.append([this, p_idx, p_timeStamp, p_text]() {
-            emit highlightCodeBlockRequested(p_idx, p_timeStamp, p_text);
-        });
+        pendAction(std::bind(&MarkdownViewerAdapter::highlightCodeBlock, this, p_idx, p_timeStamp, p_text));
     }
 }
 
@@ -454,24 +386,23 @@ void MarkdownViewerAdapter::setStyleSheetStyles(quint64 p_id, const QJsonArray &
         ruleStyles.push_back(CssRuleStyle::fromJson(p_styles[i].toObject()));
     }
 
-    m_callbackPool.call(p_id, &ruleStyles);
+    invokeCallback(p_id, &ruleStyles);
 }
 
 void MarkdownViewerAdapter::fetchStylesFromStyleSheet(const QString &p_styleSheet,
                                                       const std::function<void(const QVector<CssRuleStyle> *)> &p_callback)
 {
     if (p_styleSheet.isEmpty()) {
+        p_callback(nullptr);
         return;
     }
 
-    const quint64 id = m_callbackPool.add([p_callback](void *data) {
-        p_callback(reinterpret_cast<const QVector<CssRuleStyle> *>(data));
-    });
-    if (m_viewerReady) {
+    if (isReady()) {
+        const quint64 id = addCallback([p_callback](void *data) {
+            p_callback(reinterpret_cast<const QVector<CssRuleStyle> *>(data));
+        });
         emit parseStyleSheetRequested(id, p_styleSheet);
     } else {
-        m_pendingActions.append([this, p_styleSheet, id]() {
-            emit parseStyleSheetRequested(id, p_styleSheet);
-        });
+        pendAction(std::bind(&MarkdownViewerAdapter::fetchStylesFromStyleSheet, this, p_styleSheet, p_callback));
     }
 }

+ 3 - 38
src/widgets/editors/markdownvieweradapter.h

@@ -1,7 +1,8 @@
 #ifndef MARKDOWNVIEWERADAPTER_H
 #define MARKDOWNVIEWERADAPTER_H
 
-#include <QObject>
+#include "webviewadapter.h"
+
 #include <QString>
 #include <QJsonObject>
 #include <QScopedPointer>
@@ -9,12 +10,11 @@
 #include <QTextCharFormat>
 
 #include <core/global.h>
-#include <utils/callbackpool.h>
 
 namespace vnotex
 {
     // Adapter and interface between CPP and JS.
-    class MarkdownViewerAdapter : public QObject
+    class MarkdownViewerAdapter : public WebViewAdapter
     {
         Q_OBJECT
     public:
@@ -67,19 +67,6 @@ namespace vnotex
             QString m_anchor;
         };
 
-        struct FindOption
-        {
-            QJsonObject toJson() const;
-
-            bool m_findBackward = false;
-
-            bool m_caseSensitive = false;
-
-            bool m_wholeWordOnly = false;
-
-            bool m_regularExpression = false;
-        };
-
         struct CssRuleStyle
         {
             QTextCharFormat toTextCharFormat() const;
@@ -113,8 +100,6 @@ namespace vnotex
 
         int getTopLineNumber() const;
 
-        bool isViewerReady() const;
-
         const QVector<MarkdownViewerAdapter::Heading> &getHeadings() const;
         int getCurrentHeadingIndex() const;
 
@@ -126,8 +111,6 @@ namespace vnotex
 
         QString getCrossCopyTargetDisplayName(const QString &p_target) const;
 
-        void findText(const QStringList &p_texts, FindOptions p_options, int p_currentMatchLine = -1);
-
         void saveContent();
 
         // Should be called before WebViewer.setHtml().
@@ -141,8 +124,6 @@ namespace vnotex
 
         // Functions to be called from web side.
     public slots:
-        void setReady(bool p_ready);
-
         void setWorkFinished();
 
         // The line number at the top.
@@ -183,8 +164,6 @@ namespace vnotex
 
         void setCrossCopyResult(quint64 p_id, quint64 p_timeStamp, const QString &p_html);
 
-        void setFindText(const QStringList &p_texts, int p_totalMatches, int p_currentMatchIndex);
-
         void setSavedContent(const QString &p_headContent, const QString &p_styleContent, const QString &p_content, const QString &p_bodyClassList);
 
         // Call local CPP code to render graph.
@@ -227,8 +206,6 @@ namespace vnotex
                                 const QString &p_baseUrl,
                                 const QString &p_html);
 
-        void findTextRequested(const QStringList &p_texts, const QJsonObject &p_options, int p_currentMatchLine);
-
         // Request to get the whole HTML content.
         void contentRequested();
 
@@ -247,8 +224,6 @@ namespace vnotex
 
         void mathPreviewDataReady(const PreviewData &p_data);
 
-        void viewerReady();
-
         // All rendering work has finished.
         void workFinished();
 
@@ -264,8 +239,6 @@ namespace vnotex
 
         void crossCopyReady(quint64 p_id, quint64 p_timeStamp, const QString &p_html);
 
-        void findTextReady(const QStringList &p_texts, int p_totalMatches, int p_currentMatchIndex);
-
         void contentReady(const QString &p_headContent,
                           const QString &p_styleContent,
                           const QString &p_content,
@@ -280,12 +253,6 @@ namespace vnotex
 
         int m_revision = 0;
 
-        // Whether web side viewer is ready to handle text update.
-        bool m_viewerReady = false;
-
-        // Pending actions for the viewer once it is ready.
-        QVector<std::function<void()>> m_pendingActions;
-
         // Source line number of the top element node at web side.
         int m_topLineNumber = -1;
 
@@ -296,8 +263,6 @@ namespace vnotex
 
         // Targets supported by cross copy. Set by web.
         QStringList m_crossCopyTargets;
-
-        CallbackPool m_callbackPool;
     };
 }
 

+ 44 - 0
src/widgets/editors/mindmapeditor.cpp

@@ -0,0 +1,44 @@
+#include "mindmapeditor.h"
+
+#include <QWebChannel>
+
+#include "mindmapeditoradapter.h"
+
+using namespace vnotex;
+
+MindMapEditor::MindMapEditor(MindMapEditorAdapter *p_adapter,
+                            const QColor &p_background,
+                            qreal p_zoomFactor,
+                            QWidget *p_parent)
+    : WebViewer(p_background, p_zoomFactor, p_parent),
+      m_adapter(p_adapter)
+{
+    setAcceptDrops(true);
+
+    m_adapter->setParent(this);
+    connect(m_adapter, &MindMapEditorAdapter::contentsChanged,
+            this, [this]() {
+                m_modified = true;
+                emit contentsChanged();
+            });
+
+    auto channel = new QWebChannel(this);
+    channel->registerObject(QStringLiteral("vxAdapter"), m_adapter);
+
+    page()->setWebChannel(channel);
+}
+
+MindMapEditorAdapter *MindMapEditor::adapter() const
+{
+    return m_adapter;
+}
+
+void MindMapEditor::setModified(bool p_modified)
+{
+    m_modified = p_modified;
+}
+
+bool MindMapEditor::isModified() const
+{
+    return m_modified;
+}

+ 35 - 0
src/widgets/editors/mindmapeditor.h

@@ -0,0 +1,35 @@
+#ifndef MINDMAPEDITOR_H
+#define MINDMAPEDITOR_H
+
+#include "../webviewer.h"
+
+namespace vnotex
+{
+    class MindMapEditorAdapter;
+
+    class MindMapEditor : public WebViewer
+    {
+        Q_OBJECT
+    public:
+        MindMapEditor(MindMapEditorAdapter *p_adapter,
+                      const QColor &p_background,
+                      qreal p_zoomFactor,
+                      QWidget *p_parent = nullptr);
+
+        MindMapEditorAdapter *adapter() const;
+
+        void setModified(bool p_modified);
+        bool isModified() const;
+
+    signals:
+        void contentsChanged();
+
+    private:
+        // Managed by QObject.
+        MindMapEditorAdapter *m_adapter = nullptr;
+
+        bool m_modified = false;
+    };
+}
+
+#endif // MINDMAPEDITOR_H

+ 39 - 0
src/widgets/editors/mindmapeditoradapter.cpp

@@ -0,0 +1,39 @@
+#include "mindmapeditoradapter.h"
+
+using namespace vnotex;
+
+MindMapEditorAdapter::MindMapEditorAdapter(QObject *p_parent)
+    : WebViewAdapter(p_parent)
+{
+}
+
+void MindMapEditorAdapter::setData(const QString &p_data)
+{
+    if (isReady()) {
+        emit dataUpdated(p_data);
+    } else {
+        pendAction(std::bind(&MindMapEditorAdapter::setData, this, p_data));
+    }
+}
+
+void MindMapEditorAdapter::saveData(const std::function<void(const QString &)> &p_callback)
+{
+    if (isReady()) {
+        const quint64 id = addCallback([p_callback](void *data) {
+            p_callback(*reinterpret_cast<const QString *>(data));
+        });
+        emit saveDataRequested(id);
+    } else {
+        pendAction(std::bind(&MindMapEditorAdapter::saveData, this, p_callback));
+    }
+}
+
+void MindMapEditorAdapter::setSavedData(quint64 p_id, const QString &p_data)
+{
+    invokeCallback(p_id, (void *)&p_data);
+}
+
+void MindMapEditorAdapter::notifyContentsChanged()
+{
+    emit contentsChanged();
+}

+ 45 - 0
src/widgets/editors/mindmapeditoradapter.h

@@ -0,0 +1,45 @@
+#ifndef MINDMAPEDITORADAPTER_H
+#define MINDMAPEDITORADAPTER_H
+
+#include "webviewadapter.h"
+
+#include <QString>
+#include <QJsonObject>
+
+#include <core/global.h>
+
+namespace vnotex
+{
+    // Adapter and interface between CPP and JS for MindMap.
+    class MindMapEditorAdapter : public WebViewAdapter
+    {
+        Q_OBJECT
+    public:
+        explicit MindMapEditorAdapter(QObject *p_parent = nullptr);
+
+        ~MindMapEditorAdapter() = default;
+
+        void setData(const QString &p_data);
+
+        void saveData(const std::function<void(const QString &)> &p_callback);
+
+        // Functions to be called from web side.
+    public slots:
+        void setSavedData(quint64 p_id, const QString &p_data);
+
+        void notifyContentsChanged();
+
+        // Signals to be connected at web side.
+    signals:
+        void dataUpdated(const QString& p_data);
+
+        void saveDataRequested(quint64 p_id);
+
+    signals:
+        void contentsChanged();
+
+    private:
+    };
+}
+
+#endif // MINDMAPEDITORADAPTER_H

+ 0 - 1
src/widgets/editors/pdfviewer.cpp

@@ -3,7 +3,6 @@
 #include <QWebChannel>
 
 #include "pdfvieweradapter.h"
-#include "previewhelper.h"
 
 using namespace vnotex;
 

+ 3 - 20
src/widgets/editors/pdfvieweradapter.cpp

@@ -3,7 +3,7 @@
 using namespace vnotex;
 
 PdfViewerAdapter::PdfViewerAdapter(QObject *p_parent)
-    : QObject(p_parent)
+    : WebViewAdapter(p_parent)
 {
 }
 
@@ -11,26 +11,9 @@ void PdfViewerAdapter::setUrl(const QString &p_url)
 {
     // TODO: Not supported yet.
     Q_ASSERT(false);
-    if (m_viewerReady) {
+    if (isReady()) {
         emit urlUpdated(p_url);
     } else {
-        m_pendingActions.append([this, p_url]() {
-            emit urlUpdated(p_url);
-        });
-    }
-}
-
-void PdfViewerAdapter::setReady(bool p_ready)
-{
-    if (m_viewerReady == p_ready) {
-        return;
-    }
-
-    m_viewerReady = p_ready;
-    if (m_viewerReady) {
-        for (auto &act : m_pendingActions) {
-            act();
-        }
-        m_pendingActions.clear();
+        pendAction(std::bind(&PdfViewerAdapter::setUrl, this, p_url));
     }
 }

+ 2 - 14
src/widgets/editors/pdfvieweradapter.h

@@ -1,16 +1,12 @@
 #ifndef PDFVIEWERADAPTER_H
 #define PDFVIEWERADAPTER_H
 
-#include <QObject>
-#include <QString>
-#include <QJsonObject>
-
-#include <core/global.h>
+#include "webviewadapter.h"
 
 namespace vnotex
 {
     // Adapter and interface between CPP and JS for PDF.
-    class PdfViewerAdapter : public QObject
+    class PdfViewerAdapter : public WebViewAdapter
     {
         Q_OBJECT
     public:
@@ -22,18 +18,10 @@ namespace vnotex
 
         // Functions to be called from web side.
     public slots:
-        void setReady(bool p_ready);
 
         // Signals to be connected at web side.
     signals:
         void urlUpdated(const QString &p_url);
-
-    private:
-        // Whether web side viewer is ready to handle url update.
-        bool m_viewerReady = false;
-
-        // Pending actions for the viewer once it is ready.
-        QVector<std::function<void()>> m_pendingActions;
     };
 }
 

+ 92 - 0
src/widgets/editors/webviewadapter.cpp

@@ -0,0 +1,92 @@
+#include "webviewadapter.h"
+
+#include <utils/utils.h>
+
+using namespace vnotex;
+
+QJsonObject WebViewAdapter::FindOption::toJson() const
+{
+    QJsonObject obj;
+    obj["findBackward"] = m_findBackward;
+    obj["caseSensitive"] = m_caseSensitive;
+    obj["wholeWordOnly"] = m_wholeWordOnly;
+    obj["regularExpression"] = m_regularExpression;
+    return obj;
+}
+
+WebViewAdapter::WebViewAdapter(QObject *p_parent)
+    : QObject(p_parent)
+{
+}
+
+void WebViewAdapter::setReady(bool p_ready)
+{
+    if (m_ready == p_ready) {
+        return;
+    }
+
+    m_ready = p_ready;
+    if (m_ready) {
+        for (auto &act : m_pendingActions) {
+            act();
+        }
+        m_pendingActions.clear();
+        emit ready();
+    } else {
+        m_pendingActions.clear();
+    }
+}
+
+void WebViewAdapter::pendAction(const std::function<void()> &p_func)
+{
+    Q_ASSERT(!m_ready);
+    m_pendingActions.append(p_func);
+}
+
+bool WebViewAdapter::isReady() const
+{
+    return m_ready;
+}
+
+void WebViewAdapter::invokeCallback(quint64 p_id, void *p_data)
+{
+    m_callbackPool.call(p_id, p_data);
+}
+
+quint64 WebViewAdapter::addCallback(const CallbackPool::Callback &p_callback)
+{
+    return m_callbackPool.add(p_callback);
+}
+
+void WebViewAdapter::findText(const QStringList &p_texts, FindOptions p_options, int p_currentMatchLine)
+{
+    FindOption opts;
+    if (p_options & vnotex::FindOption::FindBackward) {
+        opts.m_findBackward = true;
+    }
+    if (p_options & vnotex::FindOption::CaseSensitive) {
+        opts.m_caseSensitive = true;
+    }
+    if (p_options & vnotex::FindOption::WholeWordOnly) {
+        opts.m_wholeWordOnly = true;
+    }
+    if (p_options & vnotex::FindOption::RegularExpression) {
+        opts.m_regularExpression = true;
+    }
+
+    if (isReady()) {
+        emit findTextRequested(p_texts, opts.toJson(), p_currentMatchLine);
+    } else {
+        pendAction([this, p_texts, opts, p_currentMatchLine]() {
+            // FIXME: highlights will be clear once the page is ready. Add a delay here.
+            Utils::sleepWait(1000);
+            emit findTextRequested(p_texts, opts.toJson(), p_currentMatchLine);
+        });
+    }
+}
+
+void WebViewAdapter::setFindText(const QStringList &p_texts, int p_totalMatches, int p_currentMatchIndex)
+{
+    emit findTextReady(p_texts, p_totalMatches, p_currentMatchIndex);
+}
+

+ 71 - 0
src/widgets/editors/webviewadapter.h

@@ -0,0 +1,71 @@
+#ifndef WEBVIEWADAPTER_H
+#define WEBVIEWADAPTER_H
+
+#include <QObject>
+
+#include <QVector>
+
+#include <utils/callbackpool.h>
+#include <core/global.h>
+
+namespace vnotex
+{
+    // Base class of adapter and interface between CPP and JS for WebView.
+    class WebViewAdapter : public QObject
+    {
+        Q_OBJECT
+    public:
+        explicit WebViewAdapter(QObject *p_parent = nullptr);
+
+        bool isReady() const;
+
+        void findText(const QStringList &p_texts, FindOptions p_options, int p_currentMatchLine = -1);
+
+        // Functions to be called from web side.
+    public slots:
+        void setReady(bool p_ready);
+
+        void setFindText(const QStringList &p_texts, int p_totalMatches, int p_currentMatchIndex);
+
+        // Signals to be connected at cpp side.
+    signals:
+        void ready();
+
+        void findTextReady(const QStringList &p_texts, int p_totalMatches, int p_currentMatchIndex);
+
+        // Signals to be connected at web side.
+    signals:
+        void findTextRequested(const QStringList &p_texts, const QJsonObject &p_options, int p_currentMatchLine);
+
+    protected:
+        void pendAction(const std::function<void()> &p_func);
+
+        void invokeCallback(quint64 p_id, void *p_data);
+
+        quint64 addCallback(const CallbackPool::Callback &p_callback);
+
+    private:
+        struct FindOption
+        {
+            QJsonObject toJson() const;
+
+            bool m_findBackward = false;
+
+            bool m_caseSensitive = false;
+
+            bool m_wholeWordOnly = false;
+
+            bool m_regularExpression = false;
+        };
+
+        // Whether web side is ready.
+        bool m_ready = false;
+
+        // Pending actions for the editor once it is ready.
+        QVector<std::function<void()>> m_pendingActions;
+
+        CallbackPool m_callbackPool;
+    };
+}
+
+#endif // WEBVIEWADAPTER_H

+ 16 - 0
src/widgets/findandreplacewidget.cpp

@@ -325,3 +325,19 @@ FindOptions FindAndReplaceWidget::getOptions() const
 {
     return m_options;
 }
+
+void FindAndReplaceWidget::setOptionsEnabled(FindOptions p_options, bool p_enabled)
+{
+    if (p_options & FindOption::CaseSensitive) {
+        m_caseSensitiveCheckBox->setEnabled(p_enabled);
+    }
+    if (p_options & FindOption::WholeWordOnly) {
+        m_wholeWordOnlyCheckBox->setEnabled(p_enabled);
+    }
+    if (p_options & FindOption::RegularExpression) {
+        m_regularExpressionCheckBox->setEnabled(p_enabled);
+    }
+    if (p_options & FindOption::IncrementalSearch) {
+        m_incrementalSearchCheckBox->setEnabled(p_enabled);
+    }
+}

+ 2 - 0
src/widgets/findandreplacewidget.h

@@ -29,6 +29,8 @@ namespace vnotex
 
         FindOptions getOptions() const;
 
+        void setOptionsEnabled(FindOptions p_options, bool p_enabled);
+
     signals:
         void findTextChanged(const QString &p_text, FindOptions p_options);
 

+ 3 - 3
src/widgets/markdownviewwindow.cpp

@@ -140,7 +140,7 @@ void MarkdownViewWindow::setModeInternal(ViewWindowMode p_mode, bool p_syncBuffe
                 setupViewer();
 
                 // Must show the viewer to let it init with the correct DPI.
-                // Will hide it when viewerReady().
+                // Will hide it when ready().
                 m_viewer->show();
             }
 
@@ -361,7 +361,7 @@ void MarkdownViewWindow::setupTextEditor()
     updateEditorFromConfig();
 
     // Connect viewer and editor.
-    connect(adapter(), &MarkdownViewerAdapter::viewerReady,
+    connect(adapter(), &MarkdownViewerAdapter::ready,
             m_editor->getHighlighter(), &vte::PegMarkdownHighlighter::updateHighlight);
     connect(m_editor, &MarkdownEditor::htmlToMarkdownRequested,
             adapter(), &MarkdownViewerAdapter::htmlToMarkdownRequested);
@@ -494,7 +494,7 @@ void MarkdownViewWindow::setupViewer()
             this, [this](const QStringList &p_texts, int p_totalMatches, int p_currentMatchIndex) {
                 this->showFindResult(p_texts, p_totalMatches, p_currentMatchIndex);
             });
-    connect(adapter, &MarkdownViewerAdapter::viewerReady,
+    connect(adapter, &MarkdownViewerAdapter::ready,
             this, [this]() {
                 m_viewerReady = true;
 

+ 292 - 0
src/widgets/mindmapviewwindow.cpp

@@ -0,0 +1,292 @@
+#include "mindmapviewwindow.h"
+
+#include <QToolBar>
+#include <QSplitter>
+
+#include <core/vnotex.h>
+#include <core/thememgr.h>
+#include <core/htmltemplatehelper.h>
+#include <core/configmgr.h>
+#include <core/editorconfig.h>
+#include <core/mindmapeditorconfig.h>
+#include <utils/utils.h>
+#include <utils/pathutils.h>
+
+#include "toolbarhelper.h"
+#include "findandreplacewidget.h"
+#include "editors/mindmapeditor.h"
+#include "editors/mindmapeditoradapter.h"
+
+using namespace vnotex;
+
+MindMapViewWindow::MindMapViewWindow(QWidget *p_parent)
+    : ViewWindow(p_parent)
+{
+    m_mode = ViewWindowMode::Edit;
+    setupUI();
+}
+
+void MindMapViewWindow::setupUI()
+{
+    setupEditor();
+    setCentralWidget(m_editor);
+
+    setupToolBar();
+}
+
+void MindMapViewWindow::setupEditor()
+{
+    Q_ASSERT(!m_editor);
+
+    const auto &editorConfig = ConfigMgr::getInst().getEditorConfig();
+    const auto &mindMapEditorConfig = editorConfig.getMindMapEditorConfig();
+
+    updateConfigRevision();
+
+    HtmlTemplateHelper::updateMindMapEditorTemplate(mindMapEditorConfig);
+
+    auto adapter = new MindMapEditorAdapter(nullptr);
+    m_editor = new MindMapEditor(adapter,
+                                 VNoteX::getInst().getThemeMgr().getBaseBackground(),
+                                 1.0,
+                                 this);
+    connect(m_editor, &MindMapEditor::contentsChanged,
+            this, [this]() {
+                getBuffer()->setModified(m_editor->isModified());
+                getBuffer()->invalidateContent(
+                    this, [this](int p_revision) {
+                        this->setBufferRevisionAfterInvalidation(p_revision);
+                    });
+            });
+}
+
+QString MindMapViewWindow::getLatestContent() const
+{
+    QString content;
+    adapter()->saveData([&content](const QString &p_data) {
+        content = p_data;
+    });
+
+    while (content.isNull()) {
+        Utils::sleepWait(50);
+    }
+
+    return content;
+}
+
+QString MindMapViewWindow::selectedText() const
+{
+    return m_editor->selectedText();
+}
+
+void MindMapViewWindow::setMode(ViewWindowMode p_mode)
+{
+    Q_UNUSED(p_mode);
+    Q_ASSERT(false);
+}
+
+void MindMapViewWindow::openTwice(const QSharedPointer<FileOpenParameters> &p_paras)
+{
+    Q_UNUSED(p_paras);
+}
+
+ViewWindowSession MindMapViewWindow::saveSession() const
+{
+    auto session = ViewWindow::saveSession();
+    return session;
+}
+
+void MindMapViewWindow::applySnippet(const QString &p_name)
+{
+    Q_UNUSED(p_name);
+}
+
+void MindMapViewWindow::applySnippet()
+{
+}
+
+void MindMapViewWindow::fetchWordCountInfo(const std::function<void(const WordCountInfo &)> &p_callback) const
+{
+    Q_UNUSED(p_callback);
+}
+
+void MindMapViewWindow::handleEditorConfigChange()
+{
+    if (updateConfigRevision()) {
+        const auto &editorConfig = ConfigMgr::getInst().getEditorConfig();
+        const auto &mindMapEditorConfig = editorConfig.getMindMapEditorConfig();
+
+        HtmlTemplateHelper::updateMindMapEditorTemplate(mindMapEditorConfig);
+    }
+}
+
+void MindMapViewWindow::setModified(bool p_modified)
+{
+    m_editor->setModified(p_modified);
+}
+
+void MindMapViewWindow::print()
+{
+}
+
+void MindMapViewWindow::syncEditorFromBuffer()
+{
+    auto buffer = getBuffer();
+    if (buffer) {
+        m_editor->setHtml(HtmlTemplateHelper::getMindMapEditorTemplate(),
+                          PathUtils::pathToUrl(buffer->getContentPath()));
+        adapter()->setData(buffer->getContent());
+        m_editor->setModified(buffer->isModified());
+    } else {
+        m_editor->setHtml("");
+        adapter()->setData("");
+        m_editor->setModified(false);
+    }
+
+    m_bufferRevision = buffer ? buffer->getRevision() : 0;
+}
+
+void MindMapViewWindow::syncEditorFromBufferContent()
+{
+    auto buffer = getBuffer();
+    Q_ASSERT(buffer);
+    adapter()->setData(buffer->getContent());
+    m_editor->setModified(buffer->isModified());
+    m_bufferRevision = buffer->getRevision();
+}
+
+void MindMapViewWindow::scrollUp()
+{
+}
+
+void MindMapViewWindow::scrollDown()
+{
+}
+
+void MindMapViewWindow::zoom(bool p_zoomIn)
+{
+    Q_UNUSED(p_zoomIn);
+}
+
+MindMapEditorAdapter *MindMapViewWindow::adapter() const
+{
+    if (m_editor) {
+        return dynamic_cast<MindMapEditorAdapter *>(m_editor->adapter());
+    }
+
+    return nullptr;
+}
+
+bool MindMapViewWindow::updateConfigRevision()
+{
+    bool changed = false;
+
+    const auto &editorConfig = ConfigMgr::getInst().getEditorConfig();
+
+    if (m_editorConfigRevision != editorConfig.revision()) {
+        changed = true;
+        m_editorConfigRevision = editorConfig.revision();
+    }
+
+    if (m_editorConfigRevision != editorConfig.getMindMapEditorConfig().revision()) {
+        changed = true;
+        m_editorConfigRevision = editorConfig.getMindMapEditorConfig().revision();
+    }
+
+    return changed;
+}
+
+void MindMapViewWindow::setupToolBar()
+{
+    auto toolBar = createToolBar(this);
+    addToolBar(toolBar);
+
+    addAction(toolBar, ViewWindowToolBarHelper::Save);
+
+    toolBar->addSeparator();
+
+    addAction(toolBar, ViewWindowToolBarHelper::Attachment);
+
+    addAction(toolBar, ViewWindowToolBarHelper::Tag);
+
+    ToolBarHelper::addSpacer(toolBar);
+
+    addAction(toolBar, ViewWindowToolBarHelper::FindAndReplace);
+
+    addAction(toolBar, ViewWindowToolBarHelper::Debug);
+}
+
+void MindMapViewWindow::toggleDebug()
+{
+    if (m_debugViewer) {
+        bool shouldEnable = !m_debugViewer->isVisible();
+        m_debugViewer->setVisible(shouldEnable);
+        m_editor->page()->setDevToolsPage(shouldEnable ? m_debugViewer->page() : nullptr);
+    } else {
+        setupDebugViewer();
+        m_editor->page()->setDevToolsPage(m_debugViewer->page());
+    }
+}
+
+void MindMapViewWindow::setupDebugViewer()
+{
+    Q_ASSERT(!m_debugViewer);
+
+    // Need a vertical QSplitter to hold the original QSplitter and the debug viewer.
+    auto mainSplitter = new QSplitter(this);
+    mainSplitter->setContentsMargins(0, 0, 0, 0);
+    mainSplitter->setOrientation(Qt::Vertical);
+
+    replaceCentralWidget(mainSplitter);
+
+    mainSplitter->addWidget(m_editor);
+    mainSplitter->setFocusProxy(m_editor);
+
+    m_debugViewer = new WebViewer(VNoteX::getInst().getThemeMgr().getBaseBackground(), this);
+    m_debugViewer->resize(m_editor->width(), m_editor->height() / 2);
+    mainSplitter->addWidget(m_debugViewer);
+}
+
+void MindMapViewWindow::handleFindTextChanged(const QString &p_text, FindOptions p_options)
+{
+    if (p_options & FindOption::IncrementalSearch) {
+        m_editor->findText(p_text, p_options);
+    }
+}
+
+void MindMapViewWindow::handleFindNext(const QStringList &p_texts, FindOptions p_options)
+{
+    // We do not use mark.js for searching as the contents are mainly SVG.
+    m_editor->findText(p_texts.empty() ? QString() : p_texts[0], p_options);
+}
+
+void MindMapViewWindow::handleReplace(const QString &p_text, FindOptions p_options, const QString &p_replaceText)
+{
+    Q_UNUSED(p_text);
+    Q_UNUSED(p_options);
+    Q_UNUSED(p_replaceText);
+    showMessage(tr("Replace is not supported yet"));
+}
+
+void MindMapViewWindow::handleReplaceAll(const QString &p_text, FindOptions p_options, const QString &p_replaceText)
+{
+    Q_UNUSED(p_text);
+    Q_UNUSED(p_options);
+    Q_UNUSED(p_replaceText);
+    showMessage(tr("Replace is not supported yet"));
+}
+
+void MindMapViewWindow::handleFindAndReplaceWidgetClosed()
+{
+    m_editor->findText(QString(), FindOption::FindNone);
+}
+
+void MindMapViewWindow::showFindAndReplaceWidget()
+{
+    bool isFirstTime = !m_findAndReplace;
+    ViewWindow::showFindAndReplaceWidget();
+    if (isFirstTime) {
+        m_findAndReplace->setReplaceEnabled(false);
+        m_findAndReplace->setOptionsEnabled(FindOption::WholeWordOnly | FindOption::RegularExpression, false);
+    }
+}

+ 93 - 0
src/widgets/mindmapviewwindow.h

@@ -0,0 +1,93 @@
+#ifndef MINDMAPVIEWWINDOW_H
+#define MINDMAPVIEWWINDOW_H
+
+#include "viewwindow.h"
+
+#include <QScopedPointer>
+
+class QWebEngineView;
+
+namespace vnotex
+{
+    class MindMapEditor;
+    class MindMapEditorAdapter;
+
+    class MindMapViewWindow : public ViewWindow
+    {
+        Q_OBJECT
+    public:
+        explicit MindMapViewWindow(QWidget *p_parent = nullptr);
+
+        QString getLatestContent() const Q_DECL_OVERRIDE;
+
+        QString selectedText() const Q_DECL_OVERRIDE;
+
+        void setMode(ViewWindowMode p_mode) Q_DECL_OVERRIDE;
+
+        void openTwice(const QSharedPointer<FileOpenParameters> &p_paras) Q_DECL_OVERRIDE;
+
+        ViewWindowSession saveSession() const Q_DECL_OVERRIDE;
+
+        void applySnippet(const QString &p_name) Q_DECL_OVERRIDE;
+
+        void applySnippet() Q_DECL_OVERRIDE;
+
+        void fetchWordCountInfo(const std::function<void(const WordCountInfo &)> &p_callback) const Q_DECL_OVERRIDE;
+
+    public slots:
+        void handleEditorConfigChange() Q_DECL_OVERRIDE;
+
+    protected slots:
+        void setModified(bool p_modified) Q_DECL_OVERRIDE;
+
+        void print() Q_DECL_OVERRIDE;
+
+        void toggleDebug() Q_DECL_OVERRIDE;
+
+        void handleFindTextChanged(const QString &p_text, FindOptions p_options) Q_DECL_OVERRIDE;
+
+        void handleFindNext(const QStringList &p_texts, FindOptions p_options) Q_DECL_OVERRIDE;
+
+        void handleReplace(const QString &p_text, FindOptions p_options, const QString &p_replaceText) Q_DECL_OVERRIDE;
+
+        void handleReplaceAll(const QString &p_text, FindOptions p_options, const QString &p_replaceText) Q_DECL_OVERRIDE;
+
+        void handleFindAndReplaceWidgetClosed() Q_DECL_OVERRIDE;
+
+        void showFindAndReplaceWidget() Q_DECL_OVERRIDE;
+
+    protected:
+        void syncEditorFromBuffer() Q_DECL_OVERRIDE;
+
+        void syncEditorFromBufferContent() Q_DECL_OVERRIDE;
+
+        void scrollUp() Q_DECL_OVERRIDE;
+
+        void scrollDown() Q_DECL_OVERRIDE;
+
+        void zoom(bool p_zoomIn) Q_DECL_OVERRIDE;
+
+    private:
+        void setupUI();
+
+        void setupToolBar();
+
+        void setupEditor();
+
+        MindMapEditorAdapter *adapter() const;
+
+        bool updateConfigRevision();
+
+        void setupDebugViewer();
+
+        // Managed by QObject.
+        MindMapEditor *m_editor = nullptr;
+
+        // Used to debug web view.
+        QWebEngineView *m_debugViewer = nullptr;
+
+        int m_editorConfigRevision = 0;
+    };
+}
+
+#endif // MINDMAPVIEWWINDOW_H

+ 10 - 1
src/widgets/pdfviewwindow.cpp

@@ -24,6 +24,16 @@ void PdfViewWindow::setupUI()
 {
     setupViewer();
     setCentralWidget(m_viewer);
+
+    setupToolBar();
+}
+
+void PdfViewWindow::setupToolBar()
+{
+    auto toolBar = createToolBar(this);
+    addToolBar(toolBar);
+
+    addAction(toolBar, ViewWindowToolBarHelper::Tag);
 }
 
 void PdfViewWindow::setupViewer()
@@ -68,7 +78,6 @@ void PdfViewWindow::openTwice(const QSharedPointer<FileOpenParameters> &p_paras)
 ViewWindowSession PdfViewWindow::saveSession() const
 {
     auto session = ViewWindow::saveSession();
-    session.m_lineNumber = 1;
     return session;
 }
 

+ 2 - 1
src/widgets/pdfviewwindow.h

@@ -11,7 +11,6 @@ namespace vnotex
 {
     class PdfViewer;
     class PdfViewerAdapter;
-    class EditorConfig;
 
     class PdfViewWindow : public ViewWindow
     {
@@ -57,6 +56,8 @@ namespace vnotex
     private:
         void setupUI();
 
+        void setupToolBar();
+
         void setupViewer();
 
         PdfViewerAdapter *adapter() const;

+ 0 - 5
src/widgets/textviewwindow.cpp

@@ -165,11 +165,6 @@ bool TextViewWindow::updateConfigRevision()
     return changed;
 }
 
-void TextViewWindow::setBufferRevisionAfterInvalidation(int p_bufferRevision)
-{
-    m_bufferRevision = p_bufferRevision;
-}
-
 void TextViewWindow::setMode(ViewWindowMode p_mode)
 {
     Q_UNUSED(p_mode);

+ 0 - 5
src/widgets/textviewwindow.h

@@ -79,11 +79,6 @@ namespace vnotex
 
         void setupToolBar();
 
-        // When we have new changes to the buffer content from our ViewWindow,
-        // we will invalidate the contents of the buffer and the buffer will
-        // call this function to tell us now the latest buffer revision.
-        void setBufferRevisionAfterInvalidation(int p_bufferRevision);
-
         void updateEditorFromConfig();
 
         void handleFileOpenParameters(const QSharedPointer<FileOpenParameters> &p_paras);

+ 5 - 0
src/widgets/viewwindow.cpp

@@ -1402,3 +1402,8 @@ void ViewWindow::print()
 void ViewWindow::clearHighlights()
 {
 }
+
+void ViewWindow::setBufferRevisionAfterInvalidation(int p_bufferRevision)
+{
+    m_bufferRevision = p_bufferRevision;
+}

+ 6 - 1
src/widgets/viewwindow.h

@@ -227,6 +227,11 @@ namespace vnotex
         // Sync buffer content changes to editor.
         virtual void syncEditorFromBufferContent() = 0;
 
+        // When we have new changes to the buffer content from our ViewWindow,
+        // we will invalidate the contents of the buffer and the buffer will
+        // call this function to tell us now the latest buffer revision.
+        void setBufferRevisionAfterInvalidation(int p_bufferRevision);
+
         // Whether we are in a mode that enable us to insert text.
         bool inModeCanInsert() const;
 
@@ -242,7 +247,7 @@ namespace vnotex
 
         void showZoomDelta(int p_delta);
 
-        void showFindAndReplaceWidget();
+        virtual void showFindAndReplaceWidget();
 
         void hideFindAndReplaceWidget();
 

+ 19 - 0
src/widgets/webviewer.cpp

@@ -2,6 +2,8 @@
 
 #include "webpage.h"
 
+#include <QWebEnginePage>
+
 #include <utils/utils.h>
 
 using namespace vnotex;
@@ -38,3 +40,20 @@ WebViewer::WebViewer(const QColor &p_background, QWidget *p_parent)
 WebViewer::~WebViewer()
 {
 }
+
+void WebViewer::findText(const QString &p_text, FindOptions p_options)
+{
+    if (p_options & FindOption::RegularExpression) {
+        return;
+    }
+
+    QWebEnginePage::FindFlags flags;
+    if (p_options & FindOption::FindBackward) {
+        flags |= QWebEnginePage::FindFlag::FindBackward;
+    }
+    if (p_options & FindOption::CaseSensitive) {
+        flags |= QWebEnginePage::FindFlag::FindCaseSensitively;
+    }
+
+    QWebEngineView::findText(p_text, flags);
+}

+ 4 - 0
src/widgets/webviewer.h

@@ -3,6 +3,8 @@
 
 #include <QWebEngineView>
 
+#include <core/global.h>
+
 namespace vnotex
 {
     class WebViewer : public QWebEngineView
@@ -15,6 +17,8 @@ namespace vnotex
 
         virtual ~WebViewer();
 
+        void findText(const QString &p_text, FindOptions p_options);
+
     signals:
         void linkHovered(const QString &p_url);
     };

+ 8 - 0
src/widgets/widgets.pri

@@ -51,12 +51,15 @@ SOURCES += \
     $$PWD/editors/markdowntablehelper.cpp \
     $$PWD/editors/markdownviewer.cpp \
     $$PWD/editors/markdownvieweradapter.cpp \
+    $$PWD/editors/mindmapeditor.cpp \
+    $$PWD/editors/mindmapeditoradapter.cpp \
     $$PWD/editors/pdfviewer.cpp \
     $$PWD/editors/pdfvieweradapter.cpp \
     $$PWD/editors/plantumlhelper.cpp \
     $$PWD/editors/previewhelper.cpp \
     $$PWD/editors/statuswidget.cpp \
     $$PWD/editors/texteditor.cpp \
+    $$PWD/editors/webviewadapter.cpp \
     $$PWD/editreaddiscardaction.cpp \
     $$PWD/filesystemviewer.cpp \
     $$PWD/dialogs/folderfilesfilterwidget.cpp \
@@ -77,6 +80,7 @@ SOURCES += \
     $$PWD/locationlist.cpp \
     $$PWD/mainwindow.cpp \
     $$PWD/markdownviewwindow.cpp \
+    $$PWD/mindmapviewwindow.cpp \
     $$PWD/navigationmodemgr.cpp \
     $$PWD/notebookexplorersession.cpp \
     $$PWD/outlinepopup.cpp \
@@ -186,12 +190,15 @@ HEADERS += \
     $$PWD/editors/markdowntablehelper.h \
     $$PWD/editors/markdownviewer.h \
     $$PWD/editors/markdownvieweradapter.h \
+    $$PWD/editors/mindmapeditor.h \
+    $$PWD/editors/mindmapeditoradapter.h \
     $$PWD/editors/pdfviewer.h \
     $$PWD/editors/pdfvieweradapter.h \
     $$PWD/editors/plantumlhelper.h \
     $$PWD/editors/previewhelper.h \
     $$PWD/editors/statuswidget.h \
     $$PWD/editors/texteditor.h \
+    $$PWD/editors/webviewadapter.h \
     $$PWD/editreaddiscardaction.h \
     $$PWD/filesystemviewer.h \
     $$PWD/dialogs/folderfilesfilterwidget.h \
@@ -213,6 +220,7 @@ HEADERS += \
     $$PWD/locationlist.h \
     $$PWD/mainwindow.h \
     $$PWD/markdownviewwindow.h \
+    $$PWD/mindmapviewwindow.h \
     $$PWD/navigationmodemgr.h \
     $$PWD/navigationmodewrapper.h \
     $$PWD/notebookexplorersession.h \

Some files were not shown because too many files changed in this diff