1 /*
2     SPDX-FileCopyrightText: 2006-2007 Aaron Seigo <aseigo@kde.org>
3 
4     SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6 
7 #ifndef PLASMA_DATAENGINE_H
8 #define PLASMA_DATAENGINE_H
9 
10 #include <QHash>
11 #include <QObject>
12 #include <QStringList>
13 
14 #include <KPluginInfo>
15 #include <KService>
16 
17 #include <plasma/plasma.h>
18 #include <plasma/service.h>
19 
20 class QAbstractItemModel;
21 
22 namespace Plasma
23 {
24 class DataContainer;
25 class DataEngineScript;
26 class Package;
27 class Service;
28 class DataEnginePrivate;
29 
30 /**
31  * @class DataEngine plasma/dataengine.h <Plasma/DataEngine>
32  *
33  * @short Data provider for plasmoids (Plasma plugins)
34  *
35  * This is the base class for DataEngines, which provide access to bodies of
36  * data via a common and consistent interface. The common use of a DataEngine
37  * is to provide data to a widget for display. This allows a user interface
38  * element to show all sorts of data: as long as there is a DataEngine, the
39  * data is retrievable.
40  *
41  * DataEngines are loaded as plugins on demand and provide zero, one or more
42  * data sources which are identified by name. For instance, a network
43  * DataEngine might provide a data source for each network interface.
44  **/
45 class PLASMA_EXPORT DataEngine : public QObject
46 {
47     Q_OBJECT
48 
49 public:
50     typedef QHash<QString, DataEngine *> Dict;
51     typedef QMap<QString, QVariant> Data;
52     typedef QMapIterator<QString, QVariant> DataIterator;
53     typedef QHash<QString, DataContainer *> SourceDict;
54 
55 #if PLASMA_ENABLE_DEPRECATED_SINCE(5, 67)
56     /**
57      * Constructor.
58      *
59      * @param parent The parent object.
60      * @param plugin plugin info that describes the engine
61      *
62      * @deprecated since 5.67
63      **/
64     PLASMA_DEPRECATED_VERSION(5, 67, "Use KPluginMetaData")
65     explicit DataEngine(const KPluginInfo &plugin, QObject *parent = nullptr);
66 #endif
67 
68     /**
69      * Constructor.
70      *
71      * @param parent The parent object.
72      * @param plugin metadata that describes the engine
73      *
74      * @since 5.67
75      */
76     explicit DataEngine(const KPluginMetaData &plugin, QObject *parent = nullptr);
77 
78     explicit DataEngine(QObject *parent = nullptr, const QVariantList &args = QVariantList());
79 
80     ~DataEngine() override;
81 
82     /**
83      * @return a list of all the data sources available via this DataEngine
84      *         Whether these sources are currently available (which is what
85      *         the default implementation provides) or not is up to the
86      *         DataEngine to decide.
87      **/
88     virtual QStringList sources() const;
89 
90     /**
91      * @param source the source to target the Service at
92      * @return a Service that has the source as a destination. The service
93      *         is parented to the DataEngine, but should be deleted by the
94      *         caller when finished with it
95      */
96     Q_INVOKABLE virtual Service *serviceForSource(const QString &source);
97 
98 #if PLASMA_ENABLE_DEPRECATED_SINCE(5, 67)
99     /**
100      * @return description of the plugin that implements this DataEngine
101      *
102      * @deprecated since 5.67, use metadata
103      */
104     PLASMA_DEPRECATED_VERSION(5, 67, "Use metadata()")
105     KPluginInfo pluginInfo() const;
106 #endif
107 
108     /**
109      * @return description of the plugin that implements this DataEngine
110      *
111      * @since 5.67
112      */
113     KPluginMetaData metadata() const;
114 
115     /**
116      * Connects a source to an object for data updates. The object must
117      * have a slot with the following signature:
118      * @code
119      * void dataUpdated(const QString &sourceName, const Plasma::DataEngine::Data &data);
120      * @endcode
121      *
122      * The data is a QHash of QVariants keyed by QString names, allowing
123      * one data source to provide sets of related data.
124      *
125      * @param source the name of the data source
126      * @param visualization the object to connect the data source to
127      * @param pollingInterval the frequency, in milliseconds, with which to check for updates;
128      *                        a value of 0 (the default) means to update only
129      *                        when there is new data spontaneously generated
130      *                        (e.g. by the engine); any other value results in
131      *                        periodic updates from this source. This value is
132      *                        per-visualization and can be handy for items that require
133      *                        constant updates such as scrolling graphs or clocks.
134      *                        If the data has not changed, no update will be sent.
135      * @param intervalAlignment the number of ms to align the interval to
136      **/
137     Q_INVOKABLE void connectSource(const QString &source,
138                                    QObject *visualization,
139                                    uint pollingInterval = 0,
140                                    Plasma::Types::IntervalAlignment intervalAlignment = Types::NoAlignment) const;
141 
142     /**
143      * Connects all currently existing sources to an object for data updates.
144      * The object must have a slot with the following signature:
145      * @code
146      * void dataUpdated(const QString &sourceName, const Plasma::DataEngine::Data &data);
147      * @endcode
148      *
149      * The data is a QHash of QVariants keyed by QString names, allowing
150      * one data source to provide sets of related data.
151      *
152      * This method may be called multiple times for the same visualization
153      * without side-effects. This can be useful to change the pollingInterval.
154      *
155      * Note that this method does not automatically connect sources that
156      * may appear later on. Connecting and responding to the sourceAdded signal
157      * is still required to achieve that.
158      *
159      * @param visualization the object to connect the data source to
160      * @param pollingInterval the frequency, in milliseconds, with which to check for updates;
161      *                        a value of 0 (the default) means to update only
162      *                        when there is new data spontaneously generated
163      *                        (e.g. by the engine); any other value results in
164      *                        periodic updates from this source. This value is
165      *                        per-visualization and can be handy for items that require
166      *                        constant updates such as scrolling graphs or clocks.
167      *                        If the data has not changed, no update will be sent.
168      * @param intervalAlignment the number of ms to align the interval to
169      **/
170     Q_INVOKABLE void
171     connectAllSources(QObject *visualization, uint pollingInterval = 0, Plasma::Types::IntervalAlignment intervalAlignment = Types::NoAlignment) const;
172 
173     /**
174      * Disconnects a source from an object that was receiving data updates.
175      *
176      * @param source the name of the data source
177      * @param visualization the object to connect the data source to
178      **/
179     Q_INVOKABLE void disconnectSource(const QString &source, QObject *visualization) const;
180 
181     /**
182      * Retrieves a pointer to the DataContainer for a given source. This method
183      * should not be used if possible. An exception is for script engines that
184      * can not provide a QMetaObject as required by connectSource for the initial
185      * call to dataUpdated. Using this method, such engines can provide their own
186      * connectSource API.
187      *
188      * @param source the name of the source.
189      * @return pointer to a DataContainer, or zero on failure
190      **/
191     Q_INVOKABLE DataContainer *containerForSource(const QString &source);
192 
193     /**
194      * @return The model associated to a source if any. The ownership of the model stays with the DataContainer.
195      *         Returns 0 if there isn't any model associated or if the source doesn't exists.
196      */
197     QAbstractItemModel *modelForSource(const QString &source);
198 
199     /**
200      * Returns true if this engine is valid, otherwise returns false
201      *
202      * @return true if the engine is valid
203      **/
204     bool isValid() const;
205 
206     /**
207      * Returns true if the data engine is empty, which is to say that it has no
208      * data sources currently.
209      *
210      * @return true if the engine has no sources currently
211      */
212     bool isEmpty() const;
213 
214 #if PLASMA_ENABLE_DEPRECATED_SINCE(5, 83)
215     /**
216      * Accessor for the associated Package object if any.
217      *
218      * @return the Package object, or 0 if none
219      **/
220     PLASMA_DEPRECATED_VERSION(5, 83, "Use kpackage API instead")
221     Package package() const;
222 #endif
223 
224 Q_SIGNALS:
225     /**
226      * Emitted when a new data source is created
227      *
228      * Note that you do not need to emit this yourself unless
229      * you are reimplementing sources() and want to advertise
230      * that a new source is available (but hasn't been created
231      * yet).
232      *
233      * @param source the name of the new data source
234      **/
235     void sourceAdded(const QString &source);
236 
237     /**
238      * Emitted when a data source is removed.
239      *
240      * Note that you do not need to emit this yourself unless
241      * you have reimplemented sources() and want to signal that
242      * a source that was available but was never created is no
243      * longer available.
244      *
245      * @param source the name of the data source that was removed
246      **/
247     void sourceRemoved(const QString &source);
248 
249 protected:
250     /**
251      * When a source that does not currently exist is requested by the
252      * consumer, this method is called to give the DataEngine the
253      * opportunity to create one.
254      *
255      * The name of the data source (e.g. the source parameter passed into
256      * setData) must be the same as the name passed to sourceRequestEvent
257      * otherwise the requesting visualization may not receive notice of a
258      * data update.
259      *
260      * If the source can not be populated with data immediately (e.g. due to
261      * an asynchronous data acquisition method such as an HTTP request)
262      * the source must still be created, even if it is empty. This can
263      * be accomplished in these cases with the follow line:
264      *
265      *      setData(name, DataEngine::Data());
266      *
267      * @param source the name of the source that has been requested
268      * @return true if a DataContainer was set up, false otherwise
269      */
270     virtual bool sourceRequestEvent(const QString &source);
271 
272     /**
273      * Called by internal updating mechanisms to trigger the engine
274      * to refresh the data contained in a given source. Reimplement this
275      * method when using facilities such as setPollingInterval.
276      * @see setPollingInterval
277      *
278      * @param source the name of the source that should be updated
279      * @return true if the data was changed, or false if there was no
280      *         change or if the change will occur later
281      **/
282     virtual bool updateSourceEvent(const QString &source);
283 
284     /**
285      * Sets a value for a data source. If the source
286      * doesn't exist then it is created.
287      *
288      * @param source the name of the data source
289      * @param value the data to associated with the source
290      **/
291     void setData(const QString &source, const QVariant &value);
292 
293     /**
294      * Sets a value for a data source. If the source
295      * doesn't exist then it is created.
296      *
297      * @param source the name of the data source
298      * @param key the key to use for the data
299      * @param value the data to associated with the source
300      **/
301     void setData(const QString &source, const QString &key, const QVariant &value);
302 
303     /**
304      * Adds a set of data to a data source. If the source
305      * doesn't exist then it is created.
306      *
307      * @param source the name of the data source
308      * @param data the data to add to the source
309      **/
310     void setData(const QString &source, const QVariantMap &data);
311 
312     /**
313      * Removes all the data associated with a data source.
314      *
315      * @param source the name of the data source
316      **/
317     void removeAllData(const QString &source);
318 
319     /**
320      * Removes a data entry from a source
321      *
322      * @param source the name of the data source
323      * @param key the data entry to remove
324      **/
325     void removeData(const QString &source, const QString &key);
326 
327     /**
328      * Associates a model to a data source. If the source
329      * doesn't exist then it is created. The source will have the key "HasModel" to easily indicate there is a model present.
330      *
331      * The ownership of the model is transferred to the DataContainer,
332      * so the model will be deleted when a new one is set or when the
333      * DataContainer itself is deleted. As the DataContainer, it will be
334      * deleted when there won't be any
335      * visualization associated to this source.
336      *
337      * @param source the name of the data source
338      * @param model the model instance
339      */
340     void setModel(const QString &source, QAbstractItemModel *model);
341 
342     /**
343      * Adds an already constructed data source. The DataEngine takes
344      * ownership of the DataContainer object. The objectName of the source
345      * is used for the source name.
346      *
347      * @param source the DataContainer to add to the DataEngine
348      **/
349     void addSource(DataContainer *source);
350 
351     /**
352      * Sets the minimum amount of time, in milliseconds, that must pass between
353      * successive updates of data. This can help prevent too many updates happening
354      * due to multiple update requests coming in, which can be useful for
355      * expensive (time- or resource-wise) update mechanisms.
356      *
357      * The default minimumPollingInterval is -1, or "never perform automatic updates"
358      *
359      * @param minimumMs the minimum time lapse, in milliseconds, between updates.
360      *                A value less than 0 means to never perform automatic updates,
361      *                a value of 0 means update immediately on every update request,
362      *                a value >0 will result in a minimum time lapse being enforced.
363      **/
364     void setMinimumPollingInterval(int minimumMs);
365 
366     /**
367      * @return the minimum time between updates. @see setMinimumPollingInterval
368      **/
369     int minimumPollingInterval() const;
370 
371     /**
372      * Sets up an internal update tick for all data sources. On every update,
373      * updateSourceEvent will be called for each applicable source.
374      * @see updateSourceEvent
375      *
376      * @param frequency the time, in milliseconds, between updates. A value of 0
377      *                  will stop internally triggered updates.
378      **/
379     void setPollingInterval(uint frequency);
380 
381     /**
382      * Removes all data sources
383      **/
384     void removeAllSources();
385 
386     /**
387      * Sets whether or not this engine is valid, e.g. can be used.
388      * In practice, only the internal fall-back engine, the NullEngine
389      * should have need for this.
390      *
391      * @param valid whether or not the engine is valid
392      **/
393     void setValid(bool valid);
394 
395     /**
396      * @return the list of active DataContainers.
397      */
398     QHash<QString, DataContainer *> containerDict() const;
399 
400     /**
401      * Reimplemented from QObject
402      **/
403     void timerEvent(QTimerEvent *event) override;
404 
405     /**
406      * Sets a source to be stored for easy retrieval
407      * when the real source of the data (usually a network connection)
408      * is unavailable.
409      * @param source the name of the source
410      * @param store if source should be stored
411      * @since 4.6
412      */
413     void setStorageEnabled(const QString &source, bool store);
414 
415 protected Q_SLOTS:
416     /**
417      * Removes a data source.
418      * @param source the name of the data source to remove
419      **/
420     void removeSource(const QString &source);
421 
422     /**
423      * Immediately updates all existing sources when called
424      */
425     void updateAllSources();
426 
427     /**
428      * Forces an immediate update to all connected sources, even those with
429      * timeouts that haven't yet expired. This should _only_ be used when
430      * there was no data available, e.g. due to network non-availability,
431      * and then it becomes available. Normal changes in data values due to
432      * calls to updateSource or in the natural progression of the monitored
433      * object (e.g. CPU heat) should not result in a call to this method!
434      *
435      * @since 4.4
436      */
437     void forceImmediateUpdateOfAllVisualizations();
438 
439 private:
440     friend class DataEnginePrivate;
441     friend class DataEngineScript;
442     friend class DataEngineManager;
443     friend class PlasmoidServiceJob;
444     friend class NullEngine;
445 
446     Q_PRIVATE_SLOT(d, void internalUpdateSource(DataContainer *source))
447     Q_PRIVATE_SLOT(d, void sourceDestroyed(QObject *object))
448     Q_PRIVATE_SLOT(d, void scheduleSourcesUpdated())
449 
450     DataEnginePrivate *const d;
451 };
452 
453 } // Plasma namespace
454 
455 #if PLASMA_ENABLE_DEPRECATED_SINCE(5, 88)
456 /**
457  * Register a data engine when it is contained in a loadable module
458  * @deprecated Since 5.88, use K_PLUGIN_CLASS_WITH_JSON instead
459  */
460 /* clang-format off */
461 #define K_EXPORT_PLASMA_DATAENGINE(libname, classname) \
462     K_PLUGIN_FACTORY(factory, registerPlugin<classname>();)
463 
464 /// @deprecated Since 5.88, use K_PLUGIN_CLASS_WITH_JSON instead
465 #define K_EXPORT_PLASMA_DATAENGINE_WITH_JSON(libname, classname, jsonFile) \
466     K_PLUGIN_FACTORY_WITH_JSON(factory, jsonFile, registerPlugin<classname>();)
467 /* clang-format on */
468 #endif
469 
470 #endif // multiple inclusion guard
471