• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.10.3 API Reference
  • KDE Home
  • Contact Us
 

KNewStuff

  • knewstuff
  • knewstuff3
  • core
knewstuff3/core/engine.cpp
Go to the documentation of this file.
1 /*
2  knewstuff3/engine.cpp
3  Copyright (c) 2007 Josef Spillner <spillner@kde.org>
4  Copyright (C) 2007-2010 Frederik Gladhorn <gladhorn@kde.org>
5  Copyright (c) 2009 Jeremy Whiting <jpwhiting@kde.org>
6  Copyright (c) 2010 Matthias Fuchs <mat69@gmx.net>
7 
8  This library is free software; you can redistribute it and/or
9  modify it under the terms of the GNU Lesser General Public
10  License as published by the Free Software Foundation; either
11  version 2.1 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  Lesser General Public License for more details.
17 
18  You should have received a copy of the GNU Lesser General Public
19  License along with this library. If not, see <http://www.gnu.org/licenses/>.
20 */
21 
22 #include "engine.h"
23 
24 #include "entry.h"
25 #include "core/installation.h"
26 #include "core/xmlloader.h"
27 #include "ui/imageloader.h"
28 
29 #include <kaboutdata.h>
30 #include <kconfig.h>
31 #include <kconfiggroup.h>
32 #include <kcomponentdata.h>
33 #include <kdebug.h>
34 #include <kstandarddirs.h>
35 #include <kcodecs.h>
36 #include <kprocess.h>
37 #include <kshell.h>
38 
39 #include <kio/job.h>
40 #include <kmimetype.h>
41 #include <krandom.h>
42 #include <ktoolinvocation.h>
43 
44 #include <QtCore/QTimer>
45 #include <QtCore/QDir>
46 #include <QtXml/qdom.h>
47 #include <QtCore/Q_PID>
48 
49 #if defined(Q_OS_WIN)
50 #include <windows.h>
51 #define _WIN32_IE 0x0500
52 #include <shlobj.h>
53 #endif
54 
55 // libattica
56 #include <attica/providermanager.h>
57 
58 // own
59 #include "attica/atticaprovider.h"
60 #include "core/cache.h"
61 #include "staticxml/staticxmlprovider.h"
62 
63 using namespace KNS3;
64 
65 Engine::Engine(QObject* parent)
66  : QObject(parent)
67  , m_initialized(false)
68  , m_installation(new Installation)
69  , m_cache(0)
70  , m_searchTimer(new QTimer)
71  , m_currentPage(-1)
72  , m_pageSize(20)
73  , m_numDataJobs(0)
74  , m_numPictureJobs(0)
75  , m_numInstallJobs(0)
76  , m_atticaProviderManager(0)
77 {
78  m_searchTimer->setSingleShot(true);
79  m_searchTimer->setInterval(1000);
80  connect(m_searchTimer, SIGNAL(timeout()), SLOT(slotSearchTimerExpired()));
81  connect(m_installation, SIGNAL(signalInstallationFinished()), this, SLOT(slotInstallationFinished()));
82  connect(m_installation, SIGNAL(signalInstallationFailed(QString)), this, SLOT(slotInstallationFailed(QString)));
83 
84 }
85 
86 Engine::~Engine()
87 {
88  if (m_cache) {
89  m_cache->writeRegistry();
90  }
91  delete m_atticaProviderManager;
92  delete m_searchTimer;
93  delete m_installation;
94 }
95 
96 bool Engine::init(const QString &configfile)
97 {
98  kDebug() << "Initializing KNS3::Engine from '" << configfile << "'";
99 
100  emit signalBusy(i18n("Initializing"));
101 
102  KConfig conf(configfile);
103  if (conf.accessMode() == KConfig::NoAccess) {
104  emit signalError(i18n("Configuration file not found: \"%1\"", configfile));
105  kError() << "No knsrc file named '" << configfile << "' was found." << endl;
106  return false;
107  }
108  // FIXME: accessMode() doesn't return NoAccess for non-existing files
109  // - bug in kdecore?
110  // - this needs to be looked at again until KConfig backend changes for KDE 4
111  // the check below is a workaround
112  if (KStandardDirs::locate("config", configfile).isEmpty()) {
113  emit signalError(i18n("Configuration file not found: \"%1\"", configfile));
114  kError() << "No knsrc file named '" << configfile << "' was found." << endl;
115  return false;
116  }
117 
118  KConfigGroup group;
119  if (conf.hasGroup("KNewStuff3")) {
120  kDebug() << "Loading KNewStuff3 config: " << configfile;
121  group = conf.group("KNewStuff3");
122  } else if (conf.hasGroup("KNewStuff2")) {
123  kDebug() << "Loading KNewStuff2 config: " << configfile;
124  group = conf.group("KNewStuff2");
125  } else {
126  emit signalError(i18n("Configuration file is invalid: \"%1\"", configfile));
127  kError() << "A knsrc file was found but it doesn't contain a KNewStuff3 section." << endl;
128  return false;
129  }
130 
131  m_categories = group.readEntry("Categories", QStringList());
132 
133  kDebug() << "Categories: " << m_categories;
134  m_providerFileUrl = group.readEntry("ProvidersUrl", QString());
135  m_applicationName = QFileInfo(KStandardDirs::locate("config", configfile)).baseName() + ':';
136 
137  // let installation read install specific config
138  if (!m_installation->readConfig(group)) {
139  return false;
140  }
141 
142  connect(m_installation, SIGNAL(signalEntryChanged(KNS3::EntryInternal)), SLOT(slotEntryChanged(KNS3::EntryInternal)));
143 
144  m_cache = Cache::getCache(m_applicationName.split(':')[0]);
145  connect(this, SIGNAL(signalEntryChanged(KNS3::EntryInternal)), m_cache.data(), SLOT(registerChangedEntry(KNS3::EntryInternal)));
146  m_cache->readRegistry();
147 
148  m_initialized = true;
149 
150  // load the providers
151  loadProviders();
152 
153  return true;
154 }
155 
156 QStringList Engine::categories() const
157 {
158  return m_categories;
159 }
160 
161 QStringList Engine::categoriesFilter() const
162 {
163  return m_currentRequest.categories;
164 }
165 
166 void Engine::loadProviders()
167 {
168  if (m_providerFileUrl.isEmpty()) {
169  // it would be nicer to move the attica stuff into its own class
170  kDebug(550) << "Using OCS default providers";
171  Attica::ProviderManager* m_atticaProviderManager = new Attica::ProviderManager;
172  connect(m_atticaProviderManager, SIGNAL(providerAdded(Attica::Provider)), this, SLOT(atticaProviderLoaded(Attica::Provider)));
173  m_atticaProviderManager->loadDefaultProviders();
174  } else {
175  kDebug(550) << "loading providers from " << m_providerFileUrl;
176  emit signalBusy(i18n("Loading provider information"));
177 
178  XmlLoader * loader = new XmlLoader(this);
179  connect(loader, SIGNAL(signalLoaded(QDomDocument)), SLOT(slotProviderFileLoaded(QDomDocument)));
180  connect(loader, SIGNAL(signalFailed()), SLOT(slotProvidersFailed()));
181 
182  loader->load(KUrl(m_providerFileUrl));
183  }
184 }
185 
186 void Engine::slotProviderFileLoaded(const QDomDocument& doc)
187 {
188  kDebug() << "slotProvidersLoaded";
189 
190  bool isAtticaProviderFile = false;
191 
192  // get each provider element, and create a provider object from it
193  QDomElement providers = doc.documentElement();
194 
195  if (providers.tagName() == "providers") {
196  isAtticaProviderFile = true;
197  } else if (providers.tagName() != "ghnsproviders" && providers.tagName() != "knewstuffproviders") {
198  kWarning(550) << "No document in providers.xml.";
199  emit signalError(i18n("Could not load get hot new stuff providers from file: %1", m_providerFileUrl));
200  return;
201  }
202 
203  QDomElement n = providers.firstChildElement("provider");
204  while (!n.isNull()) {
205  kDebug() << "Provider attributes: " << n.attribute("type");
206 
207  QSharedPointer<KNS3::Provider> provider;
208  if (isAtticaProviderFile || n.attribute("type").toLower() == "rest") {
209  provider = QSharedPointer<KNS3::Provider> (new AtticaProvider(m_categories));
210  } else {
211  provider = QSharedPointer<KNS3::Provider> (new StaticXmlProvider);
212  }
213 
214  if (provider->setProviderXML(n)) {
215  addProvider(provider);
216  } else {
217  emit signalError(i18n("Error initializing provider."));
218  }
219  n = n.nextSiblingElement();
220  }
221  emit signalBusy(i18n("Loading data"));
222 }
223 
224 void Engine::atticaProviderLoaded(const Attica::Provider& atticaProvider)
225 {
226  if (!atticaProvider.hasContentService()) {
227  kDebug() << "Found provider: " << atticaProvider.baseUrl() << " but it does not support content";
228  return;
229  }
230  QSharedPointer<KNS3::Provider> provider =
231  QSharedPointer<KNS3::Provider> (new AtticaProvider(atticaProvider, m_categories));
232  addProvider(provider);
233 }
234 
235 void Engine::addProvider(QSharedPointer<KNS3::Provider> provider)
236 {
237  m_providers.insert(provider->id(), provider);
238  connect(provider.data(), SIGNAL(providerInitialized(KNS3::Provider*)), SLOT(providerInitialized(KNS3::Provider*)));
239  connect(provider.data(), SIGNAL(loadingFinished(KNS3::Provider::SearchRequest,KNS3::EntryInternal::List)),
240  SLOT(slotEntriesLoaded(KNS3::Provider::SearchRequest,KNS3::EntryInternal::List)));
241  connect(provider.data(), SIGNAL(entryDetailsLoaded(KNS3::EntryInternal)), SLOT(slotEntryDetailsLoaded(KNS3::EntryInternal)));
242  connect(provider.data(), SIGNAL(payloadLinkLoaded(KNS3::EntryInternal)), SLOT(downloadLinkLoaded(KNS3::EntryInternal)));
243  connect(provider.data(), SIGNAL(signalError(QString)), this, SIGNAL(signalError(QString)));
244  connect(provider.data(), SIGNAL(signalInformation(QString)), this, SIGNAL(signalIdle(QString)));
245 }
246 
247 void Engine::providerJobStarted ( KJob* job )
248 {
249  emit jobStarted(job, i18n("Loading data from provider"));
250 }
251 
252 void Engine::slotProvidersFailed()
253 {
254  emit signalError(i18n("Loading of providers from file: %1 failed", m_providerFileUrl));
255 }
256 
257 void Engine::providerInitialized(Provider* p)
258 {
259  kDebug() << "providerInitialized" << p->name();
260  p->setCachedEntries(m_cache->registryForProvider(p->id()));
261  updateStatus();
262 
263  foreach (const QSharedPointer<KNS3::Provider> &p, m_providers) {
264  if (!p->isInitialized()) {
265  return;
266  }
267  }
268  emit signalProvidersLoaded();
269 }
270 
271 void Engine::slotEntriesLoaded(const KNS3::Provider::SearchRequest& request, KNS3::EntryInternal::List entries)
272 {
273  m_currentPage = qMax<int>(request.page, m_currentPage);
274  kDebug() << "loaded page " << request.page << "current page" << m_currentPage;
275 
276  if (request.sortMode == Provider::Updates) {
277  emit signalUpdateableEntriesLoaded(entries);
278  } else {
279  m_cache->insertRequest(request, entries);
280  emit signalEntriesLoaded(entries);
281  }
282 
283  --m_numDataJobs;
284  updateStatus();
285 }
286 
287 void Engine::reloadEntries()
288 {
289  emit signalResetView();
290  m_currentPage = -1;
291  m_currentRequest.page = 0;
292  m_numDataJobs = 0;
293 
294  foreach (const QSharedPointer<KNS3::Provider> &p, m_providers) {
295  if (p->isInitialized()) {
296  if (m_currentRequest.sortMode == Provider::Installed) {
297  // when asking for installed entries, never use the cache
298  p->loadEntries(m_currentRequest);
299  } else {
300  // take entries from cache until there are no more
301  EntryInternal::List cache = m_cache->requestFromCache(m_currentRequest);
302  while (!cache.isEmpty()) {
303  kDebug() << "From cache";
304  emit signalEntriesLoaded(cache);
305 
306  m_currentPage = m_currentRequest.page;
307  ++m_currentRequest.page;
308  cache = m_cache->requestFromCache(m_currentRequest);
309  }
310  // if the cache was empty, request data from provider
311  if (m_currentPage == -1) {
312  kDebug() << "From provider";
313  p->loadEntries(m_currentRequest);
314 
315  ++m_numDataJobs;
316  updateStatus();
317  }
318  }
319  }
320  }
321 }
322 
323 void Engine::setCategoriesFilter(const QStringList& categories)
324 {
325  m_currentRequest.categories = categories;
326  reloadEntries();
327 }
328 
329 void Engine::setSortMode(Provider::SortMode mode)
330 {
331  if (m_currentRequest.sortMode != mode) {
332  m_currentRequest.page = -1;
333  }
334  m_currentRequest.sortMode = mode;
335  reloadEntries();
336 }
337 
338 void Engine::setSearchTerm(const QString& searchString)
339 {
340  m_searchTimer->stop();
341  m_currentRequest.searchTerm = searchString;
342  EntryInternal::List cache = m_cache->requestFromCache(m_currentRequest);
343  if (!cache.isEmpty()) {
344  reloadEntries();
345  } else {
346  m_searchTimer->start();
347  }
348 }
349 
350 void Engine::slotSearchTimerExpired()
351 {
352  reloadEntries();
353 }
354 
355 void Engine::requestMoreData()
356 {
357  kDebug() << "Get more data! current page: " << m_currentPage << " requested: " << m_currentRequest.page;
358 
359  if (m_currentPage < m_currentRequest.page) {
360  return;
361  }
362 
363  m_currentRequest.page++;
364  doRequest();
365 }
366 
367 void Engine::requestData(int page, int pageSize)
368 {
369  m_currentRequest.page = page;
370  m_currentRequest.pageSize = pageSize;
371  doRequest();
372 }
373 
374 void Engine::doRequest()
375 {
376  foreach (const QSharedPointer<KNS3::Provider> &p, m_providers) {
377  if (p->isInitialized()) {
378  p->loadEntries(m_currentRequest);
379  ++m_numDataJobs;
380  updateStatus();
381  }
382  }
383 }
384 
385 void Engine::install(KNS3::EntryInternal entry, int linkId)
386 {
387  if (entry.status() == Entry::Updateable) {
388  entry.setStatus(Entry::Updating);
389  } else {
390  entry.setStatus(Entry::Installing);
391  }
392  emit signalEntryChanged(entry);
393 
394  kDebug() << "Install " << entry.name()
395  << " from: " << entry.providerId();
396  QSharedPointer<Provider> p = m_providers.value(entry.providerId());
397  if (p) {
398  p->loadPayloadLink(entry, linkId);
399 
400  ++m_numInstallJobs;
401  updateStatus();
402  }
403 }
404 
405 void Engine::slotInstallationFinished()
406 {
407  --m_numInstallJobs;
408  updateStatus();
409 }
410 
411 void Engine::slotInstallationFailed(const QString& message)
412 {
413  --m_numInstallJobs;
414  emit signalError(message);
415 }
416 
417 void Engine::slotEntryDetailsLoaded(const KNS3::EntryInternal& entry)
418 {
419  emit signalEntryDetailsLoaded(entry);
420 }
421 
422 void Engine::downloadLinkLoaded(const KNS3::EntryInternal& entry)
423 {
424  m_installation->install(entry);
425 }
426 
427 void Engine::uninstall(KNS3::EntryInternal entry)
428 {
429  // FIXME: change the status?
430  entry.setStatus(Entry::Installing);
431  emit signalEntryChanged(entry);
432  m_installation->uninstall(entry);
433 }
434 
435 void Engine::loadDetails(const KNS3::EntryInternal &entry)
436 {
437  QSharedPointer<Provider> p = m_providers.value(entry.providerId());
438  p->loadEntryDetails(entry);
439 }
440 
441 void Engine::loadPreview(const KNS3::EntryInternal& entry, EntryInternal::PreviewType type)
442 {
443  kDebug() << "START preview: " << entry.name() << type;
444  ImageLoader* l = new ImageLoader(entry, type, this);
445  connect(l, SIGNAL(signalPreviewLoaded(KNS3::EntryInternal,KNS3::EntryInternal::PreviewType)), this, SLOT(slotPreviewLoaded(KNS3::EntryInternal,KNS3::EntryInternal::PreviewType)));
446  l->start();
447  ++m_numPictureJobs;
448  updateStatus();
449 }
450 
451 void Engine::slotPreviewLoaded(const KNS3::EntryInternal& entry, EntryInternal::PreviewType type)
452 {
453  kDebug() << "FINISH preview: " << entry.name() << type;
454  emit signalEntryPreviewLoaded(entry, type);
455  --m_numPictureJobs;
456  updateStatus();
457 }
458 
459 void Engine::contactAuthor(const EntryInternal &entry)
460 {
461  if (!entry.author().email().isEmpty()) {
462  // invoke mail with the address of the author
463  KToolInvocation::invokeMailer(entry.author().email(), i18n("Re: %1", entry.name()));
464  } else if (!entry.author().homepage().isEmpty()) {
465  KToolInvocation::invokeBrowser(entry.author().homepage());
466  }
467 }
468 
469 void Engine::slotEntryChanged(const KNS3::EntryInternal& entry)
470 {
471  emit signalEntryChanged(entry);
472 }
473 
474 bool Engine::userCanVote(const EntryInternal& entry)
475 {
476  QSharedPointer<Provider> p = m_providers.value(entry.providerId());
477  return p->userCanVote();
478 }
479 
480 void Engine::vote(const EntryInternal& entry, uint rating)
481 {
482  QSharedPointer<Provider> p = m_providers.value(entry.providerId());
483  p->vote(entry, rating);
484 }
485 
486 bool Engine::userCanBecomeFan(const EntryInternal& entry)
487 {
488  QSharedPointer<Provider> p = m_providers.value(entry.providerId());
489  return p->userCanBecomeFan();
490 }
491 
492 void Engine::becomeFan(const EntryInternal& entry)
493 {
494  QSharedPointer<Provider> p = m_providers.value(entry.providerId());
495  p->becomeFan(entry);
496 }
497 
498 void Engine::updateStatus()
499 {
500  if (m_numDataJobs > 0) {
501  emit signalBusy(i18n("Loading data"));
502  } else if (m_numPictureJobs > 0) {
503  emit signalBusy(i18np("Loading one preview", "Loading %1 previews", m_numPictureJobs));
504  } else if (m_numInstallJobs > 0) {
505  emit signalBusy(i18n("Installing"));
506  } else {
507  emit signalIdle(QString());
508  }
509 }
510 
511 void Engine::checkForUpdates()
512 {
513  foreach(QSharedPointer<Provider> p, m_providers) {
514  Provider::SearchRequest request(KNS3::Provider::Updates);
515  p->loadEntries(request);
516  }
517 }
518 
519 #include "engine.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2013 The KDE developers.
Generated on Sat May 18 2013 11:42:10 by doxygen 1.8.3.1 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KNewStuff

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

kdelibs-4.10.3 API Reference

Skip menu "kdelibs-4.10.3 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • 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
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal