From e99bdd51d6d6f310cdd8a46fb0888f0342bc489a Mon Sep 17 00:00:00 2001 From: Ivailo Monev Date: Mon, 21 Feb 2022 08:33:28 +0200 Subject: [PATCH] plasma: reimplement dictionary data engine requires: https://github.com/fluxer/katie/commit/808d94b266f649949b0524e111201e4fb4f6856f works like a charm: https://ibb.co/j4Czypq Signed-off-by: Ivailo Monev --- plasma/dataengines/dict/dictengine.cpp | 285 ++++++++++----------------------- plasma/dataengines/dict/dictengine.h | 55 +++---- 2 files changed, 104 insertions(+), 236 deletions(-) diff --git a/plasma/dataengines/dict/dictengine.cpp b/plasma/dataengines/dict/dictengine.cpp index 73944a90..8447be16 100644 --- a/plasma/dataengines/dict/dictengine.cpp +++ b/plasma/dataengines/dict/dictengine.cpp @@ -1,239 +1,116 @@ -/* - * Copyright (C) 2007 Thomas Georgiou and Jeff Cooper - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Library General Public License version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details - * - * You should have received a copy of the GNU Library General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ +/* This file is part of the KDE project + Copyright (C) 2022 Ivailo Monev + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2, as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + #include "dictengine.h" -#include #include #include - -#include +#include +#include DictEngine::DictEngine(QObject* parent, const QVariantList& args) : Plasma::DataEngine(parent, args) - , m_tcpSocket(0) { - Q_UNUSED(args) - m_serverName = "dict.org"; //In case we need to switch it later - m_dictName = "wn"; //Default, good dictionary } DictEngine::~DictEngine() { } -void DictEngine::setDict(const QString &dict) -{ - m_dictName = dict; -} - -void DictEngine::setServer(const QString &server) +bool DictEngine::sourceRequestEvent(const QString &query) { - m_serverName = server; -} + // qDebug() << Q_FUNC_INFO << query; -static QString wnToHtml(const QString &word, QByteArray &text) -{ - Q_UNUSED(word) - QList splitText = text.split('\n'); - QString def; - def += "
\n"; - QRegExp linkRx("\\{(.*)\\}"); - linkRx.setMinimal(true); - - bool isFirst=true; - while (!splitText.empty()) { - //150 n definitions retrieved - definitions follow - //151 word database name - text follows - //250 ok (optional timing information here) - //552 No match - QString currentLine = splitText.takeFirst(); - if (currentLine.startsWith(QLatin1String("151"))) { - isFirst = true; - continue; - } - - if (currentLine.startsWith('.')) { - def += ""; - continue; - } - - if (!(currentLine.startsWith(QLatin1String("150")) - || currentLine.startsWith(QLatin1String("151")) - || currentLine.startsWith(QLatin1String("250")) - || currentLine.startsWith(QLatin1String("552")))) { - currentLine.replace(linkRx,"\\1"); - - if (isFirst) { - def += "
" + currentLine + "
\n
"; - isFirst = false; - continue; - } else { - if (currentLine.contains(QRegExp("([1-9]{1,2}:)"))) { - def += "\n
\n"; - } - currentLine.replace(QRegExp("^([\\s\\S]*[1-9]{1,2}:)"), "\\1"); - def += currentLine; - continue; - } - } + setData(query, QString("text"), QString()); + setData(QString("list-dictionaries"), QString("dictionaries"), QString()); + const QStringList splitquery = query.split(QLatin1Char(':')); + QString queryword = query; + if (splitquery.size() == 2) { + queryword = splitquery.at(1); } - def += "
"; - return def; -} - -void DictEngine::getDefinition() -{ - m_tcpSocket->readAll(); - QByteArray ret; - - m_tcpSocket->write(QByteArray("DEFINE ")); - m_tcpSocket->write(m_dictName.toAscii()); - m_tcpSocket->write(QByteArray(" \"")); - m_tcpSocket->write(m_currentWord.toUtf8()); - m_tcpSocket->write(QByteArray("\"\n")); - m_tcpSocket->flush(); - - while (!ret.contains("250") && !ret.contains("552") && !ret.contains("550")) { - m_tcpSocket->waitForReadyRead(); - ret += m_tcpSocket->readAll(); + if (queryword.isEmpty()) { + return false; + } else if (queryword.contains(' ')) { + setError(query, QLatin1String("Only words can be queried")); + return true; } - connect(m_tcpSocket, SIGNAL(disconnected()), this, SLOT(socketClosed())); - m_tcpSocket->disconnectFromHost(); - // setData(m_currentWord, m_dictName, ret); - // qWarning()< theHash; - m_tcpSocket->readAll(); - QByteArray ret; - - m_tcpSocket->write(QByteArray("SHOW DB\n"));; - m_tcpSocket->flush(); - - m_tcpSocket->waitForReadyRead(); - while (!ret.contains("250")) { - m_tcpSocket->waitForReadyRead(); - ret += m_tcpSocket->readAll(); + m_data.clear(); + const KUrl queryurl = QString::fromLatin1("https://api.dictionaryapi.dev/api/v2/entries/en/") + queryword; + KIO::TransferJob *kiojob = KIO::get(queryurl, KIO::Reload, KIO::HideProgressInfo); + connect(kiojob, SIGNAL(data(KIO::Job*,QByteArray)), this, SLOT(slotKIOData(KIO::Job*,QByteArray))); + const bool kioresult = KIO::NetAccess::synchronousRun(kiojob, nullptr); + if (!kioresult) { + kWarning() << "KIO job failed"; + setError(query, QLatin1String("Cannot get meaning")); + return true; } - QList retLines = ret.split('\n'); - QString tmp1, tmp2; - - while (!retLines.empty()) { - QString curr(retLines.takeFirst()); - - if (curr.startsWith(QLatin1String("554"))) { - //TODO: What happens if no DB available? - //TODO: Eventually there will be functionality to change the server... - break; - } - - // ignore status code and empty lines - if (curr.startsWith(QLatin1String("250")) || curr.startsWith(QLatin1String("110")) - || curr.isEmpty()) { - continue; - } - - if (!curr.startsWith('-') && !curr.startsWith('.')) { - curr = curr.trimmed(); - tmp1 = curr.section(' ', 0, 0); - tmp2 = curr.section(' ', 1); - // theHash.insert(tmp1, tmp2); - //kDebug() << tmp1 + " " + tmp2; - setData("list-dictionaries", tmp1, tmp2); - } + const QJsonDocument jsondocument = QJsonDocument::fromJson(m_data); + if (jsondocument.isNull()) { + kWarning() << jsondocument.errorString(); + setError(query, QLatin1String("Cannot parse JSON")); + return true; } - m_tcpSocket->disconnectFromHost(); -// setData("list-dictionaries", "dictionaries", QByteArray(theHash); + const QVariantList rootlist = jsondocument.toVariant().toList(); + if (rootlist.isEmpty()) { + setError(query, QLatin1String("Unexpected JSON data")); + return true; + } + const QVariantList meaningslist = rootlist.first().toMap().value("meanings").toList(); + if (meaningslist.isEmpty()) { + setError(query, QLatin1String("Unexpected meanings data")); + return true; + } + // qDebug() << Q_FUNC_INFO << "meanings" << meaningslist; + const QVariantList definitionslist = meaningslist.first().toMap().value("definitions").toList(); + if (definitionslist.isEmpty()) { + setError(query, QLatin1String("Unexpected definitions data")); + return true; + } + // qDebug() << Q_FUNC_INFO << "definitions" << definitionslist; + QString meaning = "

\n

Definition: "; + meaning.append(definitionslist.first().toMap().value("definition").toString()); + meaning.append("\n
"); + meaning.append("
\nExample: "); + meaning.append(definitionslist.first().toMap().value("example").toString()); + meaning.append("\n
\n

\n"); + // qDebug() << Q_FUNC_INFO << "meaning" << meaning; + + setData(query, QString("text"), meaning); + setData(QString("list-dictionaries"), QString("dictionaries"), QString("en")); + return true; } - - -void DictEngine::socketClosed() +void DictEngine::slotKIOData(KIO::Job *kiojob, const QByteArray &kiodata) { - m_tcpSocket->deleteLater(); - m_tcpSocket = 0; + Q_UNUSED(kiojob); + m_data.append(kiodata); } -bool DictEngine::sourceRequestEvent(const QString &query) +void DictEngine::setError(const QString &query, const QString &message) { - // FIXME: this is COMPLETELY broken .. it can only look up one query at a time! - // a DataContainer subclass that does the look up should probably be made - if (m_currentQuery == query) { - return false; - } - - if (m_tcpSocket) { - m_tcpSocket->abort(); //stop if lookup is in progress and new query is requested - m_tcpSocket->deleteLater(); - m_tcpSocket = 0; - } - - QStringList queryParts = query.split(':', QString::SkipEmptyParts); - if (queryParts.isEmpty()) { - return false; - } - - m_currentWord = queryParts.last(); - m_currentQuery = query; - - //asked for a dictionary? - if (queryParts.count() > 1) { - setDict(queryParts[queryParts.count()-2]); - //default to wordnet - } else { - setDict("wn"); - } - - //asked for a server? - if (queryParts.count() > 2) { - setServer(queryParts[queryParts.count()-3]); - //default to wordnet - } else { - setServer("dict.org"); - } - - if (m_currentWord.simplified().isEmpty()) { - setData(m_currentWord, m_dictName, QString()); - } else { - setData(m_currentWord, m_dictName, QString()); - m_tcpSocket = new QSslSocket(this); - m_tcpSocket->abort(); - connect(m_tcpSocket, SIGNAL(disconnected()), this, SLOT(socketClosed())); - - if (m_currentWord == "list-dictionaries") { - connect(m_tcpSocket, SIGNAL(readyRead()), this, SLOT(getDicts())); - } else { - connect(m_tcpSocket, SIGNAL(readyRead()), this, SLOT(getDefinition())); - } - - m_tcpSocket->connectToHost(m_serverName, 2628); - } - - return true; + setData(query, QString("text"), QString::fromLatin1("

\n

%1\n
").arg(message)); + setData(QString("list-dictionaries"), QString("dictionaries"), QString("en")); } #include "moc_dictengine.cpp" diff --git a/plasma/dataengines/dict/dictengine.h b/plasma/dataengines/dict/dictengine.h index 0e550115..b7be948f 100644 --- a/plasma/dataengines/dict/dictengine.h +++ b/plasma/dataengines/dict/dictengine.h @@ -1,26 +1,26 @@ -/* - * Copyright (C) 2007 Thomas Georgiou and Jeff Cooper - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Library General Public License version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details - * - * You should have received a copy of the GNU Library General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ +/* This file is part of the KDE project + Copyright (C) 2022 Ivailo Monev + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2, as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ #ifndef DICTENGINE_H #define DICTENGINE_H + #include -#include -#include +#include /** * This class evaluates the basic expressions given in the interface. @@ -38,22 +38,13 @@ class DictEngine: public Plasma::DataEngine protected: bool sourceRequestEvent(const QString &word); - private slots: - void getDefinition(); - void socketClosed(); - void getDicts(); + private Q_SLOTS: + void slotKIOData(KIO::Job *kiojob, const QByteArray &kiodata); private: - void setDict(const QString &dict); - void setServer(const QString &server); - - QHash m_dictNameToDictCode; - QSslSocket *m_tcpSocket; - QString m_currentWord; - QString m_currentQuery; - QString m_dictName; - QString m_serverName; + void setError(const QString &query, const QString &message); + QByteArray m_data; }; K_EXPORT_PLASMA_DATAENGINE(dict, DictEngine) -- 2.11.0