summaryrefslogtreecommitdiffstats
path: root/src/newstuff
diff options
context:
space:
mode:
Diffstat (limited to 'src/newstuff')
-rw-r--r--src/newstuff/Makefile.am18
-rw-r--r--src/newstuff/dialog.cpp477
-rw-r--r--src/newstuff/dialog.h101
-rw-r--r--src/newstuff/manager.cpp446
-rw-r--r--src/newstuff/manager.h101
-rw-r--r--src/newstuff/newscript.cpp48
-rw-r--r--src/newstuff/newscript.h60
-rw-r--r--src/newstuff/providerloader.cpp102
-rw-r--r--src/newstuff/providerloader.h84
9 files changed, 1437 insertions, 0 deletions
diff --git a/src/newstuff/Makefile.am b/src/newstuff/Makefile.am
new file mode 100644
index 0000000..9054dcb
--- /dev/null
+++ b/src/newstuff/Makefile.am
@@ -0,0 +1,18 @@
+noinst_LIBRARIES = libnewstuff.a
+
+libnewstuff_a_METASOURCES = AUTO
+
+libnewstuff_a_SOURCES = manager.cpp dialog.cpp newscript.cpp providerloader.cpp
+
+CLEANFILES = *~
+
+EXTRA_DIST = \
+manager.h manager.cpp \
+dialog.h dialog.cpp \
+newscript.h newscript.cpp \
+providerloader.h providerloader.cpp
+
+AM_CPPFLAGS = $(all_includes)
+
+KDE_OPTIONS = noautodist
+
diff --git a/src/newstuff/dialog.cpp b/src/newstuff/dialog.cpp
new file mode 100644
index 0000000..c13a249
--- /dev/null
+++ b/src/newstuff/dialog.cpp
@@ -0,0 +1,477 @@
+/***************************************************************************
+ copyright : (C) 2006 by Robby Stephenson
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#include "dialog.h"
+#include "providerloader.h"
+#include "../gui/listview.h"
+#include "../latin1literal.h"
+#include "../tellico_utils.h"
+#include "../tellico_debug.h"
+
+#include <klocale.h>
+#include <kpushbutton.h>
+#include <kconfig.h>
+#include <kiconloader.h>
+#include <kstatusbar.h>
+#include <kio/job.h>
+#include <kio/netaccess.h>
+#include <kaccelmanager.h>
+#include <knewstuff/entry.h>
+#include <knewstuff/provider.h>
+#include <ktempfile.h>
+
+#include <qlabel.h>
+#include <qtextedit.h>
+#include <qlayout.h>
+#include <qwhatsthis.h>
+#include <qregexp.h>
+#include <qvbox.h>
+#include <qimage.h>
+#include <qtimer.h>
+#include <qprogressbar.h>
+
+#if KDE_IS_VERSION(3,4,90)
+#define ENTRYNAME(e) e->name(m_lang)
+#define ENTRYSUMM(e) e->summary(m_lang)
+#define ENTRYEMAIL(e) e->authorEmail()
+#else
+#define ENTRYNAME(e) e->name()
+#define ENTRYSUMM(e) e->summary()
+#define ENTRYEMAIL(e) QString()
+#endif
+
+namespace {
+ static const int NEW_STUFF_MIN_WIDTH = 600;
+ static const int NEW_STUFF_MIN_HEIGHT = 400;
+ static const int PROGRESS_STATUS_ID = 0;
+}
+
+using Tellico::NewStuff::Dialog;
+
+class Dialog::Item : public GUI::ListViewItem {
+public:
+ Item(GUI::ListView* parent) : GUI::ListViewItem(parent) {}
+
+ InstallStatus status() const { return m_status; }
+ void setStatus(InstallStatus status) {
+ m_status = status;
+ if(m_status == Current) {
+ setPixmap(0, SmallIcon(QString::fromLatin1("ok")));
+ } else if(m_status == OldVersion) {
+ setPixmap(0, SmallIcon(QString::fromLatin1("reload")));
+ }
+ }
+
+ QString key(int col, bool asc) const {
+ if(col == 2 || col == 3) {
+ QString s;
+ s.sprintf("%08d", text(col).toInt());
+ return s;
+ } else if(col == 4) {
+ QString s;
+ QDate date = KGlobal::locale()->readDate(text(col));
+ s.sprintf("%08d", date.year() * 366 + date.dayOfYear());
+ return s;
+ }
+ return GUI::ListViewItem::key(col, asc);
+ }
+
+private:
+ InstallStatus m_status;
+};
+
+Dialog::Dialog(NewStuff::DataType type_, QWidget* parent_)
+ : KDialogBase(KDialogBase::Plain, i18n("Get Hot New Stuff"), 0, (KDialogBase::ButtonCode)0, parent_)
+ , m_manager(new Manager(this))
+ , m_type(type_)
+ , m_timer(new QTimer(this))
+ , m_cursorSaver(new GUI::CursorSaver())
+ , m_tempPreviewImage(0)
+ , m_lastPreviewItem(0) {
+
+ m_lang = KGlobal::locale()->language();
+
+ QFrame* frame = plainPage();
+ QBoxLayout* boxLayout = new QVBoxLayout(frame, 0, KDialog::spacingHint());
+
+ m_split = new QSplitter(Qt::Vertical, frame);
+ boxLayout->addWidget(m_split);
+
+ m_listView = new GUI::ListView(m_split);
+ m_listView->setAllColumnsShowFocus(true);
+ m_listView->setSelectionMode(QListView::Single);
+ m_listView->addColumn(i18n("Name"));
+ m_listView->addColumn(i18n("Version"));
+ m_listView->addColumn(i18n("Rating"));
+ m_listView->addColumn(i18n("Downloads"));
+ m_listView->addColumn(i18n("Release Date"));
+ m_listView->setSorting(2, false);
+ m_listView->setResizeMode(QListView::AllColumns);
+ connect(m_listView, SIGNAL(clicked(QListViewItem*)), SLOT(slotSelected(QListViewItem*)));
+ QWhatsThis::add(m_listView, i18n("This is a list of all the items available for download. "
+ "Previously installed items have a checkmark icon, while "
+ "items with new version available have an update icon"));
+
+ QWidget* widget = new QWidget(m_split);
+ QBoxLayout* boxLayout2 = new QVBoxLayout(widget, 0, KDialog::spacingHint());
+
+ m_iconLabel = new QLabel(widget);
+ m_iconLabel->setAlignment(Qt::AlignTop | Qt::AlignLeft);
+ m_iconLabel->setMargin(0);
+
+ m_nameLabel = new QLabel(widget);
+ QFont font = m_nameLabel->font();
+ font.setBold(true);
+ font.setItalic(true);
+ m_nameLabel->setFont(font);
+ QWhatsThis::add(m_nameLabel, i18n("The name and license of the selected item"));
+
+ m_infoLabel = new QLabel(widget);
+ QWhatsThis::add(m_infoLabel, i18n("The author of the selected item"));
+
+ m_install = new KPushButton(i18n("Install"), widget);
+ m_install->setIconSet(SmallIconSet(QString::fromLatin1("knewstuff")));
+ m_install->setEnabled(false);
+ connect(m_install, SIGNAL(clicked()), SLOT(slotInstall()));
+
+ // the button's text changes later
+ // I don't want it resizing, so figure out the maximum size and set that
+ m_install->polish();
+ int maxWidth = m_install->sizeHint().width();
+ int maxHeight = m_install->sizeHint().height();
+ m_install->setGuiItem(KGuiItem(i18n("Update"), SmallIconSet(QString::fromLatin1("knewstuff"))));
+ maxWidth = QMAX(maxWidth, m_install->sizeHint().width());
+ maxHeight = QMAX(maxHeight, m_install->sizeHint().height());
+ m_install->setMinimumWidth(maxWidth);
+ m_install->setMinimumHeight(maxHeight);
+
+ QPixmap pix;
+ if(m_type == EntryTemplate) {
+ pix = DesktopIcon(QString::fromLatin1("looknfeel"), KIcon::SizeLarge);
+ QWhatsThis::add(m_install, i18n("Download and install the selected template."));
+ } else {
+ pix = UserIcon(QString::fromLatin1("script"));
+ QWhatsThis::add(m_install, i18n("Download and install the selected script. Some scripts "
+ "may need to be configured after being installed."));
+ }
+ m_iconLabel->setPixmap(pix);
+
+ QBoxLayout* boxLayout3 = new QHBoxLayout(boxLayout2);
+
+ QBoxLayout* boxLayout4 = new QVBoxLayout(boxLayout3);
+ boxLayout4->addWidget(m_iconLabel);
+ boxLayout4->addStretch(10);
+
+ boxLayout3->addSpacing(4);
+
+ QBoxLayout* boxLayout5 = new QVBoxLayout(boxLayout3);
+ boxLayout5->addWidget(m_nameLabel);
+ boxLayout5->addWidget(m_infoLabel);
+ boxLayout5->addStretch(10);
+
+ boxLayout3->addStretch(10);
+
+ QBoxLayout* boxLayout6 = new QVBoxLayout(boxLayout3);
+ boxLayout6->addWidget(m_install);
+ boxLayout6->addStretch(10);
+
+ m_descLabel = new QTextEdit(widget);
+ m_descLabel->setReadOnly(true);
+ m_descLabel->setTextFormat(Qt::RichText);
+ m_descLabel->setPaper(colorGroup().background());
+ m_descLabel->setMinimumHeight(5 * fontMetrics().height());
+ boxLayout2->addWidget(m_descLabel, 10);
+ QWhatsThis::add(m_descLabel, i18n("A description of the selected item is shown here."));
+
+ QHBox* box = new QHBox(frame, "statusbox");
+ boxLayout->addWidget(box);
+ box->setSpacing(KDialog::spacingHint());
+
+ m_statusBar = new KStatusBar(box, "statusbar");
+ m_statusBar->insertItem(QString::null, PROGRESS_STATUS_ID, 1, false);
+ m_statusBar->setItemAlignment(PROGRESS_STATUS_ID, AlignLeft | AlignVCenter);
+ m_progress = new QProgressBar(m_statusBar, "progress");
+ m_progress->setTotalSteps(0);
+ m_progress->setFixedHeight(fontMetrics().height()+2);
+ m_statusBar->addWidget(m_progress, 0, true);
+
+ KPushButton* closeButton = new KPushButton(KStdGuiItem::close(), box);
+ connect(closeButton, SIGNAL(clicked()), SLOT(slotClose()));
+ closeButton->setFocus();
+
+ connect(m_timer, SIGNAL(timeout()), SLOT(slotMoveProgress()));
+
+ setMinimumWidth(QMAX(minimumWidth(), NEW_STUFF_MIN_WIDTH));
+ setMinimumHeight(QMAX(minimumHeight(), NEW_STUFF_MIN_HEIGHT));
+ resize(configDialogSize(QString::fromLatin1("NewStuff Dialog Options")));
+
+ KConfigGroup dialogConfig(KGlobal::config(), "NewStuff Dialog Options");
+ QValueList<int> splitList = dialogConfig.readIntListEntry("Splitter Sizes");
+ if(!splitList.empty()) {
+ m_split->setSizes(splitList);
+ }
+
+ setStatus(i18n("Downloading information..."));
+
+ ProviderLoader* loader = new Tellico::NewStuff::ProviderLoader(this);
+ connect(loader, SIGNAL(providersLoaded(QPtrList<KNS::Provider>*)), SLOT(slotProviders(QPtrList<KNS::Provider>*)));
+ connect(loader, SIGNAL(percent(KIO::Job*, unsigned long)), SLOT(slotShowPercent(KIO::Job*, unsigned long)));
+ connect(loader, SIGNAL(error()), SLOT(slotProviderError()));
+
+ KConfigGroup config(KGlobal::config(), "KNewStuff");
+ QString prov = config.readEntry("ProvidersUrl");
+ if(prov.isEmpty()) {
+ if(m_type == EntryTemplate) {
+ prov = QString::fromLatin1("http://periapsis.org/tellico/newstuff/tellicotemplates-providers.php");
+ QString alt = QString::fromLatin1("http://download.kde.org/khotnewstuff/tellicotemplates-providers.xml");
+ loader->setAlternativeProvider(alt);
+ } else {
+ prov = QString::fromLatin1("http://periapsis.org/tellico/newstuff/tellicoscripts-providers.php");
+ }
+ }
+ if(m_type == EntryTemplate) {
+ m_typeName = QString::fromLatin1("tellico/entry-template");
+ } else {
+ m_typeName = QString::fromLatin1("tellico/data-source");
+ }
+ loader->load(m_typeName, prov);
+
+ KAcceleratorManager::manage(this);
+}
+
+Dialog::~Dialog() {
+ delete m_cursorSaver;
+ m_cursorSaver = 0;
+
+ saveDialogSize(QString::fromLatin1("NewStuff Dialog Options"));
+ KConfigGroup config(KGlobal::config(), "NewStuff Dialog Options");
+ config.writeEntry("Splitter Sizes", m_split->sizes());
+}
+
+void Dialog::slotProviderError() {
+ if(m_listView->childCount() == 0) {
+ myDebug() << "NewStuff::Dialog::slotCheckError() - no available items" << endl;
+ setStatus(QString());
+
+ delete m_cursorSaver;
+ m_cursorSaver = 0;
+ }
+}
+
+void Dialog::slotProviders(QPtrList<KNS::Provider>* list_) {
+ for(KNS::Provider* prov = list_->first(); prov; prov = list_->next()) {
+ KIO::TransferJob* job = KIO::get(prov->downloadUrl());
+ m_jobs[job] = prov;
+ connect(job, SIGNAL(data(KIO::Job*, const QByteArray&)),
+ SLOT(slotData(KIO::Job*, const QByteArray&)));
+ connect(job, SIGNAL(result(KIO::Job*)), SLOT(slotResult(KIO::Job*)));
+ connect(job, SIGNAL(percent(KIO::Job*, unsigned long)),
+ SLOT(slotShowPercent(KIO::Job*, unsigned long)));
+ }
+}
+
+void Dialog::slotData(KIO::Job* job_, const QByteArray& data_) {
+ QDataStream stream(m_data[job_], IO_WriteOnly | IO_Append);
+ stream.writeRawBytes(data_.data(), data_.size());
+}
+
+void Dialog::slotResult(KIO::Job* job_) {
+// myDebug() << "NewStuff::Dialog::slotResult()" << endl;
+ QDomDocument dom;
+ if(!dom.setContent(m_data[job_])) {
+ KNS::Provider* prov = m_jobs[job_];
+ KURL u = prov ? prov->downloadUrl() : KURL();
+ myDebug() << "NewStuff::Dialog::slotResult() - can't load result: " << u.url() << endl;
+ m_jobs.remove(job_);
+ if(m_jobs.isEmpty()) {
+ setStatus(i18n("Ready."));
+ delete m_cursorSaver;
+ m_cursorSaver = 0;
+ }
+ return;
+ }
+
+ QDomElement knewstuff = dom.documentElement();
+
+ for(QDomNode pn = knewstuff.firstChild(); !pn.isNull(); pn = pn.nextSibling()) {
+ QDomElement stuff = pn.toElement();
+ if(stuff.isNull()) {
+ continue;
+ }
+
+ if(stuff.tagName() == Latin1Literal("stuff")) {
+ KNS::Entry* entry = new KNS::Entry(stuff);
+ if(!entry->type().isEmpty() && entry->type() != m_typeName) {
+ myLog() << "NewStuff::Dialog::slotResult() - type mismatch, skipping " << ENTRYNAME(entry) << endl;
+ continue;
+ }
+
+ addEntry(entry);
+ }
+ }
+ m_jobs.remove(job_);
+ if(m_jobs.isEmpty()) {
+ setStatus(i18n("Ready."));
+ delete m_cursorSaver;
+ m_cursorSaver = 0;
+ }
+}
+
+void Dialog::addEntry(KNS::Entry* entry_) {
+ if(!entry_) {
+ return;
+ }
+
+ Item* item = new Item(m_listView);
+ item->setText(0, ENTRYNAME(entry_));
+ item->setText(1, entry_->version());
+ item->setText(2, QString::number(entry_->rating()));
+ item->setText(3, QString::number(entry_->downloads()));
+ item->setText(4, KGlobal::locale()->formatDate(entry_->releaseDate(), true /*short format */));
+ item->setStatus(NewStuff::Manager::installStatus(entry_));
+ m_entryMap.insert(item, entry_);
+
+ if(!m_listView->selectedItem()) {
+ m_listView->setSelected(item, true);
+ slotSelected(item);
+ }
+}
+
+void Dialog::slotSelected(QListViewItem* item_) {
+ if(!item_) {
+ return;
+ }
+
+ KNS::Entry* entry = m_entryMap[item_];
+ if(!entry) {
+ return;
+ }
+
+ KURL preview = entry->preview(m_lang);
+ if(!preview.isEmpty() && preview.isValid()) {
+ delete m_tempPreviewImage;
+ m_tempPreviewImage = new KTempFile();
+ m_tempPreviewImage->setAutoDelete(true);
+ KURL dest;
+ dest.setPath(m_tempPreviewImage->name());
+ KIO::FileCopyJob* job = KIO::file_copy(preview, dest, -1, true, false, false);
+ connect(job, SIGNAL(result(KIO::Job*)), SLOT(slotPreviewResult(KIO::Job*)));
+ connect(job, SIGNAL(percent(KIO::Job*, unsigned long)),
+ SLOT(slotShowPercent(KIO::Job*, unsigned long)));
+ m_lastPreviewItem = item_;
+ }
+ QPixmap pix = m_type == EntryTemplate
+ ? DesktopIcon(QString::fromLatin1("looknfeel"), KIcon::SizeLarge)
+ : UserIcon(QString::fromLatin1("script"));
+ m_iconLabel->setPixmap(pix);
+
+ QString license = entry->license();
+ if(!license.isEmpty()) {
+ license.prepend('(').append(')');
+ }
+ QString name = QString::fromLatin1("%1 %2").arg(ENTRYNAME(entry)).arg(license);
+ QFont font = m_nameLabel->font();
+ font.setBold(true);
+ font.setItalic(false);
+ m_nameLabel->setFont(font);
+ m_nameLabel->setText(name);
+
+ m_infoLabel->setText(entry->author());
+
+ QString desc = entry->summary(m_lang);
+ desc.replace(QRegExp(QString::fromLatin1("\\n")), QString::fromLatin1("<br>"));
+ m_descLabel->setText(desc);
+
+ InstallStatus installed = static_cast<Item*>(item_)->status();
+ m_install->setText(installed == OldVersion ? i18n("Update Stuff", "Update") : i18n("Install"));
+ m_install->setEnabled(installed != Current);
+}
+
+void Dialog::slotInstall() {
+ QListViewItem* item = m_listView->currentItem();
+ if(!item) {
+ return;
+ }
+
+ KNS::Entry* entry = m_entryMap[item];
+ if(!entry) {
+ return;
+ }
+
+ delete m_cursorSaver;
+ m_cursorSaver = new GUI::CursorSaver();
+ setStatus(i18n("Installing item..."));
+ m_progress->show();
+ m_timer->start(100);
+ connect(m_manager, SIGNAL(signalInstalled(KNS::Entry*)), SLOT(slotDoneInstall(KNS::Entry*)));
+ m_manager->install(m_type, entry);
+ delete m_cursorSaver;
+ m_cursorSaver = 0;
+}
+
+void Dialog::slotDoneInstall(KNS::Entry* entry_) {
+ QMap<QListViewItem*, KNS::Entry*>::Iterator it;
+ for(it = m_entryMap.begin(); entry_ && it != m_entryMap.end(); ++it) {
+ if(it.data() == entry_) {
+ InstallStatus installed = Manager::installStatus(entry_);
+ static_cast<Item*>(it.key())->setStatus(installed);
+ m_install->setEnabled(installed != Current);
+ break;
+ }
+ }
+ delete m_cursorSaver;
+ m_cursorSaver = 0;
+ setStatus(i18n("Ready."));
+ m_timer->stop();
+ m_progress->hide();
+}
+
+void Dialog::slotMoveProgress() {
+ m_progress->setProgress(m_progress->progress()+5);
+}
+
+void Dialog::setStatus(const QString& text_) {
+ m_statusBar->changeItem(QChar(' ') + text_, PROGRESS_STATUS_ID);
+}
+
+void Dialog::slotShowPercent(KIO::Job*, unsigned long pct_) {
+ if(pct_ >= 100) {
+ m_progress->hide();
+ } else {
+ m_progress->show();
+ m_progress->setProgress(static_cast<int>(pct_), 100);
+ }
+}
+
+void Dialog::slotPreviewResult(KIO::Job* job_) {
+ KIO::FileCopyJob* job = static_cast<KIO::FileCopyJob*>(job_);
+ if(job->error()) {
+ return;
+ }
+ QString tmpFile = job->destURL().path(); // might be different than m_tempPreviewImage->name()
+ QPixmap pix(tmpFile);
+
+ if(!pix.isNull()) {
+ if(pix.width() > 64 || pix.height() > 64) {
+ pix.convertFromImage(pix.convertToImage().smoothScale(64, 64, QImage::ScaleMin));
+ }
+ // only set label if it's still current
+ if(m_listView->selectedItem() == m_lastPreviewItem) {
+ m_iconLabel->setPixmap(pix);
+ }
+ }
+ delete m_tempPreviewImage;
+ m_tempPreviewImage = 0;
+}
+
+#include "dialog.moc"
diff --git a/src/newstuff/dialog.h b/src/newstuff/dialog.h
new file mode 100644
index 0000000..f1c5e48
--- /dev/null
+++ b/src/newstuff/dialog.h
@@ -0,0 +1,101 @@
+/***************************************************************************
+ copyright : (C) 2006 by Robby Stephenson
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#ifndef TELLICO_NEWSTUFF_DIALOG_H
+#define TELLICO_NEWSTUFF_DIALOG_H
+
+#include "manager.h"
+
+#include <kdialogbase.h>
+
+class KPushButton;
+class KStatusBar;
+namespace KIO {
+ class Job;
+}
+namespace KNS {
+ class Entry;
+ class Provider;
+}
+
+class QProgressBar;
+class QSplitter;
+class QLabel;
+class QTextEdit;
+
+namespace Tellico {
+ namespace GUI {
+ class ListView;
+ class CursorSaver;
+ }
+
+ namespace NewStuff {
+
+class Dialog : public KDialogBase {
+Q_OBJECT
+
+public:
+ Dialog(DataType type, QWidget* parent);
+ virtual ~Dialog();
+
+ QPtrList<DataSourceInfo> dataSourceInfo() const { return m_manager->dataSourceInfo(); }
+
+private slots:
+ void slotProviders(QPtrList<KNS::Provider>* list);
+ void slotData(KIO::Job* job, const QByteArray& data);
+ void slotResult(KIO::Job* job);
+ void slotPreviewResult(KIO::Job* job);
+
+ void slotShowPercent(KIO::Job* job, unsigned long percent);
+
+ void slotSelected(QListViewItem* item);
+ void slotInstall();
+ void slotDoneInstall(KNS::Entry* entry);
+
+ void slotProviderError();
+ void slotMoveProgress();
+
+private:
+ class Item;
+
+ void setStatus(const QString& status);
+ void addEntry(KNS::Entry* entry);
+
+ Manager* const m_manager;
+ DataType m_type;
+ QString m_lang;
+ QString m_typeName;
+
+ QSplitter* m_split;
+ GUI::ListView* m_listView;
+ QLabel* m_iconLabel;
+ QLabel* m_nameLabel;
+ QLabel* m_infoLabel;
+ QTextEdit* m_descLabel;
+ KPushButton* m_install;
+ KStatusBar* m_statusBar;
+ QProgressBar* m_progress;
+ QTimer* m_timer;
+ GUI::CursorSaver* m_cursorSaver;
+ KTempFile* m_tempPreviewImage;
+
+ QMap<KIO::Job*, KNS::Provider*> m_jobs;
+ QMap<KIO::Job*, QByteArray> m_data;
+
+ QMap<QListViewItem*, KNS::Entry*> m_entryMap;
+ QListViewItem* m_lastPreviewItem;
+};
+
+ }
+}
+#endif
diff --git a/src/newstuff/manager.cpp b/src/newstuff/manager.cpp
new file mode 100644
index 0000000..3b7efbf
--- /dev/null
+++ b/src/newstuff/manager.cpp
@@ -0,0 +1,446 @@
+/***************************************************************************
+ copyright : (C) 2006 by Robby Stephenson
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#include "manager.h"
+#include "newscript.h"
+#include "../filehandler.h"
+#include "../tellico_debug.h"
+#include "../tellico_utils.h"
+#include "../tellico_kernel.h"
+#include "../fetch/fetch.h"
+
+#include <kurl.h>
+#include <ktar.h>
+#include <kglobal.h>
+#include <kio/netaccess.h>
+#include <kconfig.h>
+#include <ktempfile.h>
+#include <kio/job.h>
+#include <kfileitem.h>
+#include <kdeversion.h>
+#include <knewstuff/entry.h>
+#include <kstandarddirs.h>
+
+#include <qfileinfo.h>
+#include <qdir.h>
+#include <qptrstack.h>
+#include <qvaluestack.h>
+#include <qwidget.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+using Tellico::NewStuff::Manager;
+
+Manager::Manager(QObject* parent_) : QObject(parent_), m_tempFile(0) {
+ m_infoList.setAutoDelete(true);
+}
+
+Manager::~Manager() {
+ delete m_tempFile;
+ m_tempFile = 0;
+}
+
+bool Manager::installTemplate(const KURL& url_, const QString& entryName_) {
+ FileHandler::FileRef* ref = FileHandler::fileRef(url_);
+
+ QString xslFile;
+ QStringList allFiles;
+
+ bool success = true;
+
+ // is there a better way to figure out if the url points to a XSL file or a tar archive
+ // than just trying to open it?
+ KTar archive(ref->fileName());
+ if(archive.open(IO_ReadOnly)) {
+ const KArchiveDirectory* archiveDir = archive.directory();
+ archiveDir->copyTo(Tellico::saveLocation(QString::fromLatin1("entry-templates/")));
+
+ allFiles = archiveFiles(archiveDir);
+ // remember files installed for template
+ xslFile = findXSL(archiveDir);
+ } else { // assume it's an xsl file
+ QString name = entryName_;
+ if(name.isEmpty()) {
+ name = url_.fileName();
+ }
+ if(!name.endsWith(QString::fromLatin1(".xsl"))) {
+ name += QString::fromLatin1(".xsl");
+ }
+ KURL dest;
+ dest.setPath(Tellico::saveLocation(QString::fromLatin1("entry-templates/")) + name);
+ success = true;
+ if(QFile::exists(dest.path())) {
+ myDebug() << "Manager::installTemplate() - " << dest.path() << " exists!" << endl;
+ success = false;
+ } else if(KIO::NetAccess::file_copy(url_, dest)) {
+ xslFile = dest.fileName();
+ allFiles += xslFile;
+ }
+ }
+
+ if(xslFile.isEmpty()) {
+ success = false;
+ } else {
+ // remove ".xsl"
+ xslFile.truncate(xslFile.length()-4);
+ KConfigGroup config(KGlobal::config(), "KNewStuffFiles");
+ config.writeEntry(xslFile, allFiles);
+ m_urlNameMap.insert(url_, xslFile);
+ }
+
+ checkCommonFile();
+
+ delete ref;
+ return success;
+}
+
+bool Manager::removeTemplate(const QString& name_) {
+ KConfigGroup fileGroup(KGlobal::config(), "KNewStuffFiles");
+ QStringList files = fileGroup.readListEntry(name_);
+ // at least, delete xsl file
+ if(files.isEmpty()) {
+ kdWarning() << "Manager::deleteTemplate() no file list found for " << name_ << endl;
+ files += name_;
+ }
+
+ bool success = true;
+ QString path = Tellico::saveLocation(QString::fromLatin1("entry-templates/"));
+ for(QStringList::ConstIterator it = files.begin(); it != files.end(); ++it) {
+ if((*it).endsWith(QChar('/'))) {
+ // ok to not delete all directories
+ QDir().rmdir(path + *it);
+ } else {
+ success = success && QFile(path + *it).remove();
+ if(!success) {
+ myDebug() << "Manager::removeTemplate() - failed to remove " << (path+*it) << endl;
+ }
+ }
+ }
+
+ // remove config entries even if unsuccessful
+ fileGroup.deleteEntry(name_);
+ KConfigGroup statusGroup(KGlobal::config(), "KNewStuffStatus");
+ QString entryName = statusGroup.readEntry(name_);
+ statusGroup.deleteEntry(name_);
+ statusGroup.deleteEntry(entryName);
+
+ return success;
+}
+
+bool Manager::installScript(const KURL& url_) {
+ FileHandler::FileRef* ref = FileHandler::fileRef(url_);
+
+ KTar archive(ref->fileName());
+ if(!archive.open(IO_ReadOnly)) {
+ myDebug() << "Manager::installScript() - can't open tar file" << endl;
+ return false;
+ }
+
+ const KArchiveDirectory* archiveDir = archive.directory();
+
+ QString exeFile = findEXE(archiveDir);
+ if(exeFile.isEmpty()) {
+ myDebug() << "Manager::installScript() - no exe file found" << endl;
+ return false;
+ }
+
+ QFileInfo exeInfo(exeFile);
+ DataSourceInfo* info = new DataSourceInfo();
+
+ QString copyTarget = Tellico::saveLocation(QString::fromLatin1("data-sources/"));
+ QString scriptFolder;
+
+ // package could have a top-level directory or not
+ // it should have a directory...
+ const KArchiveEntry* firstEntry = archiveDir->entry(archiveDir->entries().first());
+ if(firstEntry->isFile()) {
+ copyTarget += exeInfo.baseName(true) + '/';
+ if(QFile::exists(copyTarget)) {
+ KURL u;
+ u.setPath(scriptFolder);
+ myLog() << "Manager::installScript() - deleting " << scriptFolder << endl;
+ KIO::NetAccess::del(u, Kernel::self()->widget());
+ info->isUpdate = true;
+ }
+ scriptFolder = copyTarget;
+ } else {
+ scriptFolder = copyTarget + firstEntry->name() + '/';
+ if(QFile::exists(copyTarget + exeFile)) {
+ info->isUpdate = true;
+ }
+ }
+
+ // overwrites stuff there
+ archiveDir->copyTo(copyTarget);
+
+ info->specFile = scriptFolder + exeInfo.baseName(true) + ".spec";
+ if(!QFile::exists(info->specFile)) {
+ myDebug() << "Manager::installScript() - no spec file for script! " << info->specFile << endl;
+ delete info;
+ return false;
+ }
+ info->sourceName = exeFile;
+ info->sourceExec = copyTarget + exeFile;
+ m_infoList.append(info);
+
+ KURL dest;
+ dest.setPath(info->sourceExec);
+ KFileItem item(KFileItem::Unknown, KFileItem::Unknown, dest, true);
+ ::chmod(QFile::encodeName(dest.path()), item.permissions() | S_IXUSR);
+
+ {
+ KConfig spec(info->specFile, false, false);
+ // update name
+ info->sourceName = spec.readEntry("Name", info->sourceName);
+ spec.writePathEntry("ExecPath", info->sourceExec);
+ spec.writeEntry("NewStuffName", info->sourceName);
+ spec.writeEntry("DeleteOnRemove", true);
+ }
+
+ {
+ KConfigGroup config(KGlobal::config(), "KNewStuffFiles");
+ config.writeEntry(info->sourceName, archiveFiles(archiveDir));
+ m_urlNameMap.insert(url_, info->sourceName);
+ }
+
+
+// myDebug() << "Manager::installScript() - exeFile = " << exeFile << endl;
+// myDebug() << "Manager::installScript() - sourceExec = " << info->sourceExec << endl;
+// myDebug() << "Manager::installScript() - sourceName = " << info->sourceName << endl;
+// myDebug() << "Manager::installScript() - specFile = " << info->specFile << endl;
+
+ delete ref;
+ return true;
+}
+
+bool Manager::removeScript(const QString& name_) {
+ KConfigGroup fileGroup(KGlobal::config(), "KNewStuffFiles");
+ QStringList files = fileGroup.readListEntry(name_);
+
+ bool success = true;
+ QString path = Tellico::saveLocation(QString::fromLatin1("data-sources/"));
+ for(QStringList::ConstIterator it = files.begin(); it != files.end(); ++it) {
+ if((*it).endsWith(QChar('/'))) {
+ // ok to not delete all directories
+ QDir().rmdir(path + *it);
+ } else {
+ success = success && QFile(path + *it).remove();
+ if(!success) {
+ myDebug() << "Manager::removeScript() - failed to remove " << (path+*it) << endl;
+ }
+ }
+ }
+
+ // remove config entries even if unsuccessful
+ fileGroup.deleteEntry(name_);
+ KConfigGroup statusGroup(KGlobal::config(), "KNewStuffStatus");
+ QString entryName = statusGroup.readEntry(name_);
+ statusGroup.deleteEntry(name_);
+ statusGroup.deleteEntry(entryName);
+
+ return success;
+}
+
+Tellico::NewStuff::InstallStatus Manager::installStatus(KNS::Entry* entry_) {
+ KConfigGroup config(KGlobal::config(), "KNewStuffStatus");
+ QString datestring = config.readEntry(entry_->name());
+ if(datestring.isEmpty()) {
+ return NotInstalled;
+ }
+
+ QDate date = QDate::fromString(datestring, Qt::ISODate);
+ if(!date.isValid()) {
+ return NotInstalled;
+ }
+ if(date < entry_->releaseDate()) {
+ return OldVersion;
+ }
+
+ // also check that executable files exists
+ KConfigGroup fileGroup(KGlobal::config(), "KNewStuffFiles");
+ QStringList files = fileGroup.readListEntry(entry_->name());
+ QString path = Tellico::saveLocation(QString::fromLatin1("data-sources/"));
+ for(QStringList::ConstIterator it = files.begin(); it != files.end(); ++it) {
+ if(!QFile::exists(path + *it)) {
+ return NotInstalled;
+ }
+ }
+ return Current;
+}
+
+QStringList Manager::archiveFiles(const KArchiveDirectory* dir_, const QString& path_) {
+ QStringList list;
+
+ const QStringList dirEntries = dir_->entries();
+ for(QStringList::ConstIterator it = dirEntries.begin(); it != dirEntries.end(); ++it) {
+ const QString& entry = *it;
+ const KArchiveEntry* curEntry = dir_->entry(entry);
+ if(curEntry->isFile()) {
+ list += path_ + entry;
+ } else if(curEntry->isDirectory()) {
+ list += archiveFiles(static_cast<const KArchiveDirectory*>(curEntry), path_ + entry + '/');
+ // add directory AFTER contents, since we delete from the top down later
+ list += path_ + entry + '/';
+ }
+ }
+
+ return list;
+}
+
+// don't recurse, the .xsl must be in top directory
+QString Manager::findXSL(const KArchiveDirectory* dir_) {
+ const QStringList entries = dir_->entries();
+ for(QStringList::ConstIterator it = entries.begin(); it != entries.end(); ++it) {
+ const QString& entry = *it;
+ if(entry.endsWith(QString::fromLatin1(".xsl"))) {
+ return entry;
+ }
+ }
+ return QString();
+}
+
+QString Manager::findEXE(const KArchiveDirectory* dir_) {
+ QPtrStack<KArchiveDirectory> dirStack;
+ QValueStack<QString> dirNameStack;
+
+ dirStack.push(dir_);
+ dirNameStack.push(QString());
+
+ do {
+ const QString dirName = dirNameStack.pop();
+ const KArchiveDirectory* curDir = dirStack.pop();
+ const QStringList entries = curDir->entries();
+ for(QStringList::ConstIterator it = entries.begin(); it != entries.end(); ++it) {
+ const QString& entry = *it;
+ const KArchiveEntry* archEntry = curDir->entry(entry);
+
+ if(archEntry->isFile() && (archEntry->permissions() & S_IEXEC)) {
+ return dirName + entry;
+ } else if(archEntry->isDirectory()) {
+ dirStack.push(static_cast<const KArchiveDirectory*>(archEntry));
+ dirNameStack.push(dirName + entry + '/');
+ }
+ }
+ } while(!dirStack.isEmpty());
+
+ return QString();
+}
+
+void Manager::install(DataType type_, KNS::Entry* entry_) {
+ if(m_tempFile) {
+ delete m_tempFile;
+ }
+ m_tempFile = new KTempFile();
+ m_tempFile->setAutoDelete(true);
+
+ KURL destination;
+ destination.setPath(m_tempFile->name());
+ KIO::FileCopyJob* job = KIO::file_copy(entry_->payload(), destination, -1, true);
+ connect(job, SIGNAL(result(KIO::Job*)), SLOT(slotDownloadJobResult(KIO::Job*)));
+ m_jobMap.insert(job, EntryPair(entry_, type_));
+}
+
+void Manager::slotDownloadJobResult(KIO::Job* job_) {
+ KIO::FileCopyJob* job = static_cast<KIO::FileCopyJob*>(job_);
+ if(job->error()) {
+ GUI::CursorSaver cs(Qt::arrowCursor);
+ delete m_tempFile;
+ m_tempFile = 0;
+ job->showErrorDialog(Kernel::self()->widget());
+ emit signalInstalled(0); // still need to notify dialog that install failed
+ return;
+ }
+
+ KNS::Entry* entry = m_jobMap[job_].first;
+ DataType type = m_jobMap[job_].second;
+
+ bool deleteTempFile = true;
+ if(type == EntryTemplate) {
+ installTemplate(job->destURL(), entry->name());
+ } else {
+#if KDE_IS_VERSION(3,3,90)
+ // needed so the GPG signature can be checked
+ NewScript* newScript = new NewScript(this, Kernel::self()->widget());
+ connect(newScript, SIGNAL(installFinished()), this, SLOT(slotInstallFinished()));
+ // need to delete temp file if install was not a success
+ // if it was a success, it gets deleted later
+ deleteTempFile = !newScript->install(job->destURL().path());
+ m_scriptEntryMap.insert(newScript, entry);
+#endif
+ // if failed, emit empty signal now
+ if(deleteTempFile) {
+ emit signalInstalled(0);
+ }
+ }
+ if(deleteTempFile) {
+ delete m_tempFile;
+ m_tempFile = 0;
+ }
+}
+
+void Manager::slotInstallFinished() {
+ const NewScript* newScript = ::qt_cast<const NewScript*>(sender());
+ if(newScript && newScript->successfulInstall()) {
+ const QString name = m_urlNameMap[newScript->url()];
+ KNS::Entry* entry = m_scriptEntryMap[newScript];
+ KConfigGroup config(KGlobal::config(), "KNewStuffStatus");
+ // have to keep a config entry that maps the name of the file to the name
+ // of the newstuff entry, so we can track which entries are installed
+ // name and entry-name() are probably the same for scripts, but not a problem
+ config.writeEntry(name, entry->name());
+ config.writeEntry(entry->name(), entry->releaseDate().toString(Qt::ISODate));
+ config.sync();
+ emit signalInstalled(entry);
+ } else {
+ emit signalInstalled(0);
+ kdWarning() << "Manager::slotInstallFinished() - Failed to install" << endl;
+ }
+ delete m_tempFile;
+ m_tempFile = 0;
+}
+
+bool Manager::checkCommonFile() {
+ // look for a file that gets installed to know the installation directory
+ // need to check timestamps
+ QString userDataDir = Tellico::saveLocation(QString::null);
+ QString userCommonFile = userDataDir + '/' + QString::fromLatin1("tellico-common.xsl");
+ if(QFile::exists(userCommonFile)) {
+ // check timestamps
+ // pics/tellico.png is not likely to be in a user directory
+ QString installDir = KGlobal::dirs()->findResourceDir("appdata", QString::fromLatin1("pics/tellico.png"));
+ QString installCommonFile = installDir + '/' + QString::fromLatin1("tellico-common.xsl");
+#ifndef NDEBUG
+ if(userCommonFile == installCommonFile) {
+ kdWarning() << "Manager::checkCommonFile() - install location is same as user location" << endl;
+ }
+#endif
+ QFileInfo installInfo(installCommonFile);
+ QFileInfo userInfo(userCommonFile);
+ if(installInfo.lastModified() > userInfo.lastModified()) {
+ // the installed file has been modified more recently than the user's
+ // remove user's tellico-common.xsl file so it gets copied again
+ myLog() << "Manager::checkCommonFile() - removing " << userCommonFile << endl;
+ myLog() << "Manager::checkCommonFile() - copying " << installCommonFile << endl;
+ QFile::remove(userCommonFile);
+ } else {
+ return true;
+ }
+ }
+ KURL src, dest;
+ src.setPath(KGlobal::dirs()->findResource("appdata", QString::fromLatin1("tellico-common.xsl")));
+ dest.setPath(userCommonFile);
+ return KIO::NetAccess::file_copy(src, dest);
+}
+
+#include "manager.moc"
diff --git a/src/newstuff/manager.h b/src/newstuff/manager.h
new file mode 100644
index 0000000..4102be3
--- /dev/null
+++ b/src/newstuff/manager.h
@@ -0,0 +1,101 @@
+/***************************************************************************
+ copyright : (C) 2006 by Robby Stephenson
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#ifndef TELLICO_NEWSTUFF_MANAGER_H
+#define TELLICO_NEWSTUFF_MANAGER_H
+
+class KArchiveDirectory;
+class KURL;
+class KTempFile;
+
+#include <qobject.h>
+#include <qptrlist.h>
+
+class QStringList;
+
+namespace KNS {
+ class Entry;
+}
+namespace KIO {
+ class Job;
+}
+
+namespace Tellico {
+ namespace NewStuff {
+
+class NewScript;
+
+enum DataType {
+ EntryTemplate,
+ DataScript
+};
+
+enum InstallStatus {
+ NotInstalled,
+ OldVersion,
+ Current
+};
+
+struct DataSourceInfo {
+ DataSourceInfo() : isUpdate(false) {}
+ QString specFile; // full path of .spec file
+ QString sourceName;
+ QString sourceExec; // full executable path of script
+ bool isUpdate : 1; // whether the info is for an updated source
+};
+
+class Manager : public QObject {
+Q_OBJECT
+
+public:
+ Manager(QObject* parent);
+ ~Manager();
+
+ void install(DataType type, KNS::Entry* entry);
+ QPtrList<DataSourceInfo> dataSourceInfo() const { return m_infoList; }
+
+ bool installTemplate(const KURL& url, const QString& entryName = QString::null);
+ bool removeTemplate(const QString& name);
+
+ bool installScript(const KURL& url);
+ bool removeScript(const QString& name);
+
+ static InstallStatus installStatus(KNS::Entry* entry);
+ static bool checkCommonFile();
+
+signals:
+ void signalInstalled(KNS::Entry* entry);
+
+private slots:
+ void slotDownloadJobResult(KIO::Job* job);
+ void slotInstallFinished();
+
+private:
+ static QStringList archiveFiles(const KArchiveDirectory* dir,
+ const QString& path = QString::null);
+
+ static QString findXSL(const KArchiveDirectory* dir);
+ static QString findEXE(const KArchiveDirectory* dir);
+
+ typedef QPair<KNS::Entry*, DataType> EntryPair;
+ QMap<KIO::Job*, EntryPair> m_jobMap;
+ QMap<KURL, QString> m_urlNameMap;
+ QMap<const NewScript*, KNS::Entry*> m_scriptEntryMap;
+ QPtrList<DataSourceInfo> m_infoList;
+ KTempFile* m_tempFile;
+};
+
+ }
+}
+
+#endif
diff --git a/src/newstuff/newscript.cpp b/src/newstuff/newscript.cpp
new file mode 100644
index 0000000..045f881
--- /dev/null
+++ b/src/newstuff/newscript.cpp
@@ -0,0 +1,48 @@
+/***************************************************************************
+ copyright : (C) 2006 by Robby Stephenson
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#include "newscript.h"
+#include "manager.h"
+
+#include <kurl.h>
+
+#include <qwidget.h>
+
+using Tellico::NewStuff::NewScript;
+
+NewScript::NewScript(Manager* manager_, QWidget* parentWidget_)
+#if KDE_IS_VERSION(3,3,90)
+ : KNewStuffSecure(QString::fromLatin1("tellico/data-source"), parentWidget_)
+#else
+ : QObject(parentWidget_)
+#endif
+ , m_manager(manager_), m_success(false) {
+}
+
+void NewScript::installResource() {
+ // m_tarName is protected in superclass
+ KURL u;
+ u.setPath(m_tarName);
+ m_success = m_manager->installScript(u);
+ m_url = u;
+}
+
+#if KDE_IS_VERSION(3,3,90)
+#include <knewstuff/knewstuffsecure.h>
+#define SUPERCLASS KNewStuffSecure
+#else
+#define SUPERCLASS QObject
+#endif
+
+#include "newscript.moc"
+#undef SUPERCLASS
diff --git a/src/newstuff/newscript.h b/src/newstuff/newscript.h
new file mode 100644
index 0000000..8bc3154
--- /dev/null
+++ b/src/newstuff/newscript.h
@@ -0,0 +1,60 @@
+/***************************************************************************
+ copyright : (C) 2006 by Robby Stephenson
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#ifndef TELLICO_NEWSTUFF_NEWSCRIPT_H
+#define TELLICO_NEWSTUFF_NEWSCRIPT_H
+
+#include <kdeversion.h>
+#include <kurl.h>
+
+#if KDE_IS_VERSION(3,3,90)
+#include <knewstuff/knewstuffsecure.h>
+#define SUPERCLASS KNewStuffSecure
+#else
+#define SUPERCLASS QObject
+#endif
+
+#include <qobject.h>
+
+namespace Tellico {
+ namespace NewStuff {
+
+class Manager;
+
+class NewScript : public SUPERCLASS {
+Q_OBJECT
+
+public:
+ NewScript(Manager* manager, QWidget* parentWidget = 0);
+ virtual ~NewScript() {}
+
+ const KURL& url() const { return m_url; }
+ bool successfulInstall() const { return m_success; }
+
+private:
+ virtual void installResource();
+
+ Manager* m_manager;
+#if !KDE_IS_VERSION(3,3,90)
+ // KNewStuffSecure has a protected variable
+ QString m_tarName;
+#endif
+ KURL m_url;
+ bool m_success : 1;
+};
+
+ }
+}
+
+#undef SUPERCLASS
+#endif
diff --git a/src/newstuff/providerloader.cpp b/src/newstuff/providerloader.cpp
new file mode 100644
index 0000000..b3f95ae
--- /dev/null
+++ b/src/newstuff/providerloader.cpp
@@ -0,0 +1,102 @@
+/***************************************************************************
+ copyright : (C) 2006 by Robby Stephenson
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+// this class is largely copied from kdelibs/knewstuff/provider.cpp
+// which is Copyright (c) 2002 Cornelius Schumacher <[email protected]>
+// and licensed under GPL v2, just like Tellico
+
+#include "providerloader.h"
+#include "../tellico_debug.h"
+#include "../latin1literal.h"
+
+#include <kio/job.h>
+#include <knewstuff/provider.h>
+#include <kglobal.h>
+#include <kconfig.h>
+#include <kmessagebox.h>
+#include <klocale.h>
+
+#include <qdom.h>
+
+using Tellico::NewStuff::ProviderLoader;
+
+ProviderLoader::ProviderLoader( QWidget *parentWidget ) :
+ mParentWidget( parentWidget ), mTryAlt(true)
+{
+ mProviders.setAutoDelete( true );
+}
+
+void ProviderLoader::load( const QString &type, const QString &providersList )
+{
+ mProviders.clear();
+ mJobData.truncate(0);
+
+// myLog() << "ProviderLoader::load(): providersList: " << providersList << endl;
+
+ KIO::TransferJob *job = KIO::get( KURL( providersList ), false, false );
+ connect( job, SIGNAL( result( KIO::Job * ) ),
+ SLOT( slotJobResult( KIO::Job * ) ) );
+ connect( job, SIGNAL( data( KIO::Job *, const QByteArray & ) ),
+ SLOT( slotJobData( KIO::Job *, const QByteArray & ) ) );
+ connect( job, SIGNAL( percent (KIO::Job *, unsigned long) ),
+ SIGNAL( percent (KIO::Job *, unsigned long) ) );
+
+// job->dumpObjectInfo();
+}
+
+void ProviderLoader::slotJobData( KIO::Job *, const QByteArray &data )
+{
+ if ( data.size() == 0 ) return;
+ QCString str( data, data.size() + 1 );
+ mJobData.append( QString::fromUtf8( str ) );
+}
+
+void ProviderLoader::slotJobResult( KIO::Job *job )
+{
+ if ( job->error() ) {
+ job->showErrorDialog( mParentWidget );
+ if(mTryAlt && !mAltProvider.isEmpty()) {
+ mTryAlt = false;
+ load(QString(), mAltProvider);
+ } else {
+ emit error();
+ }
+ return;
+ }
+
+ QDomDocument doc;
+ if ( !doc.setContent( mJobData ) ) {
+ myDebug() << "ProviderLoader::slotJobResult() - error parsing providers list." << endl;
+ if(mTryAlt && !mAltProvider.isEmpty()) {
+ mTryAlt = false;
+ load(QString(), mAltProvider);
+ } else {
+ emit error();
+ }
+ return;
+ }
+
+ QDomElement providers = doc.documentElement();
+ QDomNode n;
+ for ( n = providers.firstChild(); !n.isNull(); n = n.nextSibling() ) {
+ QDomElement p = n.toElement();
+
+ if ( p.tagName() == Latin1Literal("provider") ) {
+ mProviders.append( new KNS::Provider( p ) );
+ }
+ }
+
+ emit providersLoaded( &mProviders );
+}
+
+#include "providerloader.moc"
diff --git a/src/newstuff/providerloader.h b/src/newstuff/providerloader.h
new file mode 100644
index 0000000..3d2968c
--- /dev/null
+++ b/src/newstuff/providerloader.h
@@ -0,0 +1,84 @@
+/***************************************************************************
+ copyright : (C) 2006 by Robby Stephenson
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+// this class is largely copied from kdelibs/knewstuff/provider.h
+// which is Copyright (c) 2002 Cornelius Schumacher <[email protected]>
+// and licensed under GPL v2, just like Tellico
+//
+// I want progress info for the download, and this was the
+// easiest way to get it
+
+#ifndef TELLICO_NEWSTUFF_PROVIDERLOADER_H
+#define TELLICO_NEWSTUFF_PROVIDERLOADER_H
+
+#include <qobject.h>
+#include <qptrlist.h>
+
+namespace KIO {
+ class Job;
+}
+namespace KNS {
+ class Provider;
+}
+
+namespace Tellico {
+ namespace NewStuff {
+
+class ProviderLoader : public QObject {
+Q_OBJECT
+public:
+ /**
+ * Constructor.
+ *
+ * @param parentWidget the parent widget
+ */
+ ProviderLoader( QWidget *parentWidget );
+
+ /**
+ * Starts asynchronously loading the list of providers of the
+ * specified type.
+ *
+ * @param type data type such as 'kdesktop/wallpaper'.
+ * @param providerList the URl to the list of providers; if empty
+ * we first try the ProvidersUrl from KGlobal::config, then we
+ * fall back to a hardcoded value.
+ */
+ void load( const QString &type, const QString &providerList = QString::null );
+
+ void setAlternativeProvider(const QString& alt) { mAltProvider = alt; }
+
+ signals:
+ /**
+ * Indicates that the list of providers has been successfully loaded.
+ */
+ void providersLoaded( QPtrList<KNS::Provider>* );
+ void percent(KIO::Job *job, unsigned long percent);
+ void error();
+
+ protected slots:
+ void slotJobData( KIO::Job *, const QByteArray & );
+ void slotJobResult( KIO::Job * );
+
+ private:
+ QWidget *mParentWidget;
+
+ QString mJobData;
+
+ QPtrList<KNS::Provider> mProviders;
+ QString mAltProvider;
+ bool mTryAlt;
+};
+
+ }
+}
+#endif