• Skip to content
  • Skip to link menu
KDE 4.4 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

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 <ktemporaryfile.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 
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     //TODO: scripting API support
00070     if (name.isEmpty()) {
00071         return new NullService(QString(), parent);
00072     }
00073 
00074     QString constraint = QString("[X-KDE-PluginInfo-Name] == '%1'").arg(name);
00075     KService::List offers = KServiceTypeTrader::self()->query("Plasma/Service", constraint);
00076 
00077     if (offers.isEmpty()) {
00078         kDebug() << "offers is empty for " << name;
00079         return new NullService(name, parent);
00080     }
00081 
00082     KService::Ptr offer = offers.first();
00083     QString error;
00084     QVariantList args;
00085     //args << name;
00086     Service *service = 0;
00087 
00088     if (Plasma::isPluginVersionCompatible(KPluginLoader(*offer).pluginVersion())) {
00089         service = offer->createInstance<Plasma::Service>(parent, args, &error);
00090     }
00091 
00092     if (!service) {
00093         kDebug() << "Couldn't load Service \"" << name << "\"! reason given: " << error;
00094         return new NullService(name, parent);
00095     }
00096 
00097     if (service->name().isEmpty()) {
00098         service->setName(name);
00099     }
00100 
00101     return service;
00102 }
00103 
00104 Service *Service::access(const KUrl &url, QObject *parent)
00105 {
00106     return new RemoteService(parent, url);
00107 }
00108 
00109 void ServicePrivate::jobFinished(KJob *job)
00110     {
00111         emit q->finished(static_cast<ServiceJob*>(job));
00112     }
00113 
00114     void ServicePrivate::associatedWidgetDestroyed(QObject *obj)
00115     {
00116         associatedWidgets.remove(static_cast<QWidget*>(obj));
00117     }
00118 
00119     void ServicePrivate::associatedGraphicsWidgetDestroyed(QObject *obj)
00120     {
00121         associatedGraphicsWidgets.remove(static_cast<QGraphicsWidget*>(obj));
00122     }
00123 
00124     void ServicePrivate::publish(AnnouncementMethods methods, const QString &name, PackageMetadata metadata)
00125     {
00126     #ifdef ENABLE_REMOTE_WIDGETS
00127         if (!serviceProvider) {
00128             AuthorizationManager::self()->d->prepareForServicePublication();
00129 
00130             serviceProvider = new ServiceProvider(name, q);
00131 
00132             if (methods.testFlag(ZeroconfAnnouncement) &&
00133                 (DNSSD::ServiceBrowser::isAvailable() == DNSSD::ServiceBrowser::Working)) {
00134                 //TODO: dynamically pick a free port number.
00135                 publicService = new DNSSD::PublicService(name, "_plasma._tcp", 4000);
00136 
00137                 QMap<QString, QByteArray> textData;
00138                 textData["name"] = name.toUtf8();
00139                 textData["plasmoidname"] = metadata.name().toUtf8();
00140                 textData["description"] = metadata.description().toUtf8();
00141                 publicService->setTextData(textData);
00142                 kDebug() << "about to publish";
00143 
00144                 publicService->publishAsync();
00145             } else if (methods.testFlag(ZeroconfAnnouncement) &&
00146                        (DNSSD::ServiceBrowser::isAvailable() != DNSSD::ServiceBrowser::Working)) {
00147                 kDebug() << "sorry, but your zeroconf daemon doesn't seem to be running.";
00148             }
00149         } else {
00150             kDebug() << "already published!";
00151         }
00152     #else
00153     kWarning() << "libplasma is compiled without support for remote widgets. not publishing.";
00154     #endif
00155     }
00156 
00157     void ServicePrivate::unpublish()
00158     {
00159         if (serviceProvider) {
00160             delete serviceProvider;
00161             serviceProvider = 0;
00162         }
00163 
00164         if (publicService) {
00165             delete publicService;
00166             publicService = 0;
00167         }
00168     }
00169 
00170     bool ServicePrivate::isPublished() const
00171     {
00172         if (serviceProvider) {
00173             return true;
00174         } else {
00175             return false;
00176         }
00177     }
00178 
00179     KConfigGroup ServicePrivate::dummyGroup()
00180     {
00181         if (!dummyConfig) {
00182             if (!tempFile) {
00183                 tempFile = new KTemporaryFile;
00184                 tempFile->open();
00185             }
00186 
00187             dummyConfig = new KConfig(tempFile->fileName());
00188         }
00189 
00190         return KConfigGroup(dummyConfig, "DummyGroup");
00191     }
00192 
00193 void Service::setDestination(const QString &destination)
00194 {
00195     d->destination = destination;
00196 }
00197 
00198 QString Service::destination() const
00199 {
00200     return d->destination;
00201 }
00202 
00203 QStringList Service::operationNames() const
00204 {
00205     if (!d->config) {
00206         kDebug() << "No valid operations scheme has been registered";
00207         return QStringList();
00208     }
00209 
00210     return d->config->groupList();
00211 }
00212 
00213 KConfigGroup Service::operationDescription(const QString &operationName)
00214 {
00215     if (!d->config) {
00216         kDebug() << "No valid operations scheme has been registered";
00217         return d->dummyGroup();
00218     }
00219 
00220     d->config->writeConfig();
00221     KConfigGroup params(d->config->config(), operationName);
00222     //kDebug() << "operation" << operationName
00223     //         << "requested, has keys" << params.keyList() << "from"
00224     //         << d->config->config()->name();
00225     return params;
00226 }
00227 
00228 QMap<QString, QVariant> Service::parametersFromDescription(const KConfigGroup &description)
00229 {
00230     QMap<QString, QVariant> params;
00231 
00232     if (!d->config || !description.isValid()) {
00233         return params;
00234     }
00235 
00236     const QString op = description.name();
00237     foreach (const QString &key, description.keyList()) {
00238         KConfigSkeletonItem *item = d->config->findItem(op, key);
00239         if (item) {
00240             params.insert(key, description.readEntry(key, item->property()));
00241         }
00242     }
00243 
00244     return params;
00245 }
00246 
00247 ServiceJob *Service::startOperationCall(const KConfigGroup &description, QObject *parent)
00248 {
00249     // TODO: nested groups?
00250     ServiceJob *job = 0;
00251     const QString op = description.isValid() ? description.name() : QString();
00252 
00253     RemoteService *rs = qobject_cast<RemoteService *>(this);
00254     if (!op.isEmpty() && rs && !rs->isReady()) {
00255         // if we have an operation, but a non-ready remote service, just let it through
00256         kDebug() << "Remote service is not ready; queueing operation";
00257         QMap<QString, QVariant> params;
00258         job = createJob(op, params);
00259         RemoteServiceJob *rsj = qobject_cast<RemoteServiceJob *>(job);
00260         if (rsj) {
00261             rsj->setDelayedDescription(description);
00262         }
00263     } else if (!d->config) {
00264         kDebug() << "No valid operations scheme has been registered";
00265     } else if (!op.isEmpty() && d->config->hasGroup(op)) {
00266         if (d->disabledOperations.contains(op)) {
00267             kDebug() << "Operation" << op << "is disabled";
00268         } else {
00269             QMap<QString, QVariant> params = parametersFromDescription(description);
00270             job = createJob(op, params);
00271         }
00272     } else {
00273         kDebug() << "Not a valid group!";
00274     }
00275 
00276     if (!job) {
00277         job = new NullServiceJob(destination(), op, this);
00278     }
00279 
00280     job->setParent(parent ? parent : this);
00281     connect(job, SIGNAL(finished(KJob*)), this, SLOT(jobFinished(KJob*)));
00282     QTimer::singleShot(0, job, SLOT(slotStart()));
00283     return job;
00284 }
00285 
00286 void Service::associateWidget(QWidget *widget, const QString &operation)
00287 {
00288     disassociateWidget(widget);
00289     d->associatedWidgets.insert(widget, operation);
00290     connect(widget, SIGNAL(destroyed(QObject*)), this, SLOT(associatedWidgetDestroyed(QObject*)));
00291 
00292     widget->setEnabled(!d->disabledOperations.contains(operation));
00293 }
00294 
00295 void Service::disassociateWidget(QWidget *widget)
00296 {
00297     disconnect(widget, SIGNAL(destroyed(QObject*)),
00298                this, SLOT(associatedWidgetDestroyed(QObject*)));
00299     d->associatedWidgets.remove(widget);
00300 }
00301 
00302 void Service::associateWidget(QGraphicsWidget *widget, const QString &operation)
00303 {
00304     disassociateWidget(widget);
00305     d->associatedGraphicsWidgets.insert(widget, operation);
00306     connect(widget, SIGNAL(destroyed(QObject*)),
00307             this, SLOT(associatedGraphicsWidgetDestroyed(QObject*)));
00308 
00309     widget->setEnabled(!d->disabledOperations.contains(operation));
00310 }
00311 
00312 void Service::disassociateWidget(QGraphicsWidget *widget)
00313 {
00314     disconnect(widget, SIGNAL(destroyed(QObject*)),
00315                this, SLOT(associatedGraphicsWidgetDestroyed(QObject*)));
00316     d->associatedGraphicsWidgets.remove(widget);
00317 }
00318 
00319 QString Service::name() const
00320 {
00321     return d->name;
00322 }
00323 
00324 void Service::setName(const QString &name)
00325 {
00326     d->name = name;
00327 
00328     // now reset the config, which may be based on our name
00329     delete d->config;
00330     d->config = 0;
00331 
00332     delete d->tempFile;
00333     d->tempFile = 0;
00334 
00335     delete d->dummyConfig;
00336     d->dummyConfig = 0;
00337 
00338     registerOperationsScheme();
00339 
00340     emit serviceReady(this);
00341 }
00342 
00343 void Service::setOperationEnabled(const QString &operation, bool enable)
00344 {
00345     if (!d->config || !d->config->hasGroup(operation)) {
00346         return;
00347     }
00348 
00349     if (enable) {
00350         d->disabledOperations.remove(operation);
00351     } else {
00352         d->disabledOperations.insert(operation);
00353     }
00354 
00355     {
00356         QHashIterator<QWidget *, QString> it(d->associatedWidgets);
00357         while (it.hasNext()) {
00358             it.next();
00359             if (it.value() == operation) {
00360                 it.key()->setEnabled(enable);
00361             }
00362         }
00363     }
00364 
00365     {
00366         QHashIterator<QGraphicsWidget *, QString> it(d->associatedGraphicsWidgets);
00367         while (it.hasNext()) {
00368             it.next();
00369             if (it.value() == operation) {
00370                 it.key()->setEnabled(enable);
00371             }
00372         }
00373     }
00374 }
00375 
00376 bool Service::isOperationEnabled(const QString &operation) const
00377 {
00378     return d->config && d->config->hasGroup(operation) && !d->disabledOperations.contains(operation);
00379 }
00380 
00381 void Service::setOperationsScheme(QIODevice *xml)
00382 {
00383     delete d->config;
00384     delete d->tempFile;
00385 
00386     delete d->dummyConfig;
00387     d->dummyConfig = 0;
00388 
00389     //FIXME: make KSharedConfig and KConfigSkeleton not braindamaged in 4.2 and then get rid of the
00390     //       temp file object here
00391     d->tempFile = new KTemporaryFile;
00392     d->tempFile->open();
00393 
00394     KSharedConfigPtr c = KSharedConfig::openConfig(d->tempFile->fileName(), KConfig::NoGlobals);
00395     d->config = new ConfigLoader(c, xml, this);
00396     d->config->d->setWriteDefaults(true);
00397 
00398     emit operationsChanged();
00399 
00400     {
00401         QHashIterator<QWidget *, QString> it(d->associatedWidgets);
00402         while (it.hasNext()) {
00403             it.next();
00404             it.key()->setEnabled(d->config->hasGroup(it.value()));
00405         }
00406     }
00407 
00408     {
00409         QHashIterator<QGraphicsWidget *, QString> it(d->associatedGraphicsWidgets);
00410         while (it.hasNext()) {
00411             it.next();
00412             it.key()->setEnabled(d->config->hasGroup(it.value()));
00413         }
00414     }
00415 }
00416 
00417 void Service::registerOperationsScheme()
00418 {
00419     if (d->config) {
00420         // we've already done our job. let's go home.
00421         return;
00422     }
00423 
00424     if (d->name.isEmpty()) {
00425         kDebug() << "No name found";
00426         return;
00427     }
00428 
00429     QString path = KStandardDirs::locate("data", "plasma/services/" + d->name + ".operations");
00430 
00431     if (path.isEmpty()) {
00432         kDebug() << "Cannot find operations description:" << d->name << ".operations";
00433         return;
00434     }
00435 
00436     QFile file(path);
00437     setOperationsScheme(&file);
00438 }
00439 
00440 } // namespace Plasma
00441 
00442 #include "service.moc"
00443 

Plasma

Skip menu "Plasma"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  •     Sodep
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.9-20090814
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal