1/*
2 This file is part of libkresources.
3
4 Copyright (c) 2002 Tobias Koenig <tokoe@kde.org>
5 Copyright (c) 2002 Jan-Pascal van Best <janpascal@vanbest.org>
6 Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>
7
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Library General Public
10 License as published by the Free Software Foundation; either
11 version 2 of the License, or (at your option) any later version.
12
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Library General Public License for more details.
17
18 You should have received a copy of the GNU Library General Public License
19 along with this library; see the file COPYING.LIB. If not, write to
20 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 Boston, MA 02110-1301, USA.
22*/
23#include "managerimpl.h"
24
25#include <kaboutdata.h>
26#include <krandom.h>
27#include <kdebug.h>
28#include <kconfig.h>
29#include <kstandarddirs.h>
30#include <kconfiggroup.h>
31
32#include <QtDBus/QtDBus>
33
34#include "resource.h"
35#include "factory.h"
36#include "manager.h"
37#include "kresourcesmanageradaptor.h"
38
39using namespace KRES;
40
41class ManagerImpl::ManagerImplPrivate
42{
43 public:
44 ManagerNotifier *mNotifier;
45 QString mFamily;
46 KConfig *mConfig;
47 KConfig *mStdConfig;
48 Resource *mStandard;
49 Factory *mFactory;
50 Resource::List mResources;
51 QString mId;
52 bool mConfigRead;
53
54};
55
56ManagerImpl::ManagerImpl( ManagerNotifier *notifier, const QString &family )
57 : d( new ManagerImplPrivate )
58{
59 d->mNotifier = notifier;
60 d->mFamily = family;
61 d->mConfig = 0;
62 d->mStdConfig = 0;
63 d->mStandard = 0;
64 d->mFactory = 0;
65 d->mConfigRead = false;
66
67 new KResourcesManagerAdaptor( this );
68 const QString dBusPath = QLatin1String( "/ManagerIface_" ) + family;
69 QDBusConnection::sessionBus().registerObject( dBusPath, this );
70 kDebug();
71
72 d->mId = KRandom::randomString( 8 );
73
74 // Register with D-Bus
75 QDBusConnection::sessionBus().registerService( QLatin1String("org.kde.KResourcesManager") );
76
77 QDBusConnection::sessionBus().connect( QString(), dBusPath,
78 QLatin1String("org.kde.KResourcesManager"), QLatin1String("signalKResourceAdded"),
79 this, SLOT(dbusKResourceAdded(QString,QString)));
80 QDBusConnection::sessionBus().connect( QString(), dBusPath,
81 QLatin1String("org.kde.KResourcesManager"), QLatin1String("signalKResourceModified"),
82 this, SLOT(dbusKResourceModified(QString,QString)));
83 QDBusConnection::sessionBus().connect( QString(), dBusPath,
84 QLatin1String("org.kde.KResourcesManager"), QLatin1String("signalKResourceDeleted"),
85 this, SLOT(dbusKResourceDeleted(QString,QString)));
86}
87
88ManagerImpl::~ManagerImpl()
89{
90 kDebug();
91
92 qDeleteAll( d->mResources );
93 delete d->mStdConfig;
94 delete d;
95}
96
97void ManagerImpl::createStandardConfig()
98{
99 if ( !d->mStdConfig ) {
100 QString file = defaultConfigFile( d->mFamily );
101 d->mStdConfig = new KConfig( file );
102 }
103
104 d->mConfig = d->mStdConfig;
105}
106
107void ManagerImpl::readConfig( KConfig *cfg )
108{
109 kDebug();
110
111 if ( d->mFactory ) {
112 d->mFactory->reloadConfig();
113 } else {
114 d->mFactory = Factory::self( d->mFamily );
115 }
116
117 if ( !cfg ) {
118 createStandardConfig();
119 } else {
120 d->mConfig = cfg;
121 }
122
123 d->mStandard = 0;
124 KConfigGroup group = d->mConfig->group( "General" );
125
126 QStringList keys = group.readEntry( "ResourceKeys", QStringList() );
127 keys += group.readEntry( "PassiveResourceKeys", QStringList() );
128
129 const QString standardKey = group.readEntry( "Standard" );
130
131 for ( QStringList::const_iterator it = keys.constBegin(); it != keys.constEnd(); ++it ) {
132 readResourceConfig( *it, false );
133 }
134
135 d->mConfigRead = true;
136}
137
138void ManagerImpl::writeConfig( KConfig *cfg )
139{
140 kDebug();
141
142 if ( !cfg ) {
143 createStandardConfig();
144 } else {
145 d->mConfig = cfg;
146 }
147
148 QStringList activeKeys;
149 QStringList passiveKeys;
150
151 // First write all keys, collect active and passive keys on the way
152 Resource::List::Iterator it;
153 for ( it = d->mResources.begin(); it != d->mResources.end(); ++it ) {
154 writeResourceConfig( *it, false );
155
156 QString key = ( *it )->identifier();
157 if ( ( *it )->isActive() ) {
158 activeKeys.append( key );
159 } else {
160 passiveKeys.append( key );
161 }
162 }
163
164 // And then the general group
165
166 kDebug() << "Saving general info";
167 KConfigGroup group = d->mConfig->group( "General" );
168 group.writeEntry( "ResourceKeys", activeKeys );
169 group.writeEntry( "PassiveResourceKeys", passiveKeys );
170 if ( d->mStandard ) {
171 group.writeEntry( "Standard", d->mStandard->identifier() );
172 } else {
173 group.writeEntry( "Standard", QString() );
174 }
175
176 group.sync();
177 kDebug() << "finished";
178}
179
180void ManagerImpl::add( Resource *resource )
181{
182 resource->setActive( true );
183
184 if ( d->mResources.isEmpty() ) {
185 d->mStandard = resource;
186 }
187
188 d->mResources.append( resource );
189
190 if ( d->mConfigRead ) {
191 writeResourceConfig( resource, true );
192 }
193
194 signalKResourceAdded( d->mId, resource->identifier() );
195}
196
197void ManagerImpl::remove( Resource *resource )
198{
199 if ( d->mStandard == resource ) {
200 d->mStandard = 0;
201 }
202 removeResource( resource );
203
204 d->mResources.removeAll( resource );
205
206 signalKResourceDeleted( d->mId, resource->identifier() );
207
208 delete resource;
209
210 kDebug() << "Finished";
211}
212
213void ManagerImpl::change( Resource *resource )
214{
215 writeResourceConfig( resource, true );
216
217 signalKResourceModified( d->mId, resource->identifier() );
218}
219
220void ManagerImpl::setActive( Resource *resource, bool active )
221{
222 if ( resource && resource->isActive() != active ) {
223 resource->setActive( active );
224 }
225}
226
227Resource *ManagerImpl::standardResource()
228{
229 return d->mStandard;
230}
231
232void ManagerImpl::setStandardResource( Resource *resource )
233{
234 d->mStandard = resource;
235}
236
237// DBUS asynchronous functions
238
239void ManagerImpl::dbusKResourceAdded( const QString &managerId,
240 const QString &resourceId )
241{
242 if ( managerId == d->mId ) {
243 kDebug() << "Ignore D-Bus notification to myself";
244 return;
245 }
246 kDebug() << "Receive D-Bus call: added resource" << resourceId;
247
248 if ( getResource( resourceId ) ) {
249 kDebug() << "This resource is already known to me.";
250 }
251
252 if ( !d->mConfig ) {
253 createStandardConfig();
254 }
255
256 d->mConfig->reparseConfiguration();
257 Resource *resource = readResourceConfig( resourceId, true );
258
259 if ( resource ) {
260 d->mNotifier->notifyResourceAdded( resource );
261 } else {
262 kError() << "Received D-Bus: resource added for unknown resource"
263 << resourceId;
264 }
265}
266
267void ManagerImpl::dbusKResourceModified( const QString &managerId,
268 const QString &resourceId )
269{
270 if ( managerId == d->mId ) {
271 kDebug() << "Ignore D-Bus notification to myself";
272 return;
273 }
274 kDebug() << "Receive D-Bus call: modified resource" << resourceId;
275
276 Resource *resource = getResource( resourceId );
277 if ( resource ) {
278 d->mNotifier->notifyResourceModified( resource );
279 } else {
280 kError() << "Received D-Bus: resource modified for unknown resource"
281 << resourceId;
282 }
283}
284
285void ManagerImpl::dbusKResourceDeleted( const QString &managerId,
286 const QString &resourceId )
287{
288 if ( managerId == d->mId ) {
289 kDebug() << "Ignore D-Bus notification to myself";
290 return;
291 }
292 kDebug() << "Receive D-Bus call: deleted resource" << resourceId;
293
294 Resource *resource = getResource( resourceId );
295 if ( resource ) {
296 d->mNotifier->notifyResourceDeleted( resource );
297
298 kDebug() << "Removing item from mResources";
299 // Now delete item
300 if ( d->mStandard == resource ) {
301 d->mStandard = 0;
302 }
303 d->mResources.removeAll( resource );
304 } else {
305 kError() << "Received D-Bus: resource deleted for unknown resource"
306 << resourceId;
307 }
308}
309
310QStringList ManagerImpl::resourceNames()
311{
312 QStringList result;
313
314 Resource::List::ConstIterator it;
315 Resource::List::ConstIterator end(d->mResources.constEnd());
316 for ( it = d->mResources.constBegin(); it != end; ++it ) {
317 result.append( ( *it )->resourceName() );
318 }
319 return result;
320}
321
322Resource::List *ManagerImpl::resourceList()
323{
324 return &d->mResources;
325}
326
327QList<Resource *> ManagerImpl::resources()
328{
329 return QList<Resource *>( d->mResources );
330}
331
332QList<Resource *> ManagerImpl::resources( bool active )
333{
334 QList<Resource *> result;
335
336 for ( int i = 0; i < d->mResources.size(); ++i ) {
337 if ( d->mResources.at( i )->isActive() == active ) {
338 result.append( d->mResources.at( i ) );
339 }
340 }
341 return result;
342}
343
344Resource *ManagerImpl::readResourceConfig( const QString &identifier,
345 bool checkActive )
346{
347 kDebug() << identifier;
348
349 if ( !d->mFactory ) {
350 kError() << "mFactory is 0. Did the app forget to call readConfig?";
351 return 0;
352 }
353
354 KConfigGroup group = d->mConfig->group( QLatin1String("Resource_") + identifier );
355
356 QString type = group.readEntry( "ResourceType" );
357 QString name = group.readEntry( "ResourceName" );
358 Resource *resource = d->mFactory->resource( type, group );
359 if ( !resource ) {
360 kDebug() << "Failed to create resource with id" << identifier;
361 return 0;
362 }
363
364 if ( resource->identifier().isEmpty() ) {
365 resource->setIdentifier( identifier );
366 }
367
368 group = d->mConfig->group( "General" );
369
370 QString standardKey = group.readEntry( "Standard" );
371 if ( standardKey == identifier ) {
372 d->mStandard = resource;
373 }
374
375 if ( checkActive ) {
376 QStringList activeKeys = group.readEntry( "ResourceKeys", QStringList() );
377 resource->setActive( activeKeys.contains( identifier ) );
378 }
379 d->mResources.append( resource );
380
381 return resource;
382}
383
384void ManagerImpl::writeResourceConfig( Resource *resource, bool checkActive )
385{
386 QString key = resource->identifier();
387
388 kDebug() << "Saving resource" << key;
389
390 if ( !d->mConfig ) {
391 createStandardConfig();
392 }
393
394 KConfigGroup group( d->mConfig, QLatin1String("Resource_") + key );
395 resource->writeConfig( group );
396
397 group = d->mConfig->group( "General" );
398 QString standardKey = group.readEntry( "Standard" );
399
400 if ( resource == d->mStandard && standardKey != key ) {
401 group.writeEntry( "Standard", resource->identifier() );
402 } else if ( resource != d->mStandard && standardKey == key ) {
403 group.writeEntry( "Standard", "" );
404 }
405
406 if ( checkActive ) {
407 QStringList activeKeys = group.readEntry( "ResourceKeys", QStringList() );
408 QStringList passiveKeys = group.readEntry( "PassiveResourceKeys", QStringList() );
409 if ( resource->isActive() ) {
410 if ( passiveKeys.contains( key ) ) { // remove it from passive list
411 passiveKeys.removeAll( key );
412 group.writeEntry( "PassiveResourceKeys", passiveKeys );
413 }
414 if ( !activeKeys.contains( key ) ) { // add it to active list
415 activeKeys.append( key );
416 group.writeEntry( "ResourceKeys", activeKeys );
417 }
418 } else if ( !resource->isActive() ) {
419 if ( activeKeys.contains( key ) ) { // remove it from active list
420 activeKeys.removeAll( key );
421 group.writeEntry( "ResourceKeys", activeKeys );
422 }
423 if ( !passiveKeys.contains( key ) ) { // add it to passive list
424 passiveKeys.append( key );
425 group.writeEntry( "PassiveResourceKeys", passiveKeys );
426 }
427 }
428 }
429
430 d->mConfig->sync();
431}
432
433void ManagerImpl::removeResource( Resource *resource )
434{
435 QString key = resource->identifier();
436
437 if ( !d->mConfig ) {
438 createStandardConfig();
439 }
440
441 KConfigGroup group = d->mConfig->group( "General" );
442 QStringList activeKeys = group.readEntry( "ResourceKeys", QStringList() );
443 if ( activeKeys.contains( key ) ) {
444 activeKeys.removeAll( key );
445 group.writeEntry( "ResourceKeys", activeKeys );
446 } else {
447 QStringList passiveKeys= group.readEntry( "PassiveResourceKeys", QStringList() );
448 passiveKeys.removeAll( key );
449 group.writeEntry( "PassiveResourceKeys", passiveKeys );
450 }
451
452 QString standardKey = group.readEntry( "Standard" );
453 if ( standardKey == key ) {
454 group.writeEntry( "Standard", "" );
455 }
456
457 d->mConfig->deleteGroup( QLatin1String("Resource_") + resource->identifier() );
458 group.sync();
459}
460
461Resource *ManagerImpl::getResource( const QString &identifier )
462{
463 Resource::List::ConstIterator it;
464 for ( it = d->mResources.constBegin(); it != d->mResources.constEnd(); ++it ) {
465 if ( ( *it )->identifier() == identifier ) {
466 return *it;
467 }
468 }
469 return 0;
470}
471
472QString ManagerImpl::defaultConfigFile( const QString &family )
473{
474 return KStandardDirs::locateLocal( "config",
475 QString::fromLatin1( "kresources/%1/stdrc" ).arg( family ) );
476}
477
478