1 | /* |
---|---|
2 | Copyright (C) 2005-2009 by Olivier Goffart <ogoffart at kde.org> |
3 | |
4 | |
5 | This program is free software; you can redistribute it and/or modify |
6 | it under the terms of the GNU General Public License as published by |
7 | the Free Software Foundation; either version 2, or (at your option) |
8 | any later version. |
9 | |
10 | This program is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | GNU General Public License for more details. |
14 | |
15 | You should have received a copy of the GNU General Public License |
16 | along with this program; if not, write to the Free Software |
17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
18 | |
19 | */ |
20 | |
21 | #include "knotify.h" |
22 | |
23 | // KDE headers |
24 | #include <kapplication.h> |
25 | #include <kconfig.h> |
26 | #include <kdebug.h> |
27 | #include <kglobal.h> |
28 | #include <klocale.h> |
29 | #include <kservicetypetrader.h> |
30 | |
31 | #include <config-runtime.h> |
32 | |
33 | #include "knotifyconfig.h" |
34 | #include "ksolidnotify.h" |
35 | #include "notifybysound.h" |
36 | #include "notifybypopup.h" |
37 | #include "notifybyexecute.h" |
38 | #include "notifybylogfile.h" |
39 | #include "notifybytaskbar.h" |
40 | #include "notifybyktts.h" |
41 | |
42 | |
43 | |
44 | KNotify::KNotify( QObject *parent ) |
45 | : QObject( parent ), |
46 | m_counter(0) |
47 | { |
48 | loadConfig(); |
49 | (void)new KNotifyAdaptor(this); |
50 | (void)new KSolidNotify(this); |
51 | QDBusConnection::sessionBus().registerObject("/Notify", this, QDBusConnection::ExportAdaptors |
52 | /*| QDBusConnection::ExportScriptableSlots | QDBusConnection::ExportScriptableSignals*/ ); |
53 | } |
54 | |
55 | KNotify::~KNotify() |
56 | { |
57 | qDeleteAll(m_notifications); |
58 | } |
59 | |
60 | |
61 | void KNotify::loadConfig() |
62 | { |
63 | qDeleteAll(m_plugins); |
64 | m_plugins.clear(); |
65 | addPlugin(new NotifyBySound(this)); |
66 | addPlugin(new NotifyByPopup(this)); |
67 | addPlugin(new NotifyByExecute(this)); |
68 | addPlugin(new NotifyByLogfile(this)); |
69 | //TODO reactivate on Mac/Win when KWindowSystem::demandAttention will implemented on this system. |
70 | #ifndef Q_WS_MAC |
71 | addPlugin(new NotifyByTaskbar(this)); |
72 | #endif |
73 | addPlugin(new NotifyByKTTS(this)); |
74 | |
75 | KService::List offers = KServiceTypeTrader::self()->query("KNotify/NotifyMethod"); |
76 | |
77 | QVariantList args; |
78 | QString error; |
79 | |
80 | foreach (const KService::Ptr service, offers) |
81 | { |
82 | KNotifyPlugin *plugin = service->createInstance<KNotifyPlugin>(this, args, &error); |
83 | if (plugin) |
84 | { |
85 | addPlugin(plugin); |
86 | } |
87 | else |
88 | { |
89 | kDebug() << "Could not load plugin"<< service->name() << "due to:"<< error; |
90 | } |
91 | } |
92 | } |
93 | |
94 | void KNotify::addPlugin( KNotifyPlugin * p ) |
95 | { |
96 | m_plugins[p->optionName()]=p; |
97 | connect(p,SIGNAL(finished( int )) , this , SLOT(slotPluginFinished( int ) )); |
98 | connect(p,SIGNAL(actionInvoked( int , int )) , this , SIGNAL(notificationActivated( int , int ) )); |
99 | } |
100 | |
101 | |
102 | |
103 | void KNotify::reconfigure() |
104 | { |
105 | KGlobal::config()->reparseConfiguration(); |
106 | KNotifyConfig::reparseConfiguration(); |
107 | loadConfig(); |
108 | } |
109 | |
110 | void KNotify::closeNotification(int id) |
111 | { |
112 | if(!m_notifications.contains(id)) |
113 | return; |
114 | Event *e=m_notifications[id]; |
115 | |
116 | kDebug() << e->id << " ref="<< e->ref; |
117 | |
118 | //this has to be called before plugin->close or we will get double deletion because of slotPluginFinished |
119 | m_notifications.remove(id); |
120 | |
121 | if(e->ref>0) |
122 | { |
123 | e->ref++; |
124 | KNotifyPlugin *plugin; |
125 | foreach(plugin , m_plugins) |
126 | { |
127 | plugin->close( id ); |
128 | } |
129 | } |
130 | notificationClosed(id); |
131 | delete e; |
132 | } |
133 | |
134 | int KNotify::event( const QString & event, const QString & appname, const ContextList & contexts, const QString & title, const QString & text, const KNotifyImage & image, const QStringList & actions, int timeout, WId winId ) |
135 | { |
136 | m_counter++; |
137 | Event *e=new Event(appname , contexts , event ); |
138 | e->id = m_counter; |
139 | e->ref = 1; |
140 | |
141 | e->config.title=title; |
142 | e->config.text=text; |
143 | e->config.actions=actions; |
144 | e->config.image=image; |
145 | e->config.timeout=timeout; |
146 | e->config.winId=(WId)winId; |
147 | |
148 | m_notifications.insert(m_counter,e); |
149 | emitEvent(e); |
150 | |
151 | e->ref--; |
152 | kDebug() << e->id << " ref="<< e->ref; |
153 | if(e->ref==0) |
154 | { |
155 | m_notifications.remove(e->id); |
156 | delete e; |
157 | return 0; |
158 | } |
159 | return m_counter; |
160 | } |
161 | |
162 | void KNotify::update(int id, const QString &title, const QString &text, const KNotifyImage& image, const QStringList& actions) |
163 | { |
164 | if(!m_notifications.contains(id)) |
165 | return; |
166 | |
167 | Event *e=m_notifications[id]; |
168 | |
169 | e->config.title=title; |
170 | e->config.text=text; |
171 | e->config.image = image; |
172 | e->config.actions = actions; |
173 | |
174 | foreach(KNotifyPlugin *p, m_plugins) |
175 | { |
176 | p->update(id, &e->config); |
177 | } |
178 | } |
179 | void KNotify::reemit(int id, const ContextList& contexts) |
180 | { |
181 | if(!m_notifications.contains(id)) |
182 | return; |
183 | Event *e=m_notifications[id]; |
184 | e->config.contexts=contexts; |
185 | |
186 | emitEvent(e); |
187 | } |
188 | |
189 | void KNotify::emitEvent(Event *e) |
190 | { |
191 | QString presentstring=e->config.readEntry("Action"); |
192 | QStringList presents=presentstring.split ( |
193 | |
194 | if (!e->config.contexts.isEmpty() && !presents.first().isEmpty()) |
195 | { |
196 | //Check whether the present actions are absolute, relative or invalid |
197 | bool relative = presents.first().startsWith( |
198 | bool valid = true; |
199 | foreach (const QString & presentAction, presents) |
200 | valid &= ((presentAction.startsWith( |
201 | if (!valid) |
202 | { |
203 | kDebug() << "Context "<< e->config.contexts << "present actions are invalid! Fallback to default present actions"; |
204 | Event defaultEvent = Event(e->config.appname, ContextList(), e->config.eventid); |
205 | QString defaultPresentstring=defaultEvent.config.readEntry("Action"); |
206 | presents = defaultPresentstring.split ( |
207 | } else if (relative) |
208 | { |
209 | // Obtain the list of present actions without context |
210 | Event noContextEvent = Event(e->config.appname, ContextList(), e->config.eventid); |
211 | QString noContextPresentstring = noContextEvent.config.readEntry("Action"); |
212 | QSet<QString> noContextPresents = noContextPresentstring.split ( |
213 | foreach (const QString & presentAction, presents) |
214 | { |
215 | if (presentAction.startsWith( |
216 | noContextPresents << presentAction.mid(1); |
217 | else |
218 | noContextPresents.remove(presentAction.mid(1)); |
219 | } |
220 | presents = noContextPresents.toList(); |
221 | } |
222 | } |
223 | |
224 | foreach(const QString & action , presents) |
225 | { |
226 | if(!m_plugins.contains(action)) |
227 | continue; |
228 | KNotifyPlugin *p=m_plugins[action]; |
229 | e->ref++; |
230 | p->notify(e->id,&e->config); |
231 | } |
232 | } |
233 | |
234 | void KNotify::slotPluginFinished( int id ) |
235 | { |
236 | if(!m_notifications.contains(id)) |
237 | return; |
238 | Event *e=m_notifications[id]; |
239 | kDebug() << e->id << " ref="<< e->ref ; |
240 | e->ref--; |
241 | if(e->ref==0) |
242 | closeNotification( id ); |
243 | } |
244 | |
245 | KNotifyAdaptor::KNotifyAdaptor(QObject *parent) |
246 | : QDBusAbstractAdaptor(parent) |
247 | { |
248 | setAutoRelaySignals(true); |
249 | } |
250 | |
251 | void KNotifyAdaptor::reconfigure() |
252 | { |
253 | static_cast<KNotify *>(parent())->reconfigure(); |
254 | } |
255 | |
256 | void KNotifyAdaptor::closeNotification(int id) |
257 | { |
258 | static_cast<KNotify *>(parent())->closeNotification(id); |
259 | } |
260 | |
261 | int KNotifyAdaptor::event(const QString &event, const QString &fromApp, const QVariantList& contexts, |
262 | const QString &title, const QString &text, const QByteArray& image, const QStringList& actions, |
263 | int timeout, qlonglong winId) |
264 | // const QDBusMessage & , int _return ) |
265 | |
266 | { |
267 | /* I'm not sure this is the right way to read a a(ss) type, but it seems to work */ |
268 | ContextList contextlist; |
269 | QString context_key; |
270 | foreach( const QVariant &v , contexts) |
271 | { |
272 | /* this code doesn't work |
273 | QVariantList vl=v.toList(); |
274 | if(vl.count() != 2) |
275 | { |
276 | kWarning() << "Bad structure passed as argument" ; |
277 | continue; |
278 | } |
279 | contextlist << qMakePair(vl[0].toString() , vl[1].toString());*/ |
280 | QString s=v.toString(); |
281 | if(context_key.isEmpty()) |
282 | context_key=s; |
283 | else { |
284 | contextlist << qMakePair(context_key , s); |
285 | context_key = ""; |
286 | } |
287 | } |
288 | |
289 | return static_cast<KNotify *>(parent())->event(event, fromApp, contextlist, title, text, image, actions, timeout, WId(winId)); |
290 | } |
291 | |
292 | void KNotifyAdaptor::reemit(int id, const QVariantList& contexts) |
293 | { |
294 | ContextList contextlist; |
295 | QString context_key; |
296 | foreach( const QVariant &v , contexts) |
297 | { |
298 | QString s=v.toString(); |
299 | if(context_key.isEmpty()) |
300 | context_key=s; |
301 | else { |
302 | contextlist << qMakePair(context_key , s); |
303 | context_key = ""; |
304 | } |
305 | } |
306 | static_cast<KNotify *>(parent())->reemit(id, contextlist); |
307 | } |
308 | |
309 | |
310 | void KNotifyAdaptor::update(int id, const QString &title, const QString &text, const QByteArray& image, const QStringList& actions ) |
311 | { |
312 | static_cast<KNotify *>(parent())->update(id, title, text, image, actions); |
313 | } |
314 | |
315 | #include "knotify.moc" |
316 | |
317 | // vim: sw=4 sts=4 ts=8 et |
318 | |
319 | |
320 |