Add markdown viewer plugin

Fixes: QTCREATORBUG-27883
Change-Id: Ie4099b8a322797d300bc15a80333bcb361ecafc3
Reviewed-by: André Hartmann <aha_1980@gmx.de>
This commit is contained in:
Tasuku Suzuki
2020-01-27 17:35:38 +09:00
parent 0bb9798c30
commit 8b70e59cdb
20 changed files with 518 additions and 0 deletions

View File

@@ -6,6 +6,7 @@ add_subdirectory(texteditor)
add_subdirectory(serialterminal)
add_subdirectory(helloworld)
add_subdirectory(imageviewer)
add_subdirectory(markdownviewer)
add_subdirectory(marketplace)
add_subdirectory(updateinfo)
add_subdirectory(welcome)

View File

@@ -0,0 +1,12 @@
add_qtc_plugin(MarkdownViewer
PLUGIN_DEPENDS Core TextEditor
SOURCES
markdownbrowser.cpp markdownbrowser.h
markdowndocument.cpp markdowndocument.h
markdowneditor.cpp markdowneditor.h
markdownviewer.cpp markdownviewer.h
markdownviewerconstants.h
markdownviewerfactory.cpp markdownviewerfactory.h
markdownviewerplugin.cpp markdownviewerplugin.h
markdownviewerwidget.cpp markdownviewerwidget.h
)

View File

@@ -0,0 +1,18 @@
{
\"Name\" : \"MarkdownViewer\",
\"Version\" : \"$$QTCREATOR_VERSION\",
\"CompatVersion\" : \"$$QTCREATOR_COMPAT_VERSION\",
\"Vendor\" : \"Signal Slot Inc.\",
\"Copyright\" : \"(C) 2023 Tasuku Suzuki\",
\"License\" : [ \"Commercial Usage\",
\"\",
\"Licensees holding valid Qt Commercial licenses may use this plugin in accordance with the Qt Commercial License Agreement provided with the Software or, alternatively, in accordance with the terms contained in a written agreement between you and The Qt Company.\",
\"\",
\"GNU General Public License Usage\",
\"\",
\"Alternatively, this plugin may be used under the terms of the GNU General Public License version 3 as published by the Free Software Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT included in the packaging of this plugin. Please review the following information to ensure the GNU General Public License requirements will be met: https://www.gnu.org/licenses/gpl-3.0.html.\"
],
\"Description\" : \"Markdown Viewer component.\",
\"Url\" : \"https://signal-slot.co.jp/\",
$$dependencyList
}

View File

@@ -0,0 +1,32 @@
// Copyright (C) 2023 Tasuku Suzuki
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "markdownbrowser.h"
#include <QScrollBar>
namespace Markdown {
namespace Internal {
MarkdownBrowser::MarkdownBrowser(QWidget *parent)
: QTextBrowser(parent)
{}
void MarkdownBrowser::setMarkdown(const QString &markdown)
{
QHash<QScrollBar *, int> positions;
const auto scrollBars = findChildren<QScrollBar *>();
// save scroll positions
for (const auto scrollBar : scrollBars)
positions.insert(scrollBar, scrollBar->value());
QTextBrowser::setMarkdown(markdown);
// restore scroll positions
for (auto scrollBar : scrollBars)
scrollBar->setValue(positions.value(scrollBar));
}
} // namespace Internal
} // namespace Markdown

View File

@@ -0,0 +1,24 @@
// Copyright (C) 2023 Tasuku Suzuki
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#pragma once
#include <QTextBrowser>
namespace Core { class IDocument; }
namespace Markdown {
namespace Internal {
class MarkdownBrowser : public QTextBrowser
{
Q_OBJECT
public:
explicit MarkdownBrowser(QWidget *parent = nullptr);
public slots:
void setMarkdown(const QString &markdown);
};
} // namespace Internal
} // namespace Markdown

View File

@@ -0,0 +1,18 @@
// Copyright (C) 2023 Tasuku Suzuki
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "markdowndocument.h"
#include "markdownviewerconstants.h"
namespace Markdown {
namespace Internal {
MarkdownDocument::MarkdownDocument()
{
setId(Constants::MARKDOWNVIEWER_ID);
setMimeType(QLatin1String(Constants::MARKDOWNVIEWER_MIME_TYPE));
connect(this, &MarkdownDocument::mimeTypeChanged, this, &MarkdownDocument::changed);
}
} // namespace Internal
} // namespace Markdown

View File

@@ -0,0 +1,19 @@
// Copyright (C) 2023 Tasuku Suzuki
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#pragma once
#include <texteditor/textdocument.h>
namespace Markdown {
namespace Internal {
class MarkdownDocument : public TextEditor::TextDocument
{
Q_OBJECT
public:
MarkdownDocument();
};
} // namespace Internal
} // namespace Markdown

View File

@@ -0,0 +1,28 @@
// Copyright (C) 2023 Tasuku Suzuki
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "markdowneditor.h"
#include "markdownviewerconstants.h"
#include "markdowndocument.h"
#include <coreplugin/icore.h>
#include <texteditor/textdocument.h>
namespace Markdown {
namespace Internal {
MarkdownEditor::MarkdownEditor(QWidget *parent)
: TextEditor::TextEditorWidget(parent)
{
setTextDocument(TextEditor::TextDocumentPtr(new MarkdownDocument));
setupGenericHighlighter();
setMarksVisible(false);
auto context = new Core::IContext(this);
context->setWidget(this);
context->setContext(Core::Context(Constants::MARKDOWNVIEWER_EDITOR_CONTEXT));
Core::ICore::addContextObject(context);
}
} // namespace Internal
} // namespace Markdown

View File

@@ -0,0 +1,19 @@
// Copyright (C) 2023 Tasuku Suzuki
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#pragma once
#include <texteditor/texteditor.h>
namespace Markdown {
namespace Internal {
class MarkdownEditor : public TextEditor::TextEditorWidget
{
Q_OBJECT
public:
MarkdownEditor(QWidget *parent = nullptr);
};
} // namespace Internal
} // namespace Markdown

View File

@@ -0,0 +1,86 @@
// Copyright (C) 2023 Tasuku Suzuki
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "markdownviewer.h"
#include "markdownviewerconstants.h"
#include "markdownviewerwidget.h"
#include <coreplugin/icore.h>
#include <coreplugin/coreconstants.h>
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/actionmanager/command.h>
#include <coreplugin/actionmanager/commandbutton.h>
#include <coreplugin/editormanager/editormanager.h>
#include <utils/fileutils.h>
#include <utils/qtcassert.h>
#include <utils/utilsicons.h>
#include <QFileInfo>
#include <QDesktopServices>
#include <QWidget>
#include <QHBoxLayout>
namespace Markdown {
namespace Internal {
struct MarkdownViewerPrivate
{
MarkdownViewerWidget *widget;
QWidget *toolbar;
QToolButton *toggleEditorVisible;
};
MarkdownViewer::MarkdownViewer()
: d(new MarkdownViewerPrivate)
{
ctor();
}
void MarkdownViewer::ctor()
{
d->widget = new MarkdownViewerWidget;
setContext(Core::Context(Constants::MARKDOWNVIEWER_ID));
setWidget(d->widget);
d->toolbar = new QWidget;
auto layout = new QHBoxLayout;
layout->setSpacing(0);
layout->setContentsMargins(0, 0, 0, 0);
layout->addStretch();
d->toggleEditorVisible = new QToolButton;
d->toggleEditorVisible->setText(tr("Hide Editor"));
d->toggleEditorVisible->setCheckable(true);
d->toggleEditorVisible->setChecked(true);
layout->addWidget(d->toggleEditorVisible);
d->toolbar->setLayout(layout);
// connections
connect(d->toggleEditorVisible, &QToolButton::toggled, d->widget, &MarkdownViewerWidget::setEditorVisible);
connect(d->widget, &MarkdownViewerWidget::editorVisibleChanged, this, [this](bool editorVisible) {
d->toggleEditorVisible->setText(editorVisible ? tr("Hide Editor") : tr("Show Editor"));
});
}
MarkdownViewer::~MarkdownViewer()
{
delete d->widget;
delete d->toolbar;
delete d;
}
Core::IDocument *MarkdownViewer::document() const
{
return d->widget->document();
}
QWidget *MarkdownViewer::toolBar()
{
return d->toolbar;
}
} // namespace Internal
} // namespace Markdown

