Add webshortcut search

This commit is contained in:
Carl Schwan
2021-06-04 15:52:33 +02:00
parent 01f861fbbd
commit 51ca4994ef
7 changed files with 233 additions and 88 deletions

View File

@@ -68,6 +68,7 @@ if(ANDROID)
)
else()
find_package(Qt5 ${QT_MIN_VERSION} COMPONENTS Widgets)
find_package(KF5 ${KF5_MIN_VERSION} COMPONENTS REQUIRED KIO)
find_package(KF5QQC2DesktopStyle ${KF5_MIN_VERSION} REQUIRED)
set_package_properties(KF5QQC2DesktopStyle PROPERTIES
TYPE RUNTIME

View File

@@ -19,6 +19,7 @@ Loader {
property string eventType: ""
property string formattedBody: ""
required property string source
property string selectedText: ""
property list<Kirigami.Action> actions: [
Kirigami.Action {
@@ -65,89 +66,33 @@ Loader {
onClicked: loadRoot.item.close();
}
}
QQC2.Menu {
id: webshortcutmenu
title: i18n("Search for '%1'", webshortcutmodel.trunkatedSearchText)
property bool isVisible: selectedText && selectedText.length > 0 && webshortcutmodel.enabled
Component.onCompleted: webshortcutmenu.parent.visible = isVisible
onIsVisibleChanged: webshortcutmenu.parent.visible = isVisible
Instantiator {
model: WebShortcutModel {
id: webshortcutmodel
selectedText: loadRoot.selectedText
onOpenUrl: RoomManager.visitNonMatrix(url)
}
delegate: QQC2.MenuItem {
text: model.display
icon.name: model.decoration
onTriggered: webshortcutmodel.trigger(model.edit)
}
onObjectAdded: webshortcutmenu.insertItem(0, object)
}
QQC2.MenuSeparator {}
QQC2.MenuItem {
text: i18n("Configure Web Shortcuts...")
icon.name: "configure"
onTriggered: webshortcutmodel.configureWebShortcuts()
}
}
}
/*
Kirigami.OverlaySheet {
id: root
parent: applicationWindow().overlay
leftPadding: 0
rightPadding: 0
header: Kirigami.Heading {
text: i18nc("@title:menu Message detail dialog", "Message detail")
}
contentItem: ColumnLayout {
spacing: 0
RowLayout {
id: headerLayout
Layout.fillWidth: true
Layout.margins: Kirigami.Units.largeSpacing
spacing: Kirigami.Units.largeSpacing
Kirigami.Avatar {
id: avatar
source: author.avatarMediaId ? ("image://mxc/" + author.avatarMediaId) : ""
Layout.preferredWidth: Kirigami.Units.gridUnit * 3
Layout.preferredHeight: Kirigami.Units.gridUnit * 3
Layout.alignment: Qt.AlignTop
name: author.displayName
color: author.color
}
ColumnLayout {
Layout.fillWidth: true
Kirigami.Heading {
level: 3
Layout.fillWidth: true
text: author.displayName
wrapMode: Text.WordWrap
}
QQC2.Label {
text: message
Layout.fillWidth: true
Layout.maximumWidth: Kirigami.Units.gridUnit * 24
wrapMode: Text.WordWrap
onLinkActivated: RoomManager.openResource(link);
}
}
}
Kirigami.Separator {
Layout.fillWidth: true
}
RowLayout {
spacing: 0
Layout.fillWidth: true
Layout.preferredHeight: Kirigami.Units.gridUnit * 2.5
Repeater {
model: ["👍", "👎️", "😄", "🎉", "🚀", "👀"]
delegate: QQC2.ItemDelegate {
Layout.fillWidth: true
Layout.fillHeight: true
contentItem: QQC2.Label {
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.pixelSize: 16
font.family: "emoji"
text: modelData
}
onClicked: {
currentRoom.toggleReaction(eventId, modelData)
loadRoot.item.close();
}
}
}
}
Kirigami.Separator {
Layout.fillWidth: true
}
}
}*/
}
Component {
id: mobileMenu

View File

@@ -372,11 +372,11 @@ Kirigami.ScrollablePage {
Layout.bottomMargin: Kirigami.Units.largeSpacing * 2
TapHandler {
acceptedButtons: Qt.RightButton
onTapped: openMessageContext(author, model.message, eventId, toolTip, eventType, model.formattedBody)
onTapped: openMessageContext(author, model.message, eventId, toolTip, eventType, model.formattedBody, parent.selectedText)
}
TapHandler {
acceptedButtons: Qt.LeftButton
onLongPressed: openMessageContext(author, model.message, eventId, toolTip, eventType, model.formattedBody)
onLongPressed: openMessageContext(author, model.message, eventId, toolTip, eventType, model.formattedBody, parent.selectedText)
}
}
}
@@ -399,11 +399,11 @@ Kirigami.ScrollablePage {
Layout.leftMargin: Config.showAvatarInTimeline ? Kirigami.Units.largeSpacing : 0
TapHandler {
acceptedButtons: Qt.RightButton
onTapped: openMessageContext(author, model.message, eventId, toolTip, eventType, model.formattedBody)
onTapped: openMessageContext(author, model.message, eventId, toolTip, eventType, model.formattedBody, parent.selectedText)
}
TapHandler {
acceptedButtons: Qt.LeftButton
onLongPressed: openMessageContext(author, model.message, eventId, toolTip, eventType, model.formattedBody)
onLongPressed: openMessageContext(author, model.message, eventId, toolTip, eventType, model.formattedBody, parent.selectedText)
}
}
}
@@ -881,8 +881,9 @@ Kirigami.ScrollablePage {
}
/// Open context menu for normal message
function openMessageContext(author, message, eventId, source, eventType, formattedBody) {
function openMessageContext(author, message, eventId, source, eventType, formattedBody, selectedText) {
const contextMenu = messageDelegateContextMenu.createObject(page, {
selectedText: selectedText,
author: author,
message: message,
eventId: eventId,

View File

@@ -30,6 +30,7 @@ add_executable(neochat
stickerevent.cpp
chatboxhelper.cpp
commandmodel.cpp
webshortcutmodel.cpp
../res.qrc
)
@@ -91,7 +92,7 @@ if(ANDROID)
"network-connect"
)
else()
target_link_libraries(neochat PRIVATE Qt5::Widgets)
target_link_libraries(neochat PRIVATE Qt5::Widgets KF5::KIOWidgets)
endif()
if(TARGET KF5::DBusAddons)
@@ -99,4 +100,8 @@ if(TARGET KF5::DBusAddons)
target_compile_definitions(neochat PRIVATE -DHAVE_KDBUSADDONS)
endif()
if (TARGET KF5::KIOWidgets)
target_compile_definitions(neochat PRIVATE -DHAVE_KIO)
endif()
install(TARGETS neochat ${KF5_INSTALL_TARGETS_DEFAULT_ARGS})

View File

@@ -56,6 +56,7 @@
#include "sortfilterroomlistmodel.h"
#include "userdirectorylistmodel.h"
#include "userlistmodel.h"
#include "webshortcutmodel.h"
using namespace Quotient;
@@ -147,6 +148,7 @@ int main(int argc, char *argv[])
qmlRegisterType<ActionsHandler>("org.kde.neochat", 1, 0, "ActionsHandler");
qmlRegisterType<ChatDocumentHandler>("org.kde.neochat", 1, 0, "ChatDocumentHandler");
qmlRegisterType<RoomListModel>("org.kde.neochat", 1, 0, "RoomListModel");
qmlRegisterType<KWebShortcutModel>("org.kde.neochat", 1, 0, "WebShortcutModel");
qmlRegisterType<UserListModel>("org.kde.neochat", 1, 0, "UserListModel");
qmlRegisterType<MessageEventModel>("org.kde.neochat", 1, 0, "MessageEventModel");
qmlRegisterType<MessageFilterModel>("org.kde.neochat", 1, 0, "MessageFilterModel");

124
src/webshortcutmodel.cpp Normal file
View File

@@ -0,0 +1,124 @@
// SPDX-FileCopyrightText: 2010 Eike Hein <hein@kde.org>
// SPDX-FileCopyrightText: 2021 Carl Schwan <carl@carlschwan.eu>
// SPDX-License-Identifier: LGPL-2.0-or-later
#include "webshortcutmodel.h"
#ifdef HAVE_KIO
#include <KUriFilter>
#include <KIO/CommandLauncherJob>
#endif
#include <KStringHandler>
struct KWebShortcutModelPrivate
{
QString selectedText;
KUriFilterData filterData;
QStringList searchProviders;
};
KWebShortcutModel::KWebShortcutModel(QObject *parent)
: QAbstractListModel(parent)
, d(new KWebShortcutModelPrivate)
{
}
KWebShortcutModel::~KWebShortcutModel()
{
}
QString KWebShortcutModel::selectedText() const
{
return d->selectedText;
}
QString KWebShortcutModel::trunkatedSearchText() const
{
return KStringHandler::rsqueeze(d->selectedText, 21);
}
bool KWebShortcutModel::enabled() const
{
#ifdef HAVE_KIO
return true;
#else
return false;
#endif
}
void KWebShortcutModel::setSelectedText(const QString &selectedText)
{
if (d->selectedText == selectedText) {
return;
}
#ifdef HAVE_KIO
beginResetModel();
d->selectedText = selectedText;
if (selectedText.isEmpty()) {
endResetModel();
return;
}
QString searchText = selectedText;
searchText = searchText.replace('\n', ' ').replace('\r', ' ').simplified();
if (searchText.isEmpty()) {
endResetModel();
return;
}
d->filterData.setData(searchText);
d->filterData.setSearchFilteringOptions(KUriFilterData::RetrievePreferredSearchProvidersOnly);
if (KUriFilter::self()->filterSearchUri(d->filterData, KUriFilter::NormalTextFilter)) {
d->searchProviders = d->filterData.preferredSearchProviders();
}
endResetModel();
#else
d->selectedText = selectedText;
#endif
Q_EMIT selectedTextChanged();
}
int KWebShortcutModel::rowCount(const QModelIndex &parent) const
{
#ifdef HAVE_KIO
if (d->selectedText.count() > 0) {
return d->searchProviders.count();
}
#endif
return 0;
}
QVariant KWebShortcutModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid()) {
return {};
}
#ifdef HAVE_KIO
switch (role) {
case Qt::DisplayRole:
return d->searchProviders[index.row()];
case Qt::DecorationRole:
return d->filterData.iconNameForPreferredSearchProvider(d->searchProviders[index.row()]);
case Qt::EditRole:
return d->filterData.queryForPreferredSearchProvider(d->searchProviders[index.row()]);
}
#endif
return {};
}
void KWebShortcutModel::trigger(const QString &data)
{
KUriFilterData filterData(data);
if (KUriFilter::self()->filterSearchUri(filterData, KUriFilter::WebShortcutFilter)) {
Q_EMIT openUrl(filterData.uri().url());
}
}
void KWebShortcutModel::configureWebShortcuts()
{
auto job = new KIO::CommandLauncherJob("kcmshell5", QStringList() << "webshortcuts", this);
job->exec();
}

67
src/webshortcutmodel.h Normal file
View File

@@ -0,0 +1,67 @@
// SPDX-FileCopyrightText: 2021 Carl Schwan <carl@carlschwan.eu>
// SPDX-License-Identifier: LGPL-2.0-or-later
#pragma once
#include <QAbstractListModel>
#include <memory>
class KWebShortcutModelPrivate;
//! List model of web shortcuts for a a specified selectedText.
//!
//! This can be used as following in your QML code
//!
//! ```qml
//! QQC2.Menu {
//! id: webshortcutmenu
//! title: i18n("Search for '%1'", webshortcutmodel.trunkatedSearchText)
//! property bool isVisible: selectedText && selectedText.length > 0 && webshortcutmodel.enabled
//! Component.onCompleted: webshortcutmenu.parent.visible = isVisible
//! onIsVisibleChanged: webshortcutmenu.parent.visible = isVisible
//! Instantiator {
//! model: WebShortcutModel {
//! id: webshortcutmodel
//! selectedText: loadRoot.selectedText
//! onOpenUrl: Qt.openUrlExternally(url)
//! }
//! delegate: QQC2.MenuItem {
//! text: model.display
//! icon.name: model.decoration
//! onTriggered: webshortcutmodel.trigger(model.edit)
//! }
//! onObjectAdded: webshortcutmenu.insertItem(0, object)
//! }
//! QQC2.MenuSeparator {}
//! QQC2.MenuItem {
//! text: i18n("Configure Web Shortcuts...")
//! icon.name: "configure"
//! onTriggered: webshortcutmodel.configureWebShortcuts()
//! }
//! }
//! ```
class KWebShortcutModel : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(QString selectedText READ selectedText WRITE setSelectedText NOTIFY selectedTextChanged)
Q_PROPERTY(QString trunkatedSearchText READ trunkatedSearchText NOTIFY selectedTextChanged)
Q_PROPERTY(bool enabled READ enabled CONSTANT)
public:
explicit KWebShortcutModel(QObject *parent = nullptr);
~KWebShortcutModel();
QString selectedText() const;
void setSelectedText(const QString &selectedText);
QString trunkatedSearchText() const;
bool enabled() const;
int rowCount(const QModelIndex &parent) const override;
QVariant data(const QModelIndex &index, int role) const override;
Q_INVOKABLE void trigger(const QString &data);
Q_INVOKABLE void configureWebShortcuts();
Q_SIGNALS:
void selectedTextChanged();
void openUrl(const QUrl &url);
private:
std::unique_ptr<KWebShortcutModelPrivate> d;
};