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