Plasma
service.cpp
Go to the documentation of this file.
00001 /* 00002 * Copyright 2008 Aaron Seigo <aseigo@kde.org> 00003 * 00004 * This program is free software; you can redistribute it and/or modify 00005 * it under the terms of the GNU Library General Public License as 00006 * published by the Free Software Foundation; either version 2, or 00007 * (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details 00013 * 00014 * You should have received a copy of the GNU Library General Public 00015 * License along with this program; if not, write to the 00016 * Free Software Foundation, Inc., 00017 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00018 */ 00019 00020 #include "service.h" 00021 #include "servicejob.h" 00022 #include "private/authorizationmanager_p.h" 00023 #include "private/service_p.h" 00024 #include "private/serviceprovider_p.h" 00025 00026 #include "config-plasma.h" 00027 00028 #include <QFile> 00029 #include <QTimer> 00030 00031 #include <kdebug.h> 00032 #include <kservice.h> 00033 #include <kservicetypetrader.h> 00034 #include <ksharedconfig.h> 00035 #include <kstandarddirs.h> 00036 #include <dnssd/publicservice.h> 00037 #include <dnssd/servicebrowser.h> 00038 00039 #include "configloader.h" 00040 #include "version.h" 00041 #include "private/configloader_p.h" 00042 #include "private/remoteservice_p.h" 00043 #include "private/remoteservicejob_p.h" 00044 #include "pluginloader.h" 00045 00046 namespace Plasma 00047 { 00048 00049 Service::Service(QObject *parent) 00050 : QObject(parent), 00051 d(new ServicePrivate(this)) 00052 { 00053 } 00054 00055 Service::Service(QObject *parent, const QVariantList &args) 00056 : QObject(parent), 00057 d(new ServicePrivate(this)) 00058 { 00059 Q_UNUSED(args) 00060 } 00061 00062 Service::~Service() 00063 { 00064 d->unpublish(); 00065 delete d; 00066 } 00067 00068 Service *Service::load(const QString &name, QObject *parent) 00069 { 00070 QVariantList args; 00071 return load(name, args, parent); 00072 } 00073 00074 Service *Service::load(const QString &name, const QVariantList &args, QObject *parent) 00075 { 00076 return PluginLoader::pluginLoader()->loadService(name, args, parent); 00077 } 00078 00079 Service *Service::access(const KUrl &url, QObject *parent) 00080 { 00081 return new RemoteService(parent, url); 00082 } 00083 00084 void ServicePrivate::jobFinished(KJob *job) 00085 { 00086 emit q->finished(static_cast<ServiceJob*>(job)); 00087 } 00088 00089 void ServicePrivate::associatedWidgetDestroyed(QObject *obj) 00090 { 00091 associatedWidgets.remove(static_cast<QWidget*>(obj)); 00092 } 00093 00094 void ServicePrivate::associatedGraphicsWidgetDestroyed(QObject *obj) 00095 { 00096 associatedGraphicsWidgets.remove(static_cast<QGraphicsWidget*>(obj)); 00097 } 00098 00099 void ServicePrivate::publish(AnnouncementMethods methods, const QString &name, const PackageMetadata &metadata) 00100 { 00101 #ifdef ENABLE_REMOTE_WIDGETS 00102 if (!serviceProvider) { 00103 AuthorizationManager::self()->d->prepareForServicePublication(); 00104 00105 serviceProvider = new ServiceProvider(name, q); 00106 00107 if (methods.testFlag(ZeroconfAnnouncement) && 00108 (DNSSD::ServiceBrowser::isAvailable() == DNSSD::ServiceBrowser::Working)) { 00109 //TODO: dynamically pick a free port number. 00110 publicService = new DNSSD::PublicService(name, "_plasma._tcp", 4000); 00111 00112 QMap<QString, QByteArray> textData; 00113 textData["name"] = name.toUtf8(); 00114 textData["plasmoidname"] = metadata.name().toUtf8(); 00115 textData["description"] = metadata.description().toUtf8(); 00116 textData["icon"] = metadata.icon().toUtf8(); 00117 publicService->setTextData(textData); 00118 kDebug() << "about to publish"; 00119 00120 publicService->publishAsync(); 00121 } else if (methods.testFlag(ZeroconfAnnouncement) && 00122 (DNSSD::ServiceBrowser::isAvailable() != DNSSD::ServiceBrowser::Working)) { 00123 kDebug() << "sorry, but your zeroconf daemon doesn't seem to be running."; 00124 } 00125 } else { 00126 kDebug() << "already published!"; 00127 } 00128 #else 00129 kWarning() << "libplasma is compiled without support for remote widgets. not publishing."; 00130 #endif 00131 } 00132 00133 void ServicePrivate::unpublish() 00134 { 00135 delete serviceProvider; 00136 serviceProvider = 0; 00137 00138 delete publicService; 00139 publicService = 0; 00140 } 00141 00142 bool ServicePrivate::isPublished() const 00143 { 00144 if (serviceProvider) { 00145 return true; 00146 } else { 00147 return false; 00148 } 00149 } 00150 00151 KConfigGroup ServicePrivate::dummyGroup() 00152 { 00153 if (!dummyConfig) { 00154 dummyConfig = new KConfig(QString(), KConfig::SimpleConfig); 00155 } 00156 00157 return KConfigGroup(dummyConfig, "DummyGroup"); 00158 } 00159 00160 void Service::setDestination(const QString &destination) 00161 { 00162 d->destination = destination; 00163 } 00164 00165 QString Service::destination() const 00166 { 00167 return d->destination; 00168 } 00169 00170 QStringList Service::operationNames() const 00171 { 00172 if (!d->config) { 00173 kDebug() << "No valid operations scheme has been registered"; 00174 return QStringList(); 00175 } 00176 00177 return d->config->groupList(); 00178 } 00179 00180 KConfigGroup Service::operationDescription(const QString &operationName) 00181 { 00182 if (!d->config) { 00183 kDebug() << "No valid operations scheme has been registered"; 00184 return d->dummyGroup(); 00185 } 00186 00187 d->config->writeConfig(); 00188 KConfigGroup params(d->config->config(), operationName); 00189 //kDebug() << "operation" << operationName 00190 // << "requested, has keys" << params.keyList() << "from" 00191 // << d->config->config()->name(); 00192 return params; 00193 } 00194 00195 QMap<QString, QVariant> Service::parametersFromDescription(const KConfigGroup &description) 00196 { 00197 QMap<QString, QVariant> params; 00198 00199 if (!d->config || !description.isValid()) { 00200 return params; 00201 } 00202 00203 const QString op = description.name(); 00204 foreach (const QString &key, description.keyList()) { 00205 KConfigSkeletonItem *item = d->config->findItem(op, key); 00206 if (item) { 00207 params.insert(key, description.readEntry(key, item->property())); 00208 } 00209 } 00210 00211 return params; 00212 } 00213 00214 ServiceJob *Service::startOperationCall(const KConfigGroup &description, QObject *parent) 00215 { 00216 // TODO: nested groups? 00217 ServiceJob *job = 0; 00218 const QString op = description.isValid() ? description.name() : QString(); 00219 00220 RemoteService *rs = qobject_cast<RemoteService *>(this); 00221 if (!op.isEmpty() && rs && !rs->isReady()) { 00222 // if we have an operation, but a non-ready remote service, just let it through 00223 kDebug() << "Remote service is not ready; queueing operation"; 00224 QMap<QString, QVariant> params; 00225 job = createJob(op, params); 00226 RemoteServiceJob *rsj = qobject_cast<RemoteServiceJob *>(job); 00227 if (rsj) { 00228 rsj->setDelayedDescription(description); 00229 } 00230 } else if (!d->config) { 00231 kDebug() << "No valid operations scheme has been registered"; 00232 } else if (!op.isEmpty() && d->config->hasGroup(op)) { 00233 if (d->disabledOperations.contains(op)) { 00234 kDebug() << "Operation" << op << "is disabled"; 00235 } else { 00236 QMap<QString, QVariant> params = parametersFromDescription(description); 00237 job = createJob(op, params); 00238 } 00239 } else { 00240 kDebug() << "Not a valid group!"<<d->config->groupList(); 00241 } 00242 00243 if (!job) { 00244 job = new NullServiceJob(destination(), op, this); 00245 } 00246 00247 job->setParent(parent ? parent : this); 00248 connect(job, SIGNAL(finished(KJob*)), this, SLOT(jobFinished(KJob*))); 00249 QTimer::singleShot(0, job, SLOT(autoStart())); 00250 return job; 00251 } 00252 00253 void Service::associateWidget(QWidget *widget, const QString &operation) 00254 { 00255 if (!widget) { 00256 return; 00257 } 00258 00259 disassociateWidget(widget); 00260 d->associatedWidgets.insert(widget, operation); 00261 connect(widget, SIGNAL(destroyed(QObject*)), this, SLOT(associatedWidgetDestroyed(QObject*))); 00262 00263 widget->setEnabled(!d->disabledOperations.contains(operation)); 00264 } 00265 00266 void Service::disassociateWidget(QWidget *widget) 00267 { 00268 if (!widget) { 00269 return; 00270 } 00271 00272 disconnect(widget, SIGNAL(destroyed(QObject*)), 00273 this, SLOT(associatedWidgetDestroyed(QObject*))); 00274 d->associatedWidgets.remove(widget); 00275 } 00276 00277 void Service::associateWidget(QGraphicsWidget *widget, const QString &operation) 00278 { 00279 if (!widget) { 00280 return; 00281 } 00282 00283 disassociateWidget(widget); 00284 d->associatedGraphicsWidgets.insert(widget, operation); 00285 connect(widget, SIGNAL(destroyed(QObject*)), 00286 this, SLOT(associatedGraphicsWidgetDestroyed(QObject*))); 00287 00288 widget->setEnabled(!d->disabledOperations.contains(operation)); 00289 } 00290 00291 void Service::disassociateWidget(QGraphicsWidget *widget) 00292 { 00293 if (!widget) { 00294 return; 00295 } 00296 00297 disconnect(widget, SIGNAL(destroyed(QObject*)), 00298 this, SLOT(associatedGraphicsWidgetDestroyed(QObject*))); 00299 d->associatedGraphicsWidgets.remove(widget); 00300 } 00301 00302 QString Service::name() const 00303 { 00304 return d->name; 00305 } 00306 00307 void Service::setName(const QString &name) 00308 { 00309 d->name = name; 00310 00311 // now reset the config, which may be based on our name 00312 delete d->config; 00313 d->config = 0; 00314 00315 delete d->dummyConfig; 00316 d->dummyConfig = 0; 00317 00318 registerOperationsScheme(); 00319 00320 emit serviceReady(this); 00321 } 00322 00323 void Service::setOperationEnabled(const QString &operation, bool enable) 00324 { 00325 if (!d->config || !d->config->hasGroup(operation)) { 00326 return; 00327 } 00328 00329 if (enable) { 00330 d->disabledOperations.remove(operation); 00331 } else { 00332 d->disabledOperations.insert(operation); 00333 } 00334 00335 { 00336 QHashIterator<QWidget *, QString> it(d->associatedWidgets); 00337 while (it.hasNext()) { 00338 it.next(); 00339 if (it.value() == operation) { 00340 it.key()->setEnabled(enable); 00341 } 00342 } 00343 } 00344 00345 { 00346 QHashIterator<QGraphicsWidget *, QString> it(d->associatedGraphicsWidgets); 00347 while (it.hasNext()) { 00348 it.next(); 00349 if (it.value() == operation) { 00350 it.key()->setEnabled(enable); 00351 } 00352 } 00353 } 00354 } 00355 00356 bool Service::isOperationEnabled(const QString &operation) const 00357 { 00358 return d->config && d->config->hasGroup(operation) && !d->disabledOperations.contains(operation); 00359 } 00360 00361 void Service::setOperationsScheme(QIODevice *xml) 00362 { 00363 delete d->config; 00364 00365 delete d->dummyConfig; 00366 d->dummyConfig = 0; 00367 00368 KSharedConfigPtr c = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig); 00369 d->config = new ConfigLoader(c, xml, this); 00370 d->config->d->setWriteDefaults(true); 00371 00372 emit operationsChanged(); 00373 00374 { 00375 QHashIterator<QWidget *, QString> it(d->associatedWidgets); 00376 while (it.hasNext()) { 00377 it.next(); 00378 it.key()->setEnabled(d->config->hasGroup(it.value())); 00379 } 00380 } 00381 00382 { 00383 QHashIterator<QGraphicsWidget *, QString> it(d->associatedGraphicsWidgets); 00384 while (it.hasNext()) { 00385 it.next(); 00386 it.key()->setEnabled(d->config->hasGroup(it.value())); 00387 } 00388 } 00389 } 00390 00391 void Service::registerOperationsScheme() 00392 { 00393 if (d->config) { 00394 // we've already done our job. let's go home. 00395 return; 00396 } 00397 00398 if (d->name.isEmpty()) { 00399 kDebug() << "No name found"; 00400 return; 00401 } 00402 00403 const QString path = KStandardDirs::locate("data", "plasma/services/" + d->name + ".operations"); 00404 00405 if (path.isEmpty()) { 00406 kDebug() << "Cannot find operations description:" << d->name << ".operations"; 00407 return; 00408 } 00409 00410 QFile file(path); 00411 setOperationsScheme(&file); 00412 } 00413 00414 } // namespace Plasma 00415 00416 #include "service.moc" 00417
KDE 4.7 API Reference