1 | /* |
2 | * Copyright 2006-2007 Aaron Seigo <aseigo@kde.org> |
3 | * |
4 | * This program is free software; you can redistribute it and/or modify |
5 | * it under the terms of the GNU Library General Public License as |
6 | * published by the Free Software Foundation; either version 2, or |
7 | * (at your option) any later version. |
8 | * |
9 | * This program is distributed in the hope that it will be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | * GNU General Public License for more details |
13 | * |
14 | * You should have received a copy of the GNU Library General Public |
15 | * License along with this program; if not, write to the |
16 | * Free Software Foundation, Inc., |
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
18 | */ |
19 | |
20 | #include "dataengine.h" |
21 | #include "private/dataengine_p.h" |
22 | #include "private/datacontainer_p.h" |
23 | |
24 | #include <QQueue> |
25 | #include <QTimer> |
26 | #include <QTime> |
27 | #include <QTimerEvent> |
28 | #include <QVariant> |
29 | |
30 | #include <kdebug.h> |
31 | #include <kplugininfo.h> |
32 | #include <kservice.h> |
33 | #include <kstandarddirs.h> |
34 | |
35 | #include "authorizationmanager.h" |
36 | #include "datacontainer.h" |
37 | #include "package.h" |
38 | #include "service.h" |
39 | #include "scripting/dataenginescript.h" |
40 | |
41 | #include "private/authorizationmanager_p.h" |
42 | #include "private/dataengineservice_p.h" |
43 | #include "private/remotedataengine_p.h" |
44 | #include "private/service_p.h" |
45 | #include "private/storage_p.h" |
46 | |
47 | namespace Plasma |
48 | { |
49 | |
50 | DataEngine::DataEngine(QObject *parent, KService::Ptr service) |
51 | : QObject(parent), |
52 | d(new DataEnginePrivate(this, KPluginInfo(service))) |
53 | { |
54 | } |
55 | |
56 | DataEngine::DataEngine(QObject *parent, const QVariantList &args) |
57 | : QObject(parent), |
58 | d(new DataEnginePrivate(this, KPluginInfo(KService::serviceByStorageId(args.count() > 0 ? args[0].toString() : QString())))) |
59 | { |
60 | } |
61 | |
62 | DataEngine::~DataEngine() |
63 | { |
64 | //kDebug() << objectName() << ": bye bye birdy! "; |
65 | delete d; |
66 | } |
67 | |
68 | QStringList DataEngine::sources() const |
69 | { |
70 | if (d->script) { |
71 | return d->script->sources(); |
72 | } else { |
73 | return d->sources.keys(); |
74 | } |
75 | } |
76 | |
77 | Service *DataEngine::serviceForSource(const QString &source) |
78 | { |
79 | if (d->script) { |
80 | Service * s = d->script->serviceForSource(source); |
81 | if (s) { |
82 | return s; |
83 | } |
84 | } |
85 | |
86 | return new NullService(source, this); |
87 | } |
88 | |
89 | void DataEngine::connectSource(const QString &source, QObject *visualization, |
90 | uint pollingInterval, |
91 | Plasma::IntervalAlignment intervalAlignment) const |
92 | { |
93 | //kDebug() << "connectSource" << source; |
94 | bool newSource; |
95 | DataContainer *s = d->requestSource(source, &newSource); |
96 | |
97 | if (s) { |
98 | // we suppress the immediate invocation of dataUpdated here if the |
99 | // source was prexisting and they don't request delayed updates |
100 | // (we want to do an immediate update in that case so they don't |
101 | // have to wait for the first time out) |
102 | if (newSource && !s->data().isEmpty()) { |
103 | newSource = false; |
104 | } |
105 | d->connectSource(s, visualization, pollingInterval, intervalAlignment, |
106 | !newSource || pollingInterval > 0); |
107 | //kDebug() << " ==> source connected"; |
108 | } |
109 | } |
110 | |
111 | void DataEngine::connectAllSources(QObject *visualization, uint pollingInterval, |
112 | Plasma::IntervalAlignment intervalAlignment) const |
113 | { |
114 | foreach (DataContainer *s, d->sources) { |
115 | d->connectSource(s, visualization, pollingInterval, intervalAlignment); |
116 | } |
117 | } |
118 | |
119 | void DataEngine::disconnectSource(const QString &source, QObject *visualization) const |
120 | { |
121 | DataContainer *s = d->source(source, false); |
122 | |
123 | if (s) { |
124 | s->disconnectVisualization(visualization); |
125 | } |
126 | } |
127 | |
128 | DataContainer *DataEngine::containerForSource(const QString &source) |
129 | { |
130 | return d->source(source, false); |
131 | } |
132 | |
133 | DataEngine::Data DataEngine::query(const QString &source) const |
134 | { |
135 | bool newSource; |
136 | DataContainer *s = d->requestSource(source, &newSource); |
137 | |
138 | if (!s) { |
139 | return DataEngine::Data(); |
140 | } else if (!newSource && d->minPollingInterval >= 0 && |
141 | s->timeSinceLastUpdate() >= uint(d->minPollingInterval)) { |
142 | DataEngine *unconstThis = const_cast<DataEngine*>(this); |
143 | if (unconstThis->updateSourceEvent(source)) { |
144 | unconstThis->scheduleSourcesUpdated(); |
145 | } |
146 | } |
147 | |
148 | DataEngine::Data data = s->data(); |
149 | s->checkUsage(); |
150 | return data; |
151 | } |
152 | |
153 | void DataEngine::init() |
154 | { |
155 | if (d->script) { |
156 | d->setupScriptSupport(); |
157 | d->script->init(); |
158 | } else { |
159 | // kDebug() << "called"; |
160 | // default implementation does nothing. this is for engines that have to |
161 | // start things in motion external to themselves before they can work |
162 | } |
163 | } |
164 | |
165 | bool DataEngine::sourceRequestEvent(const QString &name) |
166 | { |
167 | if (d->script) { |
168 | return d->script->sourceRequestEvent(name); |
169 | } else { |
170 | return false; |
171 | } |
172 | } |
173 | |
174 | bool DataEngine::updateSourceEvent(const QString &source) |
175 | { |
176 | if (d->script) { |
177 | return d->script->updateSourceEvent(source); |
178 | } else { |
179 | //kDebug() << source; |
180 | return false; //TODO: should this be true to trigger, even needless, updates on every tick? |
181 | } |
182 | } |
183 | |
184 | void DataEngine::setData(const QString &source, const QVariant &value) |
185 | { |
186 | setData(source, source, value); |
187 | } |
188 | |
189 | void DataEngine::setData(const QString &source, const QString &key, const QVariant &value) |
190 | { |
191 | DataContainer *s = d->source(source, false); |
192 | bool isNew = !s; |
193 | |
194 | if (isNew) { |
195 | s = d->source(source); |
196 | } |
197 | |
198 | s->setData(key, value); |
199 | |
200 | if (isNew && source != d->waitingSourceRequest) { |
201 | emit sourceAdded(source); |
202 | } |
203 | |
204 | scheduleSourcesUpdated(); |
205 | } |
206 | |
207 | void DataEngine::setData(const QString &source, const Data &data) |
208 | { |
209 | DataContainer *s = d->source(source, false); |
210 | bool isNew = !s; |
211 | |
212 | if (isNew) { |
213 | s = d->source(source); |
214 | } |
215 | |
216 | Data::const_iterator it = data.constBegin(); |
217 | while (it != data.constEnd()) { |
218 | s->setData(it.key(), it.value()); |
219 | ++it; |
220 | } |
221 | |
222 | if (isNew && source != d->waitingSourceRequest) { |
223 | emit sourceAdded(source); |
224 | } |
225 | |
226 | scheduleSourcesUpdated(); |
227 | } |
228 | |
229 | void DataEngine::removeAllData(const QString &source) |
230 | { |
231 | DataContainer *s = d->source(source, false); |
232 | if (s) { |
233 | s->removeAllData(); |
234 | scheduleSourcesUpdated(); |
235 | } |
236 | } |
237 | |
238 | void DataEngine::removeData(const QString &source, const QString &key) |
239 | { |
240 | DataContainer *s = d->source(source, false); |
241 | if (s) { |
242 | s->setData(key, QVariant()); |
243 | scheduleSourcesUpdated(); |
244 | } |
245 | } |
246 | |
247 | void DataEngine::addSource(DataContainer *source) |
248 | { |
249 | if (d->sources.contains(source->objectName())) { |
250 | kDebug() << "source named \"" << source->objectName() << "\" already exists." ; |
251 | return; |
252 | } |
253 | |
254 | QObject::connect(source, SIGNAL(updateRequested(DataContainer*)), |
255 | this, SLOT(internalUpdateSource(DataContainer*))); |
256 | QObject::connect(source, SIGNAL(destroyed(QObject*)), this, SLOT(sourceDestroyed(QObject*))); |
257 | d->sources.insert(source->objectName(), source); |
258 | emit sourceAdded(source->objectName()); |
259 | scheduleSourcesUpdated(); |
260 | } |
261 | |
262 | void DataEngine::setMaxSourceCount(uint limit) |
263 | { |
264 | if (d->limit == limit) { |
265 | return; |
266 | } |
267 | |
268 | d->limit = limit; |
269 | |
270 | if (d->limit > 0) { |
271 | d->trimQueue(); |
272 | } else { |
273 | d->sourceQueue.clear(); |
274 | } |
275 | } |
276 | |
277 | uint DataEngine::maxSourceCount() const |
278 | { |
279 | return d->limit; |
280 | } |
281 | |
282 | void DataEngine::setMinimumPollingInterval(int minimumMs) |
283 | { |
284 | d->minPollingInterval = minimumMs; |
285 | } |
286 | |
287 | int DataEngine::minimumPollingInterval() const |
288 | { |
289 | return d->minPollingInterval; |
290 | } |
291 | |
292 | void DataEngine::setPollingInterval(uint frequency) |
293 | { |
294 | killTimer(d->updateTimerId); |
295 | d->updateTimerId = 0; |
296 | |
297 | if (frequency > 0) { |
298 | d->updateTimerId = startTimer(frequency); |
299 | } |
300 | } |
301 | |
302 | void DataEngine::removeSource(const QString &source) |
303 | { |
304 | SourceDict::iterator it = d->sources.find(source); |
305 | if (it != d->sources.end()) { |
306 | DataContainer *s = it.value(); |
307 | |
308 | // remove it from the limit queue if we're keeping one |
309 | if (d->limit > 0) { |
310 | QQueue<DataContainer*>::iterator it = d->sourceQueue.begin(); |
311 | while (it != d->sourceQueue.end()) { |
312 | if (*it == s) { |
313 | d->sourceQueue.erase(it); |
314 | break; |
315 | } |
316 | ++it; |
317 | } |
318 | } |
319 | |
320 | s->d->store(); |
321 | s->disconnect(this); |
322 | s->deleteLater(); |
323 | d->sources.erase(it); |
324 | emit sourceRemoved(source); |
325 | } |
326 | } |
327 | |
328 | void DataEngine::removeAllSources() |
329 | { |
330 | QMutableHashIterator<QString, Plasma::DataContainer*> it(d->sources); |
331 | while (it.hasNext()) { |
332 | it.next(); |
333 | Plasma::DataContainer *s = it.value(); |
334 | const QString source = it.key(); |
335 | it.remove(); |
336 | s->disconnect(this); |
337 | s->deleteLater(); |
338 | emit sourceRemoved(source); |
339 | } |
340 | } |
341 | |
342 | bool DataEngine::isValid() const |
343 | { |
344 | return d->valid; |
345 | } |
346 | |
347 | bool DataEngine::isEmpty() const |
348 | { |
349 | return d->sources.isEmpty(); |
350 | } |
351 | |
352 | void DataEngine::setValid(bool valid) |
353 | { |
354 | d->valid = valid; |
355 | } |
356 | |
357 | DataEngine::SourceDict DataEngine::containerDict() const |
358 | { |
359 | return d->sources; |
360 | } |
361 | |
362 | void DataEngine::timerEvent(QTimerEvent *event) |
363 | { |
364 | //kDebug(); |
365 | if (event->timerId() == d->updateTimerId) { |
366 | // if the freq update is less than 0, don't bother |
367 | if (d->minPollingInterval < 0) { |
368 | //kDebug() << "uh oh.. no polling allowed!"; |
369 | return; |
370 | } |
371 | |
372 | // minPollingInterval |
373 | if (d->updateTimer.elapsed() < d->minPollingInterval) { |
374 | //kDebug() << "hey now.. slow down!"; |
375 | return; |
376 | } |
377 | |
378 | d->updateTimer.start(); |
379 | updateAllSources(); |
380 | } else if (event->timerId() == d->checkSourcesTimerId) { |
381 | killTimer(d->checkSourcesTimerId); |
382 | d->checkSourcesTimerId = 0; |
383 | |
384 | QHashIterator<QString, Plasma::DataContainer*> it(d->sources); |
385 | while (it.hasNext()) { |
386 | it.next(); |
387 | it.value()->checkForUpdate(); |
388 | } |
389 | } else { |
390 | QObject::timerEvent(event); |
391 | } |
392 | } |
393 | |
394 | void DataEngine::updateAllSources() |
395 | { |
396 | QHashIterator<QString, Plasma::DataContainer*> it(d->sources); |
397 | while (it.hasNext()) { |
398 | it.next(); |
399 | //kDebug() << "updating" << it.key(); |
400 | updateSourceEvent(it.key()); |
401 | } |
402 | |
403 | scheduleSourcesUpdated(); |
404 | } |
405 | |
406 | void DataEngine::forceImmediateUpdateOfAllVisualizations() |
407 | { |
408 | foreach (DataContainer *source, d->sources) { |
409 | source->forceImmediateUpdate(); |
410 | } |
411 | } |
412 | |
413 | void DataEngine::setIcon(const QString &icon) |
414 | { |
415 | d->icon = icon; |
416 | } |
417 | |
418 | QString DataEngine::icon() const |
419 | { |
420 | return d->icon; |
421 | } |
422 | |
423 | QString DataEngine::pluginName() const |
424 | { |
425 | if (!d->dataEngineDescription.isValid()) { |
426 | return QString(); |
427 | } |
428 | |
429 | return d->dataEngineDescription.pluginName(); |
430 | } |
431 | |
432 | void DataEngine::setDefaultService(const QString &serviceName) |
433 | { |
434 | d->serviceName = serviceName; |
435 | } |
436 | |
437 | Service* DataEngine::createDefaultService(QObject *parent) |
438 | { |
439 | QVariantList args; |
440 | args << QVariant::fromValue<DataEngine*>(this); |
441 | return Service::load(d->serviceName, args, parent); |
442 | } |
443 | |
444 | void DataEnginePrivate::publish(AnnouncementMethods methods, const QString &name) |
445 | { |
446 | if (!publishedService) { |
447 | publishedService = new DataEngineService(q); |
448 | } |
449 | |
450 | //QString resourceName = |
451 | //i18nc("%1 is the name of a dataengine, %2 the name of the machine that engine is published |
452 | //on", |
453 | //"%1 dataengine on %2", name(), AuthorizationManager::self()->d->myCredentials.name()); |
454 | kDebug() << "name: " << name; |
455 | publishedService->d->publish(methods, name); |
456 | } |
457 | |
458 | void DataEnginePrivate::unpublish(const QString &name) |
459 | { |
460 | Q_UNUSED(name) |
461 | |
462 | if (publishedService) { |
463 | publishedService->d->unpublish(); |
464 | } |
465 | } |
466 | |
467 | bool DataEnginePrivate::isPublished() const |
468 | { |
469 | if (publishedService) { |
470 | return publishedService->d->isPublished(); |
471 | } else { |
472 | return false; |
473 | } |
474 | } |
475 | |
476 | const Package *DataEngine::package() const |
477 | { |
478 | return d->package; |
479 | } |
480 | |
481 | void DataEngine::scheduleSourcesUpdated() |
482 | { |
483 | if (d->checkSourcesTimerId) { |
484 | return; |
485 | } |
486 | |
487 | d->checkSourcesTimerId = startTimer(0); |
488 | } |
489 | |
490 | QString DataEngine::name() const |
491 | { |
492 | return d->engineName; |
493 | } |
494 | |
495 | void DataEngine::setName(const QString &name) |
496 | { |
497 | d->engineName = name; |
498 | setObjectName(name); |
499 | } |
500 | |
501 | void DataEngine::setStorageEnabled(const QString &source, bool store) |
502 | { |
503 | DataContainer *s = d->source(source, false); |
504 | if (s) { |
505 | s->setStorageEnabled(store); |
506 | } |
507 | } |
508 | |
509 | // Private class implementations |
510 | DataEnginePrivate::DataEnginePrivate(DataEngine *e, const KPluginInfo &info) |
511 | : q(e), |
512 | dataEngineDescription(info), |
513 | refCount(-1), // first ref |
514 | checkSourcesTimerId(0), |
515 | updateTimerId(0), |
516 | minPollingInterval(-1), |
517 | limit(0), |
518 | valid(true), |
519 | script(0), |
520 | package(0), |
521 | publishedService(0) |
522 | { |
523 | updateTimer.start(); |
524 | |
525 | if (!info.isValid()) { |
526 | engineName = i18n("Unnamed" ); |
527 | return; |
528 | } |
529 | |
530 | engineName = info.name(); |
531 | if (engineName.isEmpty()) { |
532 | engineName = i18n("Unnamed" ); |
533 | } |
534 | e->setObjectName(engineName); |
535 | icon = info.icon(); |
536 | |
537 | if (dataEngineDescription.isValid()) { |
538 | QString api = dataEngineDescription.property("X-Plasma-API" ).toString(); |
539 | |
540 | if (!api.isEmpty()) { |
541 | const QString path = |
542 | KStandardDirs::locate("data" , |
543 | "plasma/dataengines/" + dataEngineDescription.pluginName() + '/'); |
544 | PackageStructure::Ptr structure = Plasma::packageStructure(api, Plasma::DataEngineComponent); |
545 | structure->setPath(path); |
546 | package = new Package(path, structure); |
547 | |
548 | script = Plasma::loadScriptEngine(api, q); |
549 | if (!script) { |
550 | kDebug() << "Could not create a" << api << "ScriptEngine for the" |
551 | << dataEngineDescription.name() << "DataEngine." ; |
552 | delete package; |
553 | package = 0; |
554 | } |
555 | } |
556 | } |
557 | } |
558 | |
559 | DataEnginePrivate::~DataEnginePrivate() |
560 | { |
561 | delete script; |
562 | script = 0; |
563 | delete package; |
564 | package = 0; |
565 | } |
566 | |
567 | void DataEnginePrivate::internalUpdateSource(DataContainer *source) |
568 | { |
569 | if (minPollingInterval > 0 && |
570 | source->timeSinceLastUpdate() < (uint)minPollingInterval) { |
571 | // skip updating this source; it's been too soon |
572 | //kDebug() << "internal update source is delaying" << source->timeSinceLastUpdate() << minPollingInterval; |
573 | //but fake an update so that the signalrelay that triggered this gets the data from the |
574 | //recent update. this way we don't have to worry about queuing - the relay will send a |
575 | //signal immediately and everyone else is undisturbed. |
576 | source->setNeedsUpdate(); |
577 | return; |
578 | } |
579 | |
580 | if (q->updateSourceEvent(source->objectName())) { |
581 | //kDebug() << "queuing an update"; |
582 | q->scheduleSourcesUpdated(); |
583 | }/* else { |
584 | kDebug() << "no update"; |
585 | }*/ |
586 | } |
587 | |
588 | void DataEnginePrivate::ref() |
589 | { |
590 | --refCount; |
591 | } |
592 | |
593 | void DataEnginePrivate::deref() |
594 | { |
595 | ++refCount; |
596 | } |
597 | |
598 | bool DataEnginePrivate::isUsed() const |
599 | { |
600 | return refCount != 0; |
601 | } |
602 | |
603 | DataContainer *DataEnginePrivate::source(const QString &sourceName, bool createWhenMissing) |
604 | { |
605 | DataEngine::SourceDict::const_iterator it = sources.constFind(sourceName); |
606 | if (it != sources.constEnd()) { |
607 | DataContainer *s = it.value(); |
608 | if (limit > 0) { |
609 | QQueue<DataContainer*>::iterator it = sourceQueue.begin(); |
610 | while (it != sourceQueue.end()) { |
611 | if (*it == s) { |
612 | sourceQueue.erase(it); |
613 | break; |
614 | } |
615 | ++it; |
616 | } |
617 | sourceQueue.enqueue(s); |
618 | } |
619 | return s; |
620 | } |
621 | |
622 | if (!createWhenMissing) { |
623 | return 0; |
624 | } |
625 | |
626 | //kDebug() << "DataEngine " << q->objectName() << ": could not find DataContainer " << sourceName << ", creating"; |
627 | DataContainer *s = new DataContainer(q); |
628 | s->setObjectName(sourceName); |
629 | sources.insert(sourceName, s); |
630 | QObject::connect(s, SIGNAL(destroyed(QObject*)), q, SLOT(sourceDestroyed(QObject*))); |
631 | QObject::connect(s, SIGNAL(updateRequested(DataContainer*)), |
632 | q, SLOT(internalUpdateSource(DataContainer*))); |
633 | |
634 | if (limit > 0) { |
635 | trimQueue(); |
636 | sourceQueue.enqueue(s); |
637 | } |
638 | return s; |
639 | } |
640 | |
641 | void DataEnginePrivate::connectSource(DataContainer *s, QObject *visualization, |
642 | uint pollingInterval, |
643 | Plasma::IntervalAlignment align, |
644 | bool immediateCall) |
645 | { |
646 | //kDebug() << "connect source called" << s->objectName() << "with interval" << pollingInterval; |
647 | |
648 | //FIXME: at the moment a remote dataengine can only poll, a push mechanism will be needed instead |
649 | if (pollingInterval == 0 && qobject_cast<RemoteDataEngine *>(q)) { |
650 | pollingInterval = 5000; |
651 | } |
652 | if (pollingInterval > 0) { |
653 | // never more frequently than allowed, never more than 20 times per second |
654 | uint min = qMax(50, minPollingInterval); // for qMax below |
655 | pollingInterval = qMax(min, pollingInterval); |
656 | |
657 | // align on the 50ms |
658 | pollingInterval = pollingInterval - (pollingInterval % 50); |
659 | } |
660 | |
661 | if (immediateCall) { |
662 | // we don't want to do an immediate call if we are simply |
663 | // reconnecting |
664 | //kDebug() << "immediate call requested, we have:" << s->visualizationIsConnected(visualization); |
665 | immediateCall = !s->data().isEmpty() && |
666 | !s->visualizationIsConnected(visualization); |
667 | } |
668 | |
669 | s->connectVisualization(visualization, pollingInterval, align); |
670 | |
671 | if (immediateCall) { |
672 | QMetaObject::invokeMethod(visualization, "dataUpdated" , |
673 | Q_ARG(QString, s->objectName()), |
674 | Q_ARG(Plasma::DataEngine::Data, s->data())); |
675 | s->d->dirty = false; |
676 | } |
677 | } |
678 | |
679 | void DataEnginePrivate::sourceDestroyed(QObject *object) |
680 | { |
681 | DataEngine::SourceDict::iterator it = sources.begin(); |
682 | while (it != sources.end()) { |
683 | if (it.value() == object) { |
684 | sources.erase(it); |
685 | emit q->sourceRemoved(object->objectName()); |
686 | break; |
687 | } |
688 | ++it; |
689 | } |
690 | } |
691 | |
692 | DataContainer *DataEnginePrivate::requestSource(const QString &sourceName, bool *newSource) |
693 | { |
694 | if (newSource) { |
695 | *newSource = false; |
696 | } |
697 | |
698 | //kDebug() << "requesting source " << sourceName; |
699 | DataContainer *s = source(sourceName, false); |
700 | |
701 | if (!s) { |
702 | // we didn't find a data source, so give the engine an opportunity to make one |
703 | /*kDebug() << "DataEngine " << q->objectName() |
704 | << ": could not find DataContainer " << sourceName |
705 | << " will create on request" << endl;*/ |
706 | waitingSourceRequest = sourceName; |
707 | if (q->sourceRequestEvent(sourceName)) { |
708 | s = source(sourceName, false); |
709 | if (s) { |
710 | // now we have a source; since it was created on demand, assume |
711 | // it should be removed when not used |
712 | if (newSource) { |
713 | *newSource = true; |
714 | } |
715 | QObject::connect(s, SIGNAL(becameUnused(QString)), q, SLOT(removeSource(QString))); |
716 | emit q->sourceAdded(sourceName); |
717 | } |
718 | } |
719 | waitingSourceRequest.clear(); |
720 | } |
721 | |
722 | return s; |
723 | } |
724 | |
725 | void DataEnginePrivate::trimQueue() |
726 | { |
727 | uint queueCount = sourceQueue.count(); |
728 | while (queueCount >= limit && !sourceQueue.isEmpty()) { |
729 | DataContainer *punted = sourceQueue.dequeue(); |
730 | q->removeSource(punted->objectName()); |
731 | queueCount = sourceQueue.count(); |
732 | } |
733 | } |
734 | |
735 | // put all setup routines for script here. at this point we can assume that |
736 | // package exists and that we have a script engine |
737 | void DataEnginePrivate::setupScriptSupport() |
738 | { |
739 | if (!package) { |
740 | return; |
741 | } |
742 | |
743 | /* |
744 | kDebug() << "sletting up script support, package is in" << package->path() |
745 | << "which is a" << package->structure()->type() << "package" |
746 | << ", main script is" << package->filePath("mainscript"); |
747 | */ |
748 | |
749 | QString translationsPath = package->filePath("translations" ); |
750 | if (!translationsPath.isEmpty()) { |
751 | //FIXME: we should _probably_ use a KComponentData to segregate the applets |
752 | // from each other; but I want to get the basics working first :) |
753 | KGlobal::dirs()->addResourceDir("locale" , translationsPath); |
754 | KGlobal::locale()->insertCatalog(package->metadata().pluginName()); |
755 | } |
756 | } |
757 | |
758 | } |
759 | |
760 | #include "dataengine.moc" |
761 | |