Compare commits
1 Commits
work/tobia
...
work/carl/
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
29cc585b06 |
@@ -82,7 +82,7 @@ set_package_properties(Qt${QT_MAJOR_VERSION} PROPERTIES
|
||||
TYPE REQUIRED
|
||||
PURPOSE "Basic application components"
|
||||
)
|
||||
find_package(KF${QT_MAJOR_VERSION} ${KF_MIN_VERSION} COMPONENTS Kirigami2 I18n Notifications Config CoreAddons Sonnet ItemModels)
|
||||
find_package(KF${QT_MAJOR_VERSION} ${KF_MIN_VERSION} COMPONENTS Kirigami2 I18n Notifications Config CoreAddons Sonnet ItemModels SyntaxHighlighting)
|
||||
set_package_properties(KF${QT_MAJOR_VERSION} PROPERTIES
|
||||
TYPE REQUIRED
|
||||
PURPOSE "Basic application components"
|
||||
|
||||
@@ -136,6 +136,7 @@ add_library(neochat STATIC
|
||||
mediasizehelper.h
|
||||
eventhandler.cpp
|
||||
enums/delegatetype.h
|
||||
messageformatter.cpp
|
||||
)
|
||||
|
||||
ecm_qt_declare_logging_category(neochat
|
||||
@@ -199,7 +200,7 @@ else()
|
||||
endif()
|
||||
|
||||
target_include_directories(neochat PRIVATE ${CMAKE_BINARY_DIR})
|
||||
target_link_libraries(neochat PUBLIC Qt::Core Qt::Quick Qt::Qml Qt::Gui Qt::Multimedia Qt::Network Qt::QuickControls2 KF${QT_MAJOR_VERSION}::I18n KF${QT_MAJOR_VERSION}::Kirigami2 KF${QT_MAJOR_VERSION}::Notifications KF${QT_MAJOR_VERSION}::ConfigCore KF${QT_MAJOR_VERSION}::ConfigGui KF${QT_MAJOR_VERSION}::CoreAddons KF${QT_MAJOR_VERSION}::SonnetCore KF${QT_MAJOR_VERSION}::ItemModels Quotient${QUOTIENT_SUFFIX} cmark::cmark QCoro::Core)
|
||||
target_link_libraries(neochat PUBLIC Qt::Core Qt::Quick Qt::Qml Qt::Gui Qt::Multimedia Qt::Network Qt::QuickControls2 Qt::Xml KF${QT_MAJOR_VERSION}::I18n KF${QT_MAJOR_VERSION}::Kirigami2 KF${QT_MAJOR_VERSION}::Notifications KF${QT_MAJOR_VERSION}::ConfigCore KF${QT_MAJOR_VERSION}::ConfigGui KF${QT_MAJOR_VERSION}::CoreAddons KF${QT_MAJOR_VERSION}::SonnetCore KF${QT_MAJOR_VERSION}::ItemModels KF${QT_MAJOR_VERSION}::SyntaxHighlighting Quotient${QUOTIENT_SUFFIX} cmark::cmark QCoro::Core)
|
||||
|
||||
kconfig_add_kcfg_files(neochat GENERATE_MOC neochatconfig.kcfgc)
|
||||
|
||||
|
||||
@@ -107,6 +107,8 @@
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
#include "messageformatter.h"
|
||||
|
||||
using namespace Quotient;
|
||||
|
||||
class NetworkAccessManagerFactory : public QQmlNetworkAccessManagerFactory
|
||||
@@ -228,6 +230,12 @@ int main(int argc, char *argv[])
|
||||
Login *login = new Login();
|
||||
UrlHelper urlHelper;
|
||||
|
||||
MessageFormatter formatter;
|
||||
// formatter.formatInternal("<p>hrrejoire</p>\n<pre><code class=\"language-js\">var i = 0; i++; function\n</code></pre>\n<p>rekore</p>\n", new
|
||||
// QTextDocument);
|
||||
|
||||
// return 0;
|
||||
|
||||
#ifdef HAVE_COLORSCHEME
|
||||
ColorSchemer colorScheme;
|
||||
qmlRegisterSingletonInstance<ColorSchemer>("org.kde.neochat", 1, 0, "ColorSchemer", &colorScheme);
|
||||
@@ -236,6 +244,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
#endif
|
||||
|
||||
qmlRegisterSingletonInstance<MessageFormatter>("org.kde.neochat", 1, 0, "MessageFormatter", &formatter);
|
||||
qmlRegisterSingletonInstance("org.kde.neochat", 1, 0, "Controller", &Controller::instance());
|
||||
qmlRegisterSingletonInstance("org.kde.neochat", 1, 0, "NotificationsManager", &NotificationsManager::instance());
|
||||
qmlRegisterSingletonInstance("org.kde.neochat", 1, 0, "Clipboard", &clipboard);
|
||||
|
||||
133
src/messageformatter.cpp
Normal file
133
src/messageformatter.cpp
Normal file
@@ -0,0 +1,133 @@
|
||||
// SPDX-FileCopyrightText: 2021 Carson Black <uhhadd@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2022 Carl Schwan <carl@carlschwan.eu>
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "messageformatter.h"
|
||||
|
||||
#include <QDomDocument>
|
||||
#include <QGuiApplication>
|
||||
#include <QPalette>
|
||||
#include <QQmlContext>
|
||||
#include <QQmlProperty>
|
||||
#include <QTextCursor>
|
||||
#include <QTextDocumentFragment>
|
||||
|
||||
#include <KSyntaxHighlighting/definition.h>
|
||||
#include <KSyntaxHighlighting/repository.h>
|
||||
#include <KSyntaxHighlighting/syntaxhighlighter.h>
|
||||
#include <KSyntaxHighlighting/theme.h>
|
||||
|
||||
QTextDocumentFragment copyTextLayoutFrom(QTextDocument *document)
|
||||
{
|
||||
QTextCursor sourceCursor(document);
|
||||
sourceCursor.select(QTextCursor::Document);
|
||||
|
||||
QTextDocument helper;
|
||||
|
||||
// copy the content fragment from the source document into our helper document
|
||||
QTextCursor curs(&helper);
|
||||
curs.insertFragment(sourceCursor.selection());
|
||||
curs.select(QTextCursor::Document);
|
||||
|
||||
// not sure why, but fonts get lost. since this is for codeblocks, we can
|
||||
// just force the mono font. anyone copying this code would probably want
|
||||
// to fix the problem proper if it's not also for codeblocks.
|
||||
const auto fixedFont = QFontDatabase::systemFont(QFontDatabase::FixedFont);
|
||||
|
||||
const int docStart = sourceCursor.selectionStart();
|
||||
const int docEnd = helper.characterCount() - 1;
|
||||
|
||||
// since the copied fragment above lost the qsyntaxhighlighter stuff,
|
||||
// we gotta go through the qtextlayout and apply those styles to the
|
||||
// document
|
||||
const auto end = document->findBlock(sourceCursor.selectionEnd()).next();
|
||||
for (auto current = document->findBlock(docStart); current.isValid() && current != end; current = current.next()) {
|
||||
const auto layout = current.layout();
|
||||
|
||||
// iterate through the formats, applying them to our document
|
||||
for (const auto &span : layout->formats()) {
|
||||
const int start = current.position() + span.start - docStart;
|
||||
const int end = start + span.length;
|
||||
|
||||
curs.setPosition(qMax(start, 0));
|
||||
curs.setPosition(qMin(end, docEnd), QTextCursor::KeepAnchor);
|
||||
|
||||
auto fmt = span.format;
|
||||
fmt.setFont(fixedFont);
|
||||
|
||||
curs.setCharFormat(fmt);
|
||||
}
|
||||
}
|
||||
|
||||
return QTextDocumentFragment(&helper);
|
||||
}
|
||||
|
||||
QTextDocumentFragment highlight(const QString &code, const QString &language)
|
||||
{
|
||||
using namespace KSyntaxHighlighting;
|
||||
|
||||
static Repository repo;
|
||||
|
||||
auto theme = repo.themeForPalette(QGuiApplication::palette());
|
||||
auto definition = repo.definitionForFileName(QLatin1String("file.") + language);
|
||||
|
||||
QTextDocument doku(code);
|
||||
|
||||
QScopedPointer<SyntaxHighlighter> highlighter(new SyntaxHighlighter(&doku));
|
||||
highlighter->setTheme(theme);
|
||||
highlighter->setDefinition(definition);
|
||||
|
||||
return copyTextLayoutFrom(&doku);
|
||||
}
|
||||
|
||||
bool extractCodeBlock(QTextCursor cursor, QDomElement element)
|
||||
{
|
||||
const auto codeNode = element.firstChild();
|
||||
if (!codeNode.isNull()) {
|
||||
const auto code = codeNode.toElement();
|
||||
if (!code.isNull() && code.tagName() == QLatin1String("code")) {
|
||||
QString lang;
|
||||
auto langClass = code.attribute(QLatin1String("class"), QLatin1String("none"));
|
||||
if (langClass != QLatin1String("none") && langClass.startsWith(QLatin1String("language-"))) {
|
||||
lang = langClass.remove(0, 9);
|
||||
}
|
||||
|
||||
if (!lang.isNull()) {
|
||||
cursor.insertFragment(highlight(code.text(), lang));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
QString MessageFormatter::formatInternal(const QString &messageBody, QTextDocument *document)
|
||||
{
|
||||
QTextCursor curs(document);
|
||||
QDomDocument doc(QLatin1String("htmlement"));
|
||||
doc.setContent(QStringLiteral("<div>%1</div>").arg(messageBody));
|
||||
QDomElement docElem = doc.documentElement();
|
||||
QDomNode n = docElem.firstChild();
|
||||
while (!n.isNull()) {
|
||||
QDomElement e = n.toElement();
|
||||
if (!e.isNull()) {
|
||||
if (e.tagName() != QLatin1String("pre") || !extractCodeBlock(curs, e)) {
|
||||
QString outText;
|
||||
QTextStream out(&outText);
|
||||
e.save(out, 0);
|
||||
curs.insertHtml(outText);
|
||||
}
|
||||
}
|
||||
n = n.nextSibling();
|
||||
}
|
||||
|
||||
Q_EMIT document->contentsChanged();
|
||||
return document->toHtml();
|
||||
}
|
||||
|
||||
QString MessageFormatter::format(const QString &messageBody, QQuickTextDocument *doc, QQuickItem *item)
|
||||
{
|
||||
QColor linkColor = QQmlProperty(item, QLatin1String("Kirigami.Theme.linkColor"), qmlContext(item)).read().value<QColor>();
|
||||
|
||||
return formatInternal(messageBody, doc->textDocument());
|
||||
}
|
||||
13
src/messageformatter.h
Normal file
13
src/messageformatter.h
Normal file
@@ -0,0 +1,13 @@
|
||||
// SPDX-FileCopyrightText: 2022 Carl Schwan <carl@carlschwan.eu>
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include <QQuickItem>
|
||||
#include <QQuickTextDocument>
|
||||
|
||||
class MessageFormatter : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Q_INVOKABLE QString format(const QString &messageBody, QQuickTextDocument *doc, QQuickItem *item);
|
||||
Q_INVOKABLE QString formatInternal(const QString &messageBody, QTextDocument *doc);
|
||||
};
|
||||
@@ -44,6 +44,7 @@ TextEdit {
|
||||
property bool spoilerRevealed: !hasSpoiler.test(textMessage)
|
||||
|
||||
ListView.onReused: Qt.binding(() => !hasSpoiler.test(textMessage))
|
||||
onTextMessageChanged: text = MessageFormatter.format(textMessage, contentLabel.textDocument, contentLabel)
|
||||
|
||||
persistentSelection: true
|
||||
|
||||
@@ -52,6 +53,7 @@ TextEdit {
|
||||
Controller.forceRefreshTextDocument(root.textDocument, root)
|
||||
}
|
||||
|
||||
/*
|
||||
text: "<style>
|
||||
table {
|
||||
width:100%;
|
||||
@@ -84,7 +86,11 @@ a{
|
||||
background: " + Kirigami.Theme.textColor + ";
|
||||
}
|
||||
" : "") + "
|
||||
<<<<<<< HEAD:src/qml/Component/Timeline/RichLabel.qml
|
||||
</style>" + textMessage
|
||||
=======
|
||||
</style>" + (isEmote ? "* <a href='https://matrix.to/#/" + author.id + "' style='color: " + author.color + "'>" + author.displayName + "</a> " : "") + textMessage + (isEdited ? (" <span style=\"color: " + Kirigami.Theme.disabledTextColor + "\">" + "<span style='font-size: " + Kirigami.Theme.defaultFont.pixelSize +"px'>" + i18n(" (edited)") + "</span>") : "")
|
||||
*/
|
||||
|
||||
color: Kirigami.Theme.textColor
|
||||
selectedTextColor: Kirigami.Theme.highlightedTextColor
|
||||
|
||||
Reference in New Issue
Block a user