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

KNewStuff

atticaprovider.cpp

Go to the documentation of this file.
00001 /*
00002     Copyright (c) 2009-2010 Frederik Gladhorn <gladhorn@kde.org>
00003 
00004     This library is free software; you can redistribute it and/or
00005     modify it under the terms of the GNU Lesser General Public
00006     License as published by the Free Software Foundation; either
00007     version 2.1 of the License, or (at your option) any later version.
00008 
00009     This library 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 GNU
00012     Lesser General Public License for more details.
00013 
00014     You should have received a copy of the GNU Lesser General Public
00015     License along with this library.  If not, see <http://www.gnu.org/licenses/>.
00016 */
00017 
00018 #include "atticaprovider.h"
00019 
00020 #include <kdebug.h>
00021 #include <klocale.h>
00022 #include <kio/job.h>
00023 #include <kmessagebox.h>
00024 
00025 #include <attica/providermanager.h>
00026 #include <attica/provider.h>
00027 #include <attica/listjob.h>
00028 #include <attica/content.h>
00029 #include <attica/downloaditem.h>
00030 #include <attica/accountbalance.h>
00031 #include <attica/person.h>
00032 
00033 using namespace Attica;
00034 
00035 namespace KNS3
00036 {
00037 
00038 AtticaProvider::AtticaProvider(const QStringList& categories)
00039     : mEntryJob(0)
00040     , mInitialized(false)
00041 {
00042     // init categories map with invalid categories
00043     foreach (const QString& category, categories)
00044         mCategoryMap.insert(category, Attica::Category());
00045 
00046     connect(&m_providerManager, SIGNAL(providerAdded(const Attica::Provider&)), SLOT(providerLoaded(const Attica::Provider&)));
00047     connect(&m_providerManager, SIGNAL(authenticationCredentialsMissing(const Provider&)),
00048             SLOT(authenticationCredentialsMissing(const Provider&)));
00049 }
00050 
00051 AtticaProvider::AtticaProvider(const Attica::Provider& provider, const QStringList& categories)
00052     : mEntryJob(0)
00053     , mInitialized(false)
00054 {
00055     // init categories map with invalid categories
00056     foreach (const QString& category, categories) {
00057         mCategoryMap.insert(category, Attica::Category());
00058     }
00059     providerLoaded(provider);
00060 }
00061 
00062 QString AtticaProvider::id() const
00063 {
00064     return m_provider.baseUrl().toString();
00065 }
00066 
00067 void AtticaProvider::authenticationCredentialsMissing(const KNS3::Provider& )
00068 {
00069     kDebug() << "Authentication missing!";
00070     // FIXME Show autentication dialog
00071 }
00072 
00073 bool AtticaProvider::setProviderXML(const QDomElement & xmldata)
00074 {
00075     if (xmldata.tagName() != "provider")
00076         return false;
00077 
00078     // FIXME this is quite ugly, repackaging the xml into a string
00079     QDomDocument doc("temp");
00080     kDebug(550) << "setting provider xml" << doc.toString();
00081 
00082     doc.appendChild(xmldata.cloneNode(true));
00083     m_providerManager.addProviderFromXml(doc.toString());
00084 
00085     if (!m_providerManager.providers().isEmpty()) {
00086         kDebug() << "base url of attica provider:" << m_providerManager.providers().last().baseUrl().toString();
00087     } else {
00088         kError() << "Could not load provider.";
00089         return false;
00090     }
00091     return true;
00092 }
00093 
00094 void AtticaProvider::setCachedEntries(const KNS3::EntryInternal::List& cachedEntries)
00095 {
00096     mCachedEntries = cachedEntries;
00097 }
00098 
00099 void AtticaProvider::providerLoaded(const Attica::Provider& provider)
00100 {
00101     mName = provider.name();
00102     kDebug() << "Added provider: " << provider.name();
00103 
00104     m_provider = provider;
00105 
00106     Attica::ListJob<Attica::Category>* job = m_provider.requestCategories();
00107     connect(job, SIGNAL(finished(Attica::BaseJob*)), SLOT(listOfCategoriesLoaded(Attica::BaseJob*)));
00108     job->start();
00109 }
00110 
00111 void AtticaProvider::listOfCategoriesLoaded(Attica::BaseJob* listJob)
00112 {
00113     if (!jobSuccess(listJob)) return;
00114     
00115     kDebug() << "loading categories: " << mCategoryMap.keys();
00116 
00117     Attica::ListJob<Attica::Category>* job = static_cast<Attica::ListJob<Attica::Category>*>(listJob);
00118     Category::List categoryList = job->itemList();
00119 
00120     foreach(const Category& category, categoryList) {
00121         if (mCategoryMap.contains(category.name())) {
00122             kDebug() << "Adding category: " << category.name();
00123             mCategoryMap[category.name()] = category;
00124         }
00125     }
00126     mInitialized = true;
00127     emit providerInitialized(this);
00128 }
00129 
00130 bool AtticaProvider::isInitialized() const
00131 {
00132     return mInitialized;
00133 }
00134 
00135 void AtticaProvider::loadEntries(const KNS3::Provider::SearchRequest& request)
00136 {
00137     if (mEntryJob) {
00138         mEntryJob->abort();
00139         mEntryJob = 0;
00140     }
00141 
00142     mCurrentRequest = request;
00143     if (request.sortMode == Installed) {
00144         if (request.page == 0) {
00145             emit loadingFinished(request, installedEntries());
00146         } else {
00147             emit loadingFinished(request, EntryInternal::List());
00148         }
00149         return;
00150     }
00151     
00152     if (request.sortMode == Updates) {
00153         checkForUpdates();
00154         return;
00155     }
00156 
00157     Attica::Provider::SortMode sorting = atticaSortMode(request.sortMode);
00158     Attica::Category::List categoriesToSearch;
00159 
00160     if (request.categories.isEmpty()) {
00161         // search in all categories
00162         categoriesToSearch = mCategoryMap.values();
00163     } else {
00164         foreach (const QString& categoryName, request.categories) {
00165             categoriesToSearch.append(mCategoryMap.value(categoryName));
00166         }
00167     }
00168 
00169     ListJob<Content>* job = m_provider.searchContents(categoriesToSearch, request.searchTerm, sorting, request.page, request.pageSize);
00170     connect(job, SIGNAL(finished(Attica::BaseJob*)), SLOT(categoryContentsLoaded(Attica::BaseJob*)));
00171 
00172     mEntryJob = job;
00173     job->start();
00174 }
00175 
00176 void AtticaProvider::checkForUpdates()
00177 {
00178     foreach (const EntryInternal& e, mCachedEntries) {
00179         ItemJob<Content>* job = m_provider.requestContent(e.uniqueId());
00180         connect(job, SIGNAL(finished(Attica::BaseJob*)), this, SLOT(detailsLoaded(Attica::BaseJob*)));
00181         m_updateJobs.insert(job);
00182         job->start();
00183         kDebug() << "Checking for update: " << e.name();
00184     }
00185 }
00186 
00187 void AtticaProvider::loadEntryDetails(const KNS3::EntryInternal& entry)
00188 {
00189     ItemJob<Content>* job = m_provider.requestContent(entry.uniqueId());
00190     connect(job, SIGNAL(finished(Attica::BaseJob*)), this, SLOT(detailsLoaded(Attica::BaseJob*)));
00191     job->start();
00192 }
00193 
00194 void AtticaProvider::detailsLoaded(BaseJob* job)
00195 {
00196     if (jobSuccess(job)) {
00197         ItemJob<Content>* contentJob = static_cast<ItemJob<Content>*>(job);
00198         Content content = contentJob->result();
00199         EntryInternal entry = entryFromAtticaContent(content);
00200         emit entryDetailsLoaded(entry);
00201         kDebug() << "check update finished: " << entry.name();
00202     }
00203 
00204     if (m_updateJobs.remove(job) && m_updateJobs.isEmpty()) {
00205         kDebug() << "check update finished.";
00206         QList<EntryInternal> updatable;
00207         foreach(const EntryInternal& entry, mCachedEntries) {
00208             if (entry.status() == Entry::Updateable) {
00209                 updatable.append(entry);
00210             }
00211         }
00212         emit loadingFinished(mCurrentRequest, updatable);
00213     }    
00214 }
00215 
00216 void AtticaProvider::categoryContentsLoaded(BaseJob* job)
00217 {
00218     if (!jobSuccess(job)) return;
00219 
00220     ListJob<Content>* listJob = static_cast<ListJob<Content>*>(job);
00221     Content::List contents = listJob->itemList();
00222 
00223     EntryInternal::List entries;
00224     Q_FOREACH(const Content &content, contents) {
00225         mCachedContent.insert(content.id(), content);
00226         entries.append(entryFromAtticaContent(content));
00227     }
00228 
00229     kDebug() << "loaded: " << mCurrentRequest.hashForRequest() << " count: " << entries.size();
00230     emit loadingFinished(mCurrentRequest, entries);
00231     mEntryJob = 0;
00232 }
00233 
00234 Attica::Provider::SortMode AtticaProvider::atticaSortMode(const SortMode& sortMode)
00235 {
00236     if (sortMode == Newest) {
00237         return Attica::Provider::Newest;
00238     }
00239     if (sortMode == Alphabetical) {
00240         return Attica::Provider::Alphabetical;
00241     }
00242     if (sortMode == Downloads) {
00243         return Attica::Provider::Downloads;
00244     }
00245     return Attica::Provider::Rating;
00246 }
00247 
00248 void AtticaProvider::loadPayloadLink(const KNS3::EntryInternal& entry, int linkId)
00249 {
00250     Attica::Content content = mCachedContent.value(entry.uniqueId());
00251     DownloadDescription desc = content.downloadUrlDescription(linkId);
00252 
00253     if (desc.hasPrice()) {
00254         // Ask for balance, then show information...
00255         ItemJob<AccountBalance>* job = m_provider.requestAccountBalance();
00256         connect(job, SIGNAL(finished(Attica::BaseJob*)), SLOT(accountBalanceLoaded(Attica::BaseJob*)));
00257         mDownloadLinkJobs[job] = qMakePair(entry, linkId);
00258         job->start();
00259 
00260         kDebug() << "get account balance";
00261     } else {
00262         ItemJob<DownloadItem>* job = m_provider.downloadLink(entry.uniqueId(), QString::number(linkId));
00263         connect(job, SIGNAL(finished(Attica::BaseJob*)), SLOT(downloadItemLoaded(Attica::BaseJob*)));
00264         mDownloadLinkJobs[job] = qMakePair(entry, linkId);
00265         job->start();
00266 
00267         kDebug() << " link for " << entry.uniqueId();
00268     }
00269 }
00270 
00271 void AtticaProvider::accountBalanceLoaded(Attica::BaseJob* baseJob)
00272 {
00273     if (!jobSuccess(baseJob)) return;
00274 
00275     ItemJob<AccountBalance>* job = static_cast<ItemJob<AccountBalance>*>(baseJob);
00276     AccountBalance item = job->result();
00277 
00278     QPair<EntryInternal, int> pair = mDownloadLinkJobs.take(job);
00279     EntryInternal entry(pair.first);
00280     Content content = mCachedContent.value(entry.uniqueId());
00281     if (content.downloadUrlDescription(pair.second).priceAmount() < item.balance()) {
00282         kDebug() << "Your balance is greather than the price."
00283                     << content.downloadUrlDescription(pair.second).priceAmount() << " balance: " << item.balance();
00284         if (KMessageBox::questionYesNo(0,
00285                 i18nc("the price of a download item, parameter 1 is the currency, 2 is the price",
00286                       "This items costs %1 %2.\nDo you want to buy it?",
00287                       item.currency(), content.downloadUrlDescription(pair.second).priceAmount()
00288                 )) == KMessageBox::Yes) {
00289             ItemJob<DownloadItem>* job = m_provider.downloadLink(entry.uniqueId(), QString::number(pair.second));
00290             connect(job, SIGNAL(finished(Attica::BaseJob*)), SLOT(downloadItemLoaded(Attica::BaseJob*)));
00291             connect(job, SIGNAL(jobStarted(QNetworkReply*)), SLOT(atticaJobStarted(QNetworkReply*)));
00292             mDownloadLinkJobs[job] = qMakePair(entry, pair.second);
00293             job->start();
00294         } else {
00295             return;
00296         }
00297     } else {
00298         kDebug() << "You don't have enough money on your account!"
00299                 << content.downloadUrlDescription(0).priceAmount() << " balance: " << item.balance();
00300         KMessageBox::information(0, i18n("Your account balance is too low:\nYour balance: %1\nPrice: %2",
00301                                          item.balance(),content.downloadUrlDescription(0).priceAmount()));
00302     }
00303 }
00304 
00305 void AtticaProvider::downloadItemLoaded(BaseJob* baseJob)
00306 {
00307     if (!jobSuccess(baseJob)) return;
00308 
00309     ItemJob<DownloadItem>* job = static_cast<ItemJob<DownloadItem>*>(baseJob);
00310     DownloadItem item = job->result();
00311 
00312     EntryInternal entry = mDownloadLinkJobs.take(job).first;
00313     entry.setPayload(QString(item.url().toString()));
00314     emit payloadLinkLoaded(entry);
00315 }
00316 
00317 EntryInternal::List AtticaProvider::installedEntries() const
00318 {
00319     EntryInternal::List entries;
00320     foreach (const EntryInternal& entry, mCachedEntries) {
00321         if (entry.status() == Entry::Installed || entry.status() == Entry::Updateable) {
00322             entries.append(entry);
00323         }
00324     }
00325     return entries;
00326 }
00327 
00328 void AtticaProvider::vote(const EntryInternal& entry, uint rating)
00329 {
00330     PostJob * job = m_provider.voteForContent(entry.uniqueId(), rating);
00331     connect(job, SIGNAL(finished(Attica::BaseJob*)), this, SLOT(votingFinished(Attica::BaseJob*)));
00332     connect(job, SIGNAL(jobStarted(QNetworkReply*)), SLOT(atticaJobStarted(QNetworkReply*)));
00333     job->start();
00334 }
00335 
00336 void AtticaProvider::votingFinished(Attica::BaseJob* job)
00337 {
00338     if (!jobSuccess(job)) return;
00339     emit signalInformation(i18nc("voting for an item (good/bad)", "Your vote was recorded."));
00340 }
00341 
00342 void AtticaProvider::becomeFan(const EntryInternal& entry)
00343 {
00344     PostJob * job = m_provider.becomeFan(entry.uniqueId());
00345     connect(job, SIGNAL(finished(Attica::BaseJob*)), this, SLOT(becomeFanFinished(Attica::BaseJob*)));
00346     connect(job, SIGNAL(jobStarted(QNetworkReply*)), SLOT(atticaJobStarted(QNetworkReply*)));
00347     job->start();
00348 }
00349 
00350 void AtticaProvider::becomeFanFinished(Attica::BaseJob* job)
00351 {
00352     if (!jobSuccess(job)) return;
00353     emit signalInformation(i18n("You are now a fan."));
00354 }
00355 
00356 bool AtticaProvider::jobSuccess(Attica::BaseJob* job) const
00357 {
00358     if (job->metadata().error() == Attica::Metadata::NoError) {
00359         return true;
00360     }
00361     kDebug() << "job error: " << job->metadata().error() << " status code: " << job->metadata().statusCode() << job->metadata().message();
00362 
00363     if (job->metadata().error() == Attica::Metadata::NetworkError) {
00364         emit signalError(i18n("Network error. (%1)", job->metadata().statusCode()));
00365     }
00366     if (job->metadata().error() == Attica::Metadata::OcsError) {
00367         if (job->metadata().statusCode() == 200) {
00368             emit signalError(i18n("Too many requests to server. Please try again in a few minutes."));
00369         } else {
00370             emit signalError(i18n("Unknown Open Collaboration Service API error. (%1)", job->metadata().statusCode()));
00371         }
00372     }
00373     return false;
00374 }
00375 
00376 EntryInternal AtticaProvider::entryFromAtticaContent(const Attica::Content& content)
00377 {
00378     EntryInternal entry;
00379 
00380     entry.setProviderId(id());
00381     entry.setUniqueId(content.id());
00382     entry.setStatus(KNS3::Entry::Downloadable);
00383     entry.setVersion(content.version());
00384     entry.setReleaseDate(content.updated().date());
00385 
00386     int index = mCachedEntries.indexOf(entry);
00387     if (index >= 0) {
00388         EntryInternal &cacheEntry = mCachedEntries[index];
00389         // check if updateable
00390         if (((cacheEntry.status() == Entry::Installed) || (cacheEntry.status() == Entry::Updateable)) &&
00391             ((cacheEntry.version() != entry.version()) || (cacheEntry.releaseDate() != entry.releaseDate()))) {
00392             cacheEntry.setStatus(Entry::Updateable);
00393             cacheEntry.setUpdateVersion(entry.version());
00394             cacheEntry.setUpdateReleaseDate(entry.releaseDate());
00395         }
00396         entry = cacheEntry;
00397     } else {
00398         mCachedEntries.append(entry);
00399     }
00400 
00401     entry.setName(content.name());
00402     entry.setHomepage(content.detailpage());
00403     entry.setRating(content.rating());
00404     entry.setDownloadCount(content.downloads());
00405     entry.setNumberFans(content.attribute("fans").toInt());
00406     entry.setDonationLink(content.attribute("donationpage"));
00407     entry.setKnowledgebaseLink(content.attribute("knowledgebasepage"));
00408     entry.setNumberKnowledgebaseEntries(content.attribute("knowledgebaseentries").toInt());
00409     
00410     entry.setPreviewUrl(content.smallPreviewPicture("1"), EntryInternal::PreviewSmall1);
00411     entry.setPreviewUrl(content.smallPreviewPicture("2"), EntryInternal::PreviewSmall2);
00412     entry.setPreviewUrl(content.smallPreviewPicture("3"), EntryInternal::PreviewSmall3);
00413 
00414     entry.setPreviewUrl(content.previewPicture("1"), EntryInternal::PreviewBig1);
00415     entry.setPreviewUrl(content.previewPicture("2"), EntryInternal::PreviewBig2);
00416     entry.setPreviewUrl(content.previewPicture("3"), EntryInternal::PreviewBig3);
00417 
00418     entry.setLicense(content.license());
00419     Author author;
00420     author.setName(content.author());
00421     author.setHomepage(content.attribute("profilepage"));
00422     entry.setAuthor(author);
00423 
00424     entry.setSource(KNS3::EntryInternal::Online);
00425     entry.setSummary(content.description());
00426     entry.setChangelog(content.changelog());
00427 
00428     entry.clearDownloadLinkInformation();
00429     QList<Attica::DownloadDescription> descs = content.downloadUrlDescriptions();
00430     foreach (Attica::DownloadDescription desc, descs) {
00431         EntryInternal::DownloadLinkInformation info;
00432         info.name = desc.name();
00433         info.priceAmount = desc.priceAmount();
00434         info.distributionType = desc.distributionType();
00435         info.descriptionLink = desc.link();
00436         info.id = desc.id();
00437         info.isDownloadtypeLink = desc.isDownloadtypLink();
00438         entry.appendDownloadLinkInformation(info);
00439     }
00440 
00441     return entry;
00442 }
00443 
00444 } // namespace
00445 
00446 
00447 #include "atticaprovider.moc"

KNewStuff

Skip menu "KNewStuff"
  • 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
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.3
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