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