Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Plasma
Plasma Add-ons
Commits
41de3215
Commit
41de3215
authored
Mar 06, 2022
by
Alexander Lohnau
💬
Browse files
Port dictionary runner & applet away from Dataengines
Task:
https://phabricator.kde.org/T13384
parent
28d8943e
Pipeline
#152829
passed with stage
in 3 minutes and 9 seconds
Changes
11
Pipelines
2
Hide whitespace changes
Inline
Side-by-side
CMakeLists.txt
View file @
41de3215
...
...
@@ -74,6 +74,7 @@ add_definitions(
-DQT_NO_URL_CAST_FROM_STRING
)
add_subdirectory
(
dict
)
add_subdirectory
(
applets
)
add_subdirectory
(
dataengines
)
add_subdirectory
(
runners
)
...
...
applets/dict/CMakeLists.txt
View file @
41de3215
...
...
@@ -33,10 +33,10 @@ set(dict_SRCS
add_library
(
dictplugin SHARED
${
dict_SRCS
}
)
target_link_libraries
(
dictplugin
KF5::Plasma
KF5::I18n
Qt::Quick
Qt::WebEngine
engine_dict_static
)
install
(
FILES plugin/qmldir DESTINATION
${
KDE_INSTALL_QMLDIR
}
/org/kde/plasma/private/dict
)
...
...
applets/dict/plugin/dict_object.cpp
View file @
41de3215
...
...
@@ -11,9 +11,6 @@
#include
<QWebEngineUrlRequestJob>
#include
<QWebEngineUrlSchemeHandler>
// The KDE4 applet could use "qstardict" if available, but I have no idea where this came from.
static
const
char
defaultDataEngine
[]
=
"dict"
;
class
DictSchemeHandler
:
public
QWebEngineUrlSchemeHandler
{
Q_OBJECT
...
...
@@ -35,38 +32,26 @@ Q_SIGNALS:
DictObject
::
DictObject
(
QObject
*
parent
)
:
QObject
(
parent
)
,
m_dataEngineName
(
QString
::
fromLatin1
(
defaultDataEngine
))
{
m_selectedDict
=
QStringLiteral
(
"wn"
);
m_webProfile
=
new
QQuickWebEngineProfile
(
this
);
auto
*
schemeHandler
=
new
DictSchemeHandler
(
this
);
connect
(
schemeHandler
,
&
DictSchemeHandler
::
wordClicked
,
this
,
&
DictObject
::
lookup
);
connect
(
&
m_engine
,
&
DictEngine
::
definitionRecieved
,
this
,
[
this
](
const
QString
&
html
)
{
Q_EMIT
definitionFound
(
html
);
});
m_webProfile
->
installUrlSchemeHandler
(
"dict"
,
schemeHandler
);
m_dataEngine
=
dataEngine
(
m_dataEngineName
);
// Load it upfront so the config dialog can reuse this one
}
void
DictObject
::
lookup
(
const
QString
&
word
)
{
const
QString
newSource
=
m_selectedDict
+
QLatin1Char
(
':'
)
+
word
;
if
(
!
m_source
.
isEmpty
())
{
m_dataEngine
->
disconnectSource
(
m_source
,
this
);
}
if
(
!
newSource
.
isEmpty
())
{
// Look up new definition
Q_EMIT
searchInProgress
();
m_source
=
newSource
;
m_dataEngine
->
connectSource
(
m_source
,
this
);
}
}
void
DictObject
::
dataUpdated
(
const
QString
&
sourceName
,
const
Plasma
::
DataEngine
::
Data
&
data
)
{
Q_UNUSED
(
sourceName
);
// always == m_source
const
QString
html
=
data
.
value
(
QStringLiteral
(
"text"
)).
toString
();
if
(
!
html
.
isEmpty
())
{
Q_EMIT
definitionFound
(
html
);
m_engine
.
requestDefinition
(
newSource
);
}
}
...
...
applets/dict/plugin/dict_object.h
View file @
41de3215
...
...
@@ -6,12 +6,12 @@
#ifndef DICT_OBJECT_H
#define DICT_OBJECT_H
#include
<Plasma/DataEngine>
#include
<Plasma/DataEngineConsumer>
#include
"../../dict/dictengine.h"
#include
<QObject>
class
QQuickWebEngineProfile
;
class
DictObject
:
public
QObject
,
public
Plasma
::
DataEngineConsumer
class
DictObject
:
public
QObject
{
Q_OBJECT
Q_PROPERTY
(
QQuickWebEngineProfile
*
webProfile
READ
webProfile
CONSTANT
)
...
...
@@ -28,9 +28,6 @@ public:
public
Q_SLOTS
:
void
lookup
(
const
QString
&
word
);
private
Q_SLOTS
:
void
dataUpdated
(
const
QString
&
sourceName
,
const
Plasma
::
DataEngine
::
Data
&
data
);
Q_SIGNALS:
void
searchInProgress
();
void
definitionFound
(
const
QString
&
html
);
...
...
@@ -40,7 +37,7 @@ private:
QString
m_dataEngineName
;
QString
m_selectedDict
;
Plasma
::
Data
Engine
*
m_
dataE
ngine
;
Dict
Engine
m_
e
ngine
;
QQuickWebEngineProfile
*
m_webProfile
;
};
...
...
applets/dict/plugin/dictionariesmodel.cpp
View file @
41de3215
...
...
@@ -5,19 +5,23 @@
*/
#include
"dictionariesmodel.h"
#include
<Plasma/DataContainer>
#include
<QDebug>
DictionariesModel
::
DictionariesModel
(
QObject
*
parent
)
:
QAbstractListModel
(
parent
)
{
Plasma
::
DataEngine
*
dataengine
=
dataEngine
(
QStringLiteral
(
"dict"
));
const
QString
source
=
QLatin1String
(
"list-dictionaries"
);
Plasma
::
DataContainer
*
container
=
dataengine
->
containerForSource
(
source
);
if
(
container
)
{
// in practice this never seems to happen, this source is only used here, so never shared
setAvailableDicts
(
container
->
data
());
}
dataengine
->
connectSource
(
source
,
this
);
static
DictEngine
engine
;
// Keep this around longer, because then we can use it's cache'
connect
(
&
engine
,
&
DictEngine
::
dictsRecieved
,
this
,
[
this
](
const
QMap
<
QString
,
QString
>
&
dicts
)
{
beginResetModel
();
m_availableDicts
=
{};
m_availableDicts
.
resize
(
dicts
.
count
());
int
i
=
0
;
for
(
auto
it
=
dicts
.
begin
(),
end
=
dicts
.
end
();
it
!=
end
;
++
it
,
++
i
)
{
m_availableDicts
[
i
]
=
AvailableDict
{
it
.
key
(),
it
.
value
()};
}
endResetModel
();
});
engine
.
requestDicts
();
}
QVariant
DictionariesModel
::
data
(
const
QModelIndex
&
index
,
int
role
)
const
...
...
@@ -46,21 +50,3 @@ QHash<int, QByteArray> DictionariesModel::roleNames() const
{
return
{{
Qt
::
DisplayRole
,
"description"
},
{
Qt
::
EditRole
,
"id"
}};
}
void
DictionariesModel
::
dataUpdated
(
const
QString
&
sourceName
,
const
Plasma
::
DataEngine
::
Data
&
data
)
{
Q_ASSERT
(
sourceName
==
QLatin1String
(
"list-dictionaries"
));
beginResetModel
();
setAvailableDicts
(
data
);
endResetModel
();
}
void
DictionariesModel
::
setAvailableDicts
(
const
QVariantMap
&
data
)
{
m_availableDicts
=
{};
m_availableDicts
.
resize
(
data
.
count
());
int
i
=
0
;
for
(
auto
it
=
data
.
begin
(),
end
=
data
.
end
();
it
!=
end
;
++
it
,
++
i
)
{
m_availableDicts
[
i
]
=
AvailableDict
{
it
.
key
(),
it
.
value
().
toString
()};
}
}
applets/dict/plugin/dictionariesmodel.h
View file @
41de3215
...
...
@@ -6,12 +6,11 @@
#ifndef DICTIONARIES_MODEL_H
#define DICTIONARIES_MODEL_H
#include
<Plasma/DataEngine>
#include
<Plasma/DataEngineConsumer>
#include
"../../dict/dictengine.h"
#include
<QAbstractListModel>
#include
<vector>
class
DictionariesModel
:
public
QAbstractListModel
,
public
Plasma
::
DataEngineConsumer
class
DictionariesModel
:
public
QAbstractListModel
{
Q_OBJECT
...
...
@@ -22,9 +21,6 @@ public:
int
rowCount
(
const
QModelIndex
&
index
=
QModelIndex
())
const
override
;
QHash
<
int
,
QByteArray
>
roleNames
()
const
override
;
private
Q_SLOTS
:
void
dataUpdated
(
const
QString
&
sourceName
,
const
Plasma
::
DataEngine
::
Data
&
data
);
private:
void
setAvailableDicts
(
const
QVariantMap
&
data
);
...
...
runners/dictionary/CMakeLists.txt
View file @
41de3215
add_definitions
(
-DTRANSLATION_DOMAIN=
"plasma_runner_krunner_dictionary"
)
kcoreaddons_add_plugin
(
krunner_dictionary SOURCES
${
dictionaryrunner_SRCS
}
INSTALL_NAMESPACE
"kf5/krunner"
)
target_sources
(
krunner_dictionary PRIVATE dictionaryrunner.cpp
dictionarymatchengine.cpp
)
target_link_libraries
(
krunner_dictionary KF5::Runner KF5::I18n
)
target_sources
(
krunner_dictionary PRIVATE dictionaryrunner.cpp
)
target_link_libraries
(
krunner_dictionary KF5::Runner KF5::I18n
engine_dict_static
)
kcoreaddons_add_plugin
(
kcm_krunner_dictionary INSTALL_NAMESPACE
"kf5/krunner/kcms"
)
target_sources
(
kcm_krunner_dictionary PRIVATE dictionaryrunner_config.cpp
)
...
...
runners/dictionary/dictionarymatchengine.cpp
deleted
100644 → 0
View file @
28d8943e
/*
* SPDX-License-Identifier: GPL-2.0-or-later
* SPDX-FileCopyrightText: 2010, 2012 Jason A. Donenfeld <Jason@zx2c4.com>
*/
#include
"dictionarymatchengine.h"
#include
<KRunner/AbstractRunner>
#include
<QDeadlineTimer>
#include
<QDebug>
#include
<QMetaMethod>
#include
<QThread>
DictionaryMatchEngine
::
DictionaryMatchEngine
(
Plasma
::
DataEngine
*
dictionaryEngine
,
QObject
*
parent
)
:
QObject
(
parent
)
,
m_dictionaryEngine
(
dictionaryEngine
)
{
/* We have to connect source in two different places, due to the difference in
* how the connection is made based on data availability. There are two cases,
* and this extra connection handles the second case. */
Q_ASSERT
(
m_dictionaryEngine
);
connect
(
m_dictionaryEngine
,
&
Plasma
::
DataEngine
::
sourceAdded
,
this
,
&
DictionaryMatchEngine
::
sourceAdded
);
}
/* This function should be called from a different thread. */
QString
DictionaryMatchEngine
::
lookupWord
(
const
QString
&
word
)
{
if
(
!
m_dictionaryEngine
)
{
qDebug
()
<<
"Could not find dictionary data engine."
;
return
QString
();
}
if
(
thread
()
==
QThread
::
currentThread
())
{
qDebug
()
<<
"DictionaryMatchEngine::lookupWord is only meant to be called from non-primary threads."
;
return
QString
();
}
ThreadData
data
;
m_wordLock
.
lockForWrite
();
m_lockers
.
insert
(
word
,
&
data
);
m_wordLock
.
unlock
();
QMetaObject
::
invokeMethod
(
this
,
"sourceAdded"
,
Qt
::
QueuedConnection
,
Q_ARG
(
const
QString
&
,
word
));
QMutexLocker
locker
(
&
data
.
mutex
);
if
(
!
data
.
waitCondition
.
wait
(
&
data
.
mutex
,
QDeadlineTimer
(
30
*
1000
)))
{
// Timeout after 30 seconds
qDebug
()
<<
"The dictionary data engine timed out (word:"
<<
word
<<
")"
;
}
locker
.
unlock
();
QMetaObject
::
invokeMethod
(
this
,
"sourceRemoved"
,
Qt
::
QueuedConnection
,
Q_ARG
(
const
QString
&
,
word
));
// after a timeout, if dataUpdated gets m_wordLock here, it can lock data->mutex successfully.
m_wordLock
.
lockForWrite
();
m_lockers
.
remove
(
word
,
&
data
);
m_wordLock
.
unlock
();
// after a timeout, if dataUpdated gets m_wordLock here, it won't see this data instance anymore.
locker
.
relock
();
return
data
.
definition
;
}
void
DictionaryMatchEngine
::
sourceAdded
(
const
QString
&
source
)
{
m_dictionaryEngine
->
connectSource
(
source
,
this
);
}
void
DictionaryMatchEngine
::
sourceRemoved
(
const
QString
&
source
)
{
m_dictionaryEngine
->
disconnectSource
(
source
,
this
);
}
void
DictionaryMatchEngine
::
dataUpdated
(
const
QString
&
source
,
const
Plasma
::
DataEngine
::
Data
&
result
)
{
if
(
!
result
.
contains
(
QLatin1String
(
"text"
)))
{
return
;
}
QString
definition
(
result
[
QLatin1String
(
"text"
)].
toString
());
m_wordLock
.
lockForRead
();
for
(
ThreadData
*
data
:
std
::
as_const
(
m_lockers
))
{
QMutexLocker
locker
(
&
data
->
mutex
);
/* Because of QString's CoW semantics, we don't have to worry about
* the overhead of assigning this to every item. */
data
->
definition
=
definition
;
data
->
waitCondition
.
wakeOne
();
}
m_wordLock
.
unlock
();
}
runners/dictionary/dictionarymatchengine.h
deleted
100644 → 0
View file @
28d8943e
/*
* SPDX-License-Identifier: GPL-2.0-or-later
* SPDX-FileCopyrightText: 2010, 2012 Jason A. Donenfeld <Jason@zx2c4.com>
*/
#ifndef DICTIONARYMATCHENGINE_H
#define DICTIONARYMATCHENGINE_H
#include
<Plasma/DataEngine>
#include
<QHash>
#include
<QMultiMap>
#include
<QMutex>
#include
<QReadWriteLock>
#include
<QWaitCondition>
namespace
Plasma
{
}
class
DictionaryMatchEngine
:
public
QObject
{
Q_OBJECT
public:
explicit
DictionaryMatchEngine
(
Plasma
::
DataEngine
*
dictionaryEngine
,
QObject
*
parent
=
nullptr
);
QString
lookupWord
(
const
QString
&
word
);
private:
struct
ThreadData
{
QWaitCondition
waitCondition
;
QMutex
mutex
;
QString
definition
;
};
QMultiMap
<
QString
,
ThreadData
*>
m_lockers
;
QReadWriteLock
m_wordLock
;
Plasma
::
DataEngine
*
m_dictionaryEngine
;
private
Q_SLOTS
:
void
dataUpdated
(
const
QString
&
name
,
const
Plasma
::
DataEngine
::
Data
&
data
);
void
sourceAdded
(
const
QString
&
source
);
void
sourceRemoved
(
const
QString
&
source
);
};
#endif
runners/dictionary/dictionaryrunner.cpp
View file @
41de3215
...
...
@@ -25,11 +25,6 @@ DictionaryRunner::DictionaryRunner(QObject *parent, const KPluginMetaData &metaD
setObjectName
(
QLatin1String
(
"Dictionary"
));
}
void
DictionaryRunner
::
init
()
{
reloadConfiguration
();
}
void
DictionaryRunner
::
reloadConfiguration
()
{
KConfigGroup
c
=
config
();
...
...
@@ -53,34 +48,25 @@ void DictionaryRunner::match(RunnerContext &context)
return
;
}
// Initialize engine
{
// It can happen that we are in this function and
// another match starts happening. Hence we lock to
// ensure that we always init the engine once
QMutexLocker
lock
(
&
s_initMutex
);
if
(
!
m_engine
)
{
QMetaObject
::
invokeMethod
(
this
,
[
this
]
{
m_consumer
=
std
::
make_unique
<
Plasma
::
DataEngineConsumer
>
();
m_engine
=
std
::
make_unique
<
DictionaryMatchEngine
>
(
m_consumer
->
dataEngine
(
QStringLiteral
(
"dict"
)));
},
Qt
::
BlockingQueuedConnection
);
}
QEventLoop
loop
;
QTimer
::
singleShot
(
400
,
&
loop
,
[
&
loop
]()
{
loop
.
quit
();
});
loop
.
exec
();
}
if
(
!
context
.
isValid
())
{
return
;
}
QString
returnedQuery
;
QMetaObject
::
invokeMethod
(
&
m_dictEngine
,
"requestDefinition"
,
Qt
::
QueuedConnection
,
Q_ARG
(
const
QString
&
,
query
));
QEventLoop
loop
;
QTimer
::
singleShot
(
400
,
&
loop
,
[
&
loop
]()
{
connect
(
&
m_dictEngine
,
&
DictEngine
::
definitionRecieved
,
&
loop
,
[
&
loop
,
&
query
,
&
returnedQuery
,
&
context
](
const
QString
&
html
)
{
returnedQuery
=
html
;
loop
.
quit
();
});
loop
.
exec
();
if
(
!
context
.
isValid
())
{
return
;
}
QString
returnedQuery
=
m_engine
->
lookupWord
(
query
);
if
(
!
context
.
isValid
())
{
if
(
!
context
.
isValid
()
||
returnedQuery
.
isEmpty
())
{
return
;
}
...
...
runners/dictionary/dictionaryrunner.h
View file @
41de3215
...
...
@@ -6,9 +6,8 @@
#ifndef DICTIONARYRUNNER_H
#define DICTIONARYRUNNER_H
#include
"
dictionarymatch
engine.h"
#include
"
../../dict/dict
engine.h"
#include
<KRunner/AbstractRunner>
#include
<Plasma/DataEngineConsumer>
using
namespace
Plasma
;
...
...
@@ -23,11 +22,7 @@ public:
private:
QString
m_triggerWord
;
std
::
unique_ptr
<
DictionaryMatchEngine
>
m_engine
;
std
::
unique_ptr
<
Plasma
::
DataEngineConsumer
>
m_consumer
;
protected
Q_SLOTS
:
void
init
()
override
;
DictEngine
m_dictEngine
;
};
#endif
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment