You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tellico/src/newstuff/dialog.cpp

478 lines
16 KiB

/***************************************************************************
copyright : (C) 2006 by Robby Stephenson
email : robby@periapsis.org
***************************************************************************/
/***************************************************************************
* *
* 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 <tdeconfig.h>
#include <kiconloader.h>
#include <kstatusbar.h>
#include <tdeio/job.h>
#include <tdeio/netaccess.h>
#include <tdeaccelmanager.h>
#include <knewstuff/entry.h>
#include <knewstuff/provider.h>
#include <ktempfile.h>
#include <tqlabel.h>
#include <tqtextedit.h>
#include <tqlayout.h>
#include <tqwhatsthis.h>
#include <tqregexp.h>
#include <tqvbox.h>
#include <tqimage.h>
#include <tqtimer.h>
#include <tqprogressbar.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) TQString()
#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(TQString::fromLatin1("ok")));
} else if(m_status == OldVersion) {
setPixmap(0, SmallIcon(TQString::fromLatin1("reload")));
}
}
TQString key(int col, bool asc) const {
if(col == 2 || col == 3) {
TQString s;
s.sprintf("%08d", text(col).toInt());
return s;
} else if(col == 4) {
TQString s;
TQDate date = TDEGlobal::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_, TQWidget* parent_)
: KDialogBase(KDialogBase::Plain, i18n("Get Hot New Stuff"), 0, (KDialogBase::ButtonCode)0, parent_)
, m_manager(new Manager(TQT_TQOBJECT(this)))
, m_type(type_)
, m_timer(new TQTimer(this))
, m_cursorSaver(new GUI::CursorSaver())
, m_tempPreviewImage(0)
, m_lastPreviewItem(0) {
m_lang = TDEGlobal::locale()->language();
TQFrame* frame = plainPage();
TQBoxLayout* boxLayout = new TQVBoxLayout(frame, 0, KDialog::spacingHint());
m_split = new TQSplitter(Qt::Vertical, frame);
boxLayout->addWidget(m_split);
m_listView = new GUI::ListView(m_split);
m_listView->setAllColumnsShowFocus(true);
m_listView->setSelectionMode(TQListView::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(TQListView::AllColumns);
connect(m_listView, TQT_SIGNAL(clicked(TQListViewItem*)), TQT_SLOT(slotSelected(TQListViewItem*)));
TQWhatsThis::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"));
TQWidget* widget = new TQWidget(m_split);
TQBoxLayout* boxLayout2 = new TQVBoxLayout(widget, 0, KDialog::spacingHint());
m_iconLabel = new TQLabel(widget);
m_iconLabel->setAlignment(TQt::AlignTop | TQt::AlignLeft);
m_iconLabel->setMargin(0);
m_nameLabel = new TQLabel(widget);
TQFont font = m_nameLabel->font();
font.setBold(true);
font.setItalic(true);
m_nameLabel->setFont(font);
TQWhatsThis::add(m_nameLabel, i18n("The name and license of the selected item"));
m_infoLabel = new TQLabel(widget);
TQWhatsThis::add(m_infoLabel, i18n("The author of the selected item"));
m_install = new KPushButton(i18n("Install"), widget);
m_install->setIconSet(SmallIconSet(TQString::fromLatin1("knewstuff")));
m_install->setEnabled(false);
connect(m_install, TQT_SIGNAL(clicked()), TQT_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(TQString::fromLatin1("knewstuff"))));
maxWidth = TQMAX(maxWidth, m_install->sizeHint().width());
maxHeight = TQMAX(maxHeight, m_install->sizeHint().height());
m_install->setMinimumWidth(maxWidth);
m_install->setMinimumHeight(maxHeight);
TQPixmap pix;
if(m_type == EntryTemplate) {
pix = DesktopIcon(TQString::fromLatin1("looknfeel"), KIcon::SizeLarge);
TQWhatsThis::add(m_install, i18n("Download and install the selected template."));
} else {
pix = UserIcon(TQString::fromLatin1("script"));
TQWhatsThis::add(m_install, i18n("Download and install the selected script. Some scripts "
"may need to be configured after being installed."));
}
m_iconLabel->setPixmap(pix);
TQBoxLayout* boxLayout3 = new TQHBoxLayout(boxLayout2);
TQBoxLayout* boxLayout4 = new TQVBoxLayout(boxLayout3);
boxLayout4->addWidget(m_iconLabel);
boxLayout4->addStretch(10);
boxLayout3->addSpacing(4);
TQBoxLayout* boxLayout5 = new TQVBoxLayout(boxLayout3);
boxLayout5->addWidget(m_nameLabel);
boxLayout5->addWidget(m_infoLabel);
boxLayout5->addStretch(10);
boxLayout3->addStretch(10);
TQBoxLayout* boxLayout6 = new TQVBoxLayout(boxLayout3);
boxLayout6->addWidget(m_install);
boxLayout6->addStretch(10);
m_descLabel = new TQTextEdit(widget);
m_descLabel->setReadOnly(true);
m_descLabel->setTextFormat(TQt::RichText);
m_descLabel->setPaper(colorGroup().background());
m_descLabel->setMinimumHeight(5 * fontMetrics().height());
boxLayout2->addWidget(m_descLabel, 10);
TQWhatsThis::add(m_descLabel, i18n("A description of the selected item is shown here."));
TQHBox* box = new TQHBox(frame, "statusbox");
boxLayout->addWidget(box);
box->setSpacing(KDialog::spacingHint());
m_statusBar = new KStatusBar(box, "statusbar");
m_statusBar->insertItem(TQString(), PROGRESS_STATUS_ID, 1, false);
m_statusBar->setItemAlignment(PROGRESS_STATUS_ID, AlignLeft | AlignVCenter);
m_progress = new TQProgressBar(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, TQT_SIGNAL(clicked()), TQT_SLOT(slotClose()));
closeButton->setFocus();
connect(m_timer, TQT_SIGNAL(timeout()), TQT_SLOT(slotMoveProgress()));
setMinimumWidth(TQMAX(minimumWidth(), NEW_STUFF_MIN_WIDTH));
setMinimumHeight(TQMAX(minimumHeight(), NEW_STUFF_MIN_HEIGHT));
resize(configDialogSize(TQString::fromLatin1("NewStuff Dialog Options")));
TDEConfigGroup dialogConfig(TDEGlobal::config(), "NewStuff Dialog Options");
TQValueList<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, TQT_SIGNAL(providersLoaded(TQPtrList<KNS::Provider>*)), TQT_SLOT(slotProviders(TQPtrList<KNS::Provider>*)));
connect(loader, TQT_SIGNAL(percent(TDEIO::Job*, unsigned long)), TQT_SLOT(slotShowPercent(TDEIO::Job*, unsigned long)));
connect(loader, TQT_SIGNAL(error()), TQT_SLOT(slotProviderError()));
TDEConfigGroup config(TDEGlobal::config(), "KNewStuff");
TQString prov = config.readEntry("ProvidersUrl");
if(prov.isEmpty()) {
if(m_type == EntryTemplate) {
prov = TQString::fromLatin1("http://periapsis.org/tellico/newstuff/tellicotemplates-providers.php");
TQString alt = TQString::fromLatin1("http://download.kde.org/tdehotnewstuff/tellicotemplates-providers.xml");
loader->setAlternativeProvider(alt);
} else {
prov = TQString::fromLatin1("http://periapsis.org/tellico/newstuff/tellicoscripts-providers.php");
}
}
if(m_type == EntryTemplate) {
m_typeName = TQString::fromLatin1("tellico/entry-template");
} else {
m_typeName = TQString::fromLatin1("tellico/data-source");
}
loader->load(m_typeName, prov);
TDEAcceleratorManager::manage(this);
}
Dialog::~Dialog() {
delete m_cursorSaver;
m_cursorSaver = 0;
saveDialogSize(TQString::fromLatin1("NewStuff Dialog Options"));
TDEConfigGroup config(TDEGlobal::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(TQString());
delete m_cursorSaver;
m_cursorSaver = 0;
}
}
void Dialog::slotProviders(TQPtrList<KNS::Provider>* list_) {
for(KNS::Provider* prov = list_->first(); prov; prov = list_->next()) {
TDEIO::TransferJob* job = TDEIO::get(prov->downloadUrl());
m_jobs[job] = prov;
connect(job, TQT_SIGNAL(data(TDEIO::Job*, const TQByteArray&)),
TQT_SLOT(slotData(TDEIO::Job*, const TQByteArray&)));
connect(job, TQT_SIGNAL(result(TDEIO::Job*)), TQT_SLOT(slotResult(TDEIO::Job*)));
connect(job, TQT_SIGNAL(percent(TDEIO::Job*, unsigned long)),
TQT_SLOT(slotShowPercent(TDEIO::Job*, unsigned long)));
}
}
void Dialog::slotData(TDEIO::Job* job_, const TQByteArray& data_) {
TQDataStream stream(m_data[job_], IO_WriteOnly | IO_Append);
stream.writeRawBytes(data_.data(), data_.size());
}
void Dialog::slotResult(TDEIO::Job* job_) {
// myDebug() << "NewStuff::Dialog::slotResult()" << endl;
TQDomDocument 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;
}
TQDomElement knewstuff = dom.documentElement();
for(TQDomNode pn = knewstuff.firstChild(); !pn.isNull(); pn = pn.nextSibling()) {
TQDomElement 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, TQString::number(entry_->rating()));
item->setText(3, TQString::number(entry_->downloads()));
item->setText(4, TDEGlobal::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(TQListViewItem* 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());
TDEIO::FileCopyJob* job = TDEIO::file_copy(preview, dest, -1, true, false, false);
connect(job, TQT_SIGNAL(result(TDEIO::Job*)), TQT_SLOT(slotPreviewResult(TDEIO::Job*)));
connect(job, TQT_SIGNAL(percent(TDEIO::Job*, unsigned long)),
TQT_SLOT(slotShowPercent(TDEIO::Job*, unsigned long)));
m_lastPreviewItem = item_;
}
TQPixmap pix = m_type == EntryTemplate
? DesktopIcon(TQString::fromLatin1("looknfeel"), KIcon::SizeLarge)
: UserIcon(TQString::fromLatin1("script"));
m_iconLabel->setPixmap(pix);
TQString license = entry->license();
if(!license.isEmpty()) {
license.prepend('(').append(')');
}
TQString name = TQString::fromLatin1("%1 %2").arg(ENTRYNAME(entry)).arg(license);
TQFont font = m_nameLabel->font();
font.setBold(true);
font.setItalic(false);
m_nameLabel->setFont(font);
m_nameLabel->setText(name);
m_infoLabel->setText(entry->author());
TQString desc = entry->summary(m_lang);
desc.replace(TQRegExp(TQString::fromLatin1("\\n")), TQString::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() {
TQListViewItem* 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, TQT_SIGNAL(signalInstalled(KNS::Entry*)), TQT_SLOT(slotDoneInstall(KNS::Entry*)));
m_manager->install(m_type, entry);
delete m_cursorSaver;
m_cursorSaver = 0;
}
void Dialog::slotDoneInstall(KNS::Entry* entry_) {
TQMap<TQListViewItem*, 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 TQString& text_) {
m_statusBar->changeItem(TQChar(' ') + text_, PROGRESS_STATUS_ID);
}
void Dialog::slotShowPercent(TDEIO::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(TDEIO::Job* job_) {
TDEIO::FileCopyJob* job = static_cast<TDEIO::FileCopyJob*>(job_);
if(job->error()) {
return;
}
TQString tmpFile = job->destURL().path(); // might be different than m_tempPreviewImage->name()
TQPixmap pix(tmpFile);
if(!pix.isNull()) {
if(pix.width() > 64 || pix.height() > 64) {
pix.convertFromImage(pix.convertToImage().smoothScale(64, 64, TQ_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"