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_DATACONTAINER_H
21#define PLASMA_DATACONTAINER_H
22
23#include <QtCore/QHash>
24#include <QtCore/QObject>
25#include <QtCore/QTimer>
26
27#include <kjob.h>
28#include <plasma/plasma_export.h>
29#include <plasma/dataengine.h>
30
31namespace Plasma
32{
33
34class DataContainerPrivate;
35
36/**
37 * @class DataContainer plasma/datacontainer.h <Plasma/DataContainer>
38 *
39 * @brief A set of data exported via a DataEngine
40 *
41 * Plasma::DataContainer wraps the data exported by a DataEngine
42 * implementation, providing a generic wrapper for the data.
43 *
44 * A DataContainer may have zero or more associated pieces of data which
45 * are keyed by strings. The data itself is stored as QVariants. This allows
46 * easy and flexible retrieval of the information associated with this object
47 * without writing DataContainer or DataEngine specific code in visualizations.
48 *
49 * If you are creating your own DataContainer objects (and are passing them to
50 * DataEngine::addSource()), you normally just need to listen to the
51 * updateRequested() signal (as well as any other methods you might have of
52 * being notified of new data) and call setData() to actually update the data.
53 * Then you need to either trigger the scheduleSourcesUpdated signal of the
54 * parent DataEngine or call checkForUpdate() on the DataContainer.
55 *
56 * You also need to set a suitable name for the source with setObjectName().
57 * See DataEngine::addSource() for more information.
58 *
59 * Note that there is normally no need to subclass DataContainer, except as
60 * a way of encapsulating the data retrieval for a source, since all notifications
61 * are done via signals rather than virtual methods.
62 **/
63class PLASMA_EXPORT DataContainer : public QObject
64{
65 friend class DataEngine;
66 friend class DataEnginePrivate;
67 Q_OBJECT
68
69 public:
70 /**
71 * Constructs a default DataContainer that has no name or data
72 * associated with it
73 **/
74 explicit DataContainer(QObject *parent = 0);
75 virtual ~DataContainer();
76
77 /**
78 * Returns the data for this DataContainer
79 **/
80 const DataEngine::Data data() const;
81
82 /**
83 * Set a value for a key.
84 *
85 * This also marks this source as needing to signal an update.
86 *
87 * If you call setData() directly on a DataContainer, you need to
88 * either trigger the scheduleSourcesUpdated() slot for the
89 * data engine it belongs to or call checkForUpdate() on the
90 * DataContainer.
91 *
92 * @param key a string used as the key for the data
93 * @param value a QVariant holding the actual data. If a invalid
94 * QVariant is passed in and the key currently exists in the
95 * data, then the data entry is removed
96 **/
97 void setData(const QString &key, const QVariant &value);
98
99 /**
100 * Removes all data currently associated with this source
101 *
102 * If you call removeAllData() on a DataContainer, you need to
103 * either trigger the scheduleSourcesUpdated() slot for the
104 * data engine it belongs to or call checkForUpdate() on the
105 * DataContainer.
106 **/
107 void removeAllData();
108
109 /**
110 * @return true if the visualization is currently connected
111 */
112 bool visualizationIsConnected(QObject *visualization) const;
113
114 /**
115 * Connects an object to this DataContainer.
116 *
117 * May be called repeatedly for the same visualization without
118 * side effects
119 *
120 * @param visualization the object to connect to this DataContainer
121 * @param pollingInterval the time in milliseconds between updates
122 * @param alignment the clock position to align updates to
123 **/
124 void connectVisualization(QObject *visualization, uint pollingInterval,
125 Plasma::IntervalAlignment alignment);
126
127 /**
128 * sets this data container to be automatically stored.
129 * @param whether this data container should be stored
130 * @since 4.6
131 */
132 void setStorageEnabled(bool store);
133
134 /**
135 * @return true if the data container has been marked for storage
136 * @since 4.6
137 */
138 bool isStorageEnabled() const;
139
140 /**
141 * @return true if the data container has been updated, but not stored
142 */
143 bool needsToBeStored() const;
144
145 /**
146 * sets that the data container needs to be stored or not.
147 * @param whether the data container needs to be stored
148 */
149 void setNeedsToBeStored(bool store);
150
151 /**
152 * @return the DataEngine that the DataContainer is
153 * a child of.
154 */
155 DataEngine* getDataEngine();
156
157 public Q_SLOTS:
158 /**
159 * Disconnects an object from this DataContainer.
160 *
161 * Note that if this source was created by DataEngine::sourceRequestEvent(),
162 * it will be deleted by DataEngine once control returns to the event loop.
163 **/
164 void disconnectVisualization(QObject *visualization);
165
166 /**
167 * Forces immediate update signals to all visualizations
168 * @since 4.4
169 */
170 void forceImmediateUpdate();
171
172 Q_SIGNALS:
173 /**
174 * Emitted when the data has been updated, allowing visualizations to
175 * reflect the new data.
176 *
177 * Note that you should not normally emit this directly. Instead, use
178 * checkForUpdate() or the DataEngine::scheduleSourcesUpdated() slot.
179 *
180 * @param source the objectName() of the DataContainer (and hence the name
181 * of the source) that updated its data
182 * @param data the updated data
183 **/
184 void dataUpdated(const QString &source, const Plasma::DataEngine::Data &data);
185
186 /**
187 * Emitted when the last visualization is disconnected.
188 *
189 * Note that if this source was created by DataEngine::sourceRequestEvent(),
190 * it will be deleted by DataEngine once control returns to the event loop
191 * after this signal is emitted.
192 *
193 * @param source the name of the source that became unused
194 **/
195 void becameUnused(const QString &source);
196
197 /**
198 * Emitted when an update is requested.
199 *
200 * If a polling interval was passed connectVisualization(), this signal
201 * will be emitted every time the interval expires.
202 *
203 * Note that if you create your own DataContainer (and pass it to
204 * DataEngine::addSource()), you will need to listen to this signal
205 * and refresh the data when it is triggered.
206 *
207 * @param source the datacontainer the update was requested for. Useful
208 * for classes that update the data for several containers.
209 **/
210 void updateRequested(DataContainer *source);
211
212 protected:
213 /**
214 * Checks whether any data has changed and, if so, emits dataUpdated().
215 **/
216 void checkForUpdate();
217
218 /**
219 * Returns how long ago, in msecs, that the data in this container was last updated.
220 *
221 * This is used by DataEngine to compress updates that happen more quickly than the
222 * minimum polling interval by calling setNeedsUpdate() instead of calling
223 * updateSourceEvent() immediately.
224 **/
225 uint timeSinceLastUpdate() const;
226
227 /**
228 * Indicates that the data should be treated as dirty the next time hasUpdates() is called.
229 *
230 * This is needed for the case where updateRequested() is triggered but we don't want to
231 * update the data immediately because it has just been updated. The second request won't
232 * be fulfilled in this case, because we never updated the data and so never called
233 * checkForUpdate(). So we claim it needs an update anyway.
234 **/
235 void setNeedsUpdate(bool update = true);
236
237 protected Q_SLOTS:
238 /**
239 * Check if the DataContainer is still in use.
240 *
241 * If not the signal "becameUnused" will be emitted.
242 *
243 * Warning: The DataContainer may be invalid after calling this function, because a listener
244 * to becameUnused() may have deleted it.
245 **/
246 void checkUsage();
247
248 /**
249 * @reimp from QObject
250 */
251 void timerEvent(QTimerEvent * event);
252
253 private:
254 friend class SignalRelay;
255 friend class DataContainerPrivate;
256 friend class DataEngineManager;
257 DataContainerPrivate *const d;
258
259 Q_PRIVATE_SLOT(d, void storeJobFinished(KJob *job))
260 Q_PRIVATE_SLOT(d, void populateFromStoredData(KJob *job))
261 Q_PRIVATE_SLOT(d, void retrieve())
262};
263
264} // Plasma namespace
265
266#endif // multiple inclusion guard
267