View File

@@ -0,0 +1,30 @@
// Copyright (C) 2023 Tasuku Suzuki
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#pragma once
#include <coreplugin/editormanager/ieditor.h>
#include <coreplugin/idocument.h>
namespace Markdown {
namespace Internal {
class MarkdownDocument;
class MarkdownViewer : public Core::IEditor
{
Q_OBJECT
public:
explicit MarkdownViewer();
~MarkdownViewer() override;
Core::IDocument *document() const override;
QWidget *toolBar() override;
private:
void ctor();
struct MarkdownViewerPrivate *d;
};
} // namespace Internal
} // namespace Markdown

View File

@@ -0,0 +1,27 @@
import qbs 1.0
QtcPlugin {
name: "MarkdownViewer"
Depends { name: "Qt.widgets" }
Depends { name: "Core" }
Depends { name: "TextEditor" }
files: [
"markdownbrowser.cpp",
"markdownbrowser.h",
"markdowndocument.cpp",
"markdowndocument.h",
"markdowneditor.cpp",
"markdowneditor.h",
"markdownviewer.cpp",
"markdownviewer.h",
"markdownviewerconstants.h",
"markdownviewerfactory.cpp",
"markdownviewerfactory.h",
"markdownviewerplugin.cpp",
"markdownviewerplugin.h",
"markdownviewerwidget.cpp",
"markdownviewerwidget.h",
]
}

View File

@@ -0,0 +1,17 @@
// Copyright (C) 2023 Tasuku Suzuki
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#pragma once
#include <qglobal.h>
namespace Markdown {
namespace Constants {
const char MARKDOWNVIEWER_ID[] = "Editors.MarkdownViewer";
const char MARKDOWNVIEWER_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("OpenWith::Editors", "Markdown Viewer");
const char MARKDOWNVIEWER_MIME_TYPE[] = "text/markdown";
const char MARKDOWNVIEWER_EDITOR_CONTEXT[] = "Editors.MarkdownViewer.Id";
} // namespace Constants
} // namespace Markdown

View File

@@ -0,0 +1,22 @@
// Copyright (C) 2023 Tasuku Suzuki
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "markdownviewerfactory.h"
#include "markdownviewerconstants.h"
#include "markdownviewer.h"
#include <QCoreApplication>
namespace Markdown {
namespace Internal {
MarkdownViewerFactory::MarkdownViewerFactory()
{
setId(Constants::MARKDOWNVIEWER_ID);
setDisplayName(QCoreApplication::translate("OpenWith::Editors", Constants::MARKDOWNVIEWER_DISPLAY_NAME));
addMimeType(Constants::MARKDOWNVIEWER_MIME_TYPE);
setEditorCreator([] { return new MarkdownViewer(); });
}
} // namespace Internal
} // namespace Markdown

View File

@@ -0,0 +1,18 @@
// Copyright (C) 2023 Tasuku Suzuki
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#pragma once
#include <coreplugin/editormanager/ieditorfactory.h>
namespace Markdown {
namespace Internal {
class MarkdownViewerFactory final : public Core::IEditorFactory
{
public:
MarkdownViewerFactory();
};
} // namespace Internal
} // namespace Markdown

View File

@@ -0,0 +1,25 @@
// Copyright (C) 2023 Tasuku Suzuki
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "markdownviewerplugin.h"
#include "markdownviewerfactory.h"
#include <extensionsystem/pluginmanager.h>
using namespace Core;
namespace Markdown {
namespace Internal {
bool MarkdownViewerPlugin::initialize(const QStringList &arguments, QString *errorMessage)
{
Q_UNUSED(arguments)
Q_UNUSED(errorMessage)
ExtensionSystem::PluginManager::addObject(new MarkdownViewerFactory);
return true;
}
} // namespace Internal
} // namespace Markdown

View File

@@ -0,0 +1,26 @@
// Copyright (C) 2023 Tasuku Suzuki
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#pragma once
#include <extensionsystem/iplugin.h>
namespace Markdown {
namespace Internal {
class MarkdownViewerPlugin : public ExtensionSystem::IPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "MarkdownViewer.json")
public:
MarkdownViewerPlugin() = default;
~MarkdownViewerPlugin() = default;
private:
bool initialize(const QStringList &arguments, QString *errorMessage) final;
void extensionsInitialized() final {}
};
} // namespace Internal
} // namespace Markdown

View File

@@ -0,0 +1,58 @@
// Copyright (C) 2023 Tasuku Suzuki
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "markdownviewerwidget.h"
#include "markdowneditor.h"
#include "markdownbrowser.h"
#include <texteditor/textdocument.h>
namespace Markdown {
namespace Internal {
struct MarkdownViewerWidgetPrivate
{
MarkdownBrowser *browser;
MarkdownEditor *editor;
};
MarkdownViewerWidget::MarkdownViewerWidget()
: d(new MarkdownViewerWidgetPrivate)
{
d->browser = new MarkdownBrowser(this);
d->browser->setOpenExternalLinks(true);
d->browser->setFrameShape(QFrame::NoFrame);
d->editor = new MarkdownEditor(this);
connect(d->editor->document(), &QTextDocument::contentsChanged,
this, [this]() {
const auto plainText = d->editor->textDocument()->plainText();
d->browser->setMarkdown(plainText);
});
}
MarkdownViewerWidget::~MarkdownViewerWidget()
{
delete d;
}
Core::IDocument *MarkdownViewerWidget::document() const
{
return d->editor->textDocument();
}
bool MarkdownViewerWidget::isEditorVisible() const
{
return d->editor->isVisible();
}
void MarkdownViewerWidget::setEditorVisible(bool editorVisible)
{
if (d->editor->isVisible() == editorVisible)
return;
d->editor->setVisible(editorVisible);
emit editorVisibleChanged(editorVisible);
}
} // namespace Internal
} // namespace Markdown

View File

@@ -0,0 +1,37 @@
// Copyright (C) 2023 Tasuku Suzuki
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#pragma once
#include <coreplugin/minisplitter.h>
#include <utils/fileutils.h>
namespace Core { class IDocument; }
namespace Markdown {
namespace Internal {
class MarkdownViewerWidget : public Core::MiniSplitter
{
Q_OBJECT
Q_PROPERTY(bool editorVisible READ isEditorVisible WRITE setEditorVisible NOTIFY editorVisibleChanged)
public:
explicit MarkdownViewerWidget();
~MarkdownViewerWidget() override;
Core::IDocument *document() const;
bool isEditorVisible() const;
public slots:
void setEditorVisible(bool editorVisible);
signals:
void editorVisibleChanged(bool editorVisible);
private:
struct MarkdownViewerWidgetPrivate *d;
};
} // namespace Internal
} // namespace Markdown

View File

@@ -50,6 +50,7 @@ Project {
"ios/ios.qbs",
"languageclient/languageclient.qbs",
"macros/macros.qbs",
"markdownviewer/markdownviewer.qbs",
"marketplace/marketplace.qbs",
"mcusupport/mcusupport.qbs",
"mercurial/mercurial.qbs",