/*************************************************************************** copyright : (C) 2006 by Robby Stephenson email : robby@periapsis.org Copyright (c) 2014 Timothy Pearson ***************************************************************************/ /*************************************************************************** * * * 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 "../gui/listview.h" #include "../latin1literal.h" #include "../tellico_utils.h" #include "../tellico_debug.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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 #define OPENDESKTOP_REDIRECT_URL "opendesktop.org/content/download.php?content=" #define OPENDESKTOP_REDIRECT_TEXT "If the download does not start in 3 seconds: 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"), TDEIcon::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 splitList = dialogConfig.readIntListEntry("Splitter Sizes"); if(!splitList.empty()) { m_split->setSizes(splitList); } setStatus(i18n("Downloading information...")); KNS::ProviderLoader* loader = new KNS::ProviderLoader(this); connect(loader, TQT_SIGNAL(providersLoaded(Provider::List*)), this, TQT_SLOT(slotProviders(Provider::List*))); connect(loader, TQT_SIGNAL(percent(TDEIO::Job*, unsigned long)), this, TQT_SLOT(slotShowPercent(TDEIO::Job*, unsigned long))); connect(loader, TQT_SIGNAL(error()), this, TQT_SLOT(slotProviderError())); TDEConfigGroup config(TDEGlobal::config(), "TDENewStuff"); TQString prov = config.readEntry("ProvidersUrl"); if(prov.isEmpty()) { prov = TQString::fromLatin1("https://www.trinitydesktop.org/ocs/providers.xml"); } if(m_type == EntryTemplate) { m_typeName = TQString::fromLatin1("tellico template"); } else { m_typeName = TQString::fromLatin1("tellico script"); } 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(Provider::List* 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 tdenewstuff = dom.documentElement(); TQDomElement content; for(TQDomNode pn = tdenewstuff.firstChild(); !pn.isNull(); pn = pn.nextSibling()) { TQDomElement stuff = pn.toElement(); if(stuff.tagName() == "data") { content = pn.toElement(); } } for(TQDomNode pn = content.firstChild(); !pn.isNull(); pn = pn.nextSibling()) { TQDomElement stuff = pn.toElement(); if(stuff.isNull()) { continue; } if(stuff.tagName() == Latin1Literal("content")) { 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"), TDEIcon::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("
")); m_descLabel->setText(desc); InstallStatus installed = static_cast(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*))); mJobEntry = entry; // OpenDesktop.org broke the basic functionality of TDEHNS by forcing // downloads though an advertising display page. This in turn forces // the user to download and manually install the wallpaper, which // is relatively complex and negates much of the benefit of TDEHNS. // Therefore, if the download URL contains OPENDESKTOP_REDIRECT_URL // then download the raw HTML page and extract the real download URL for use below. // In the future we may want to figure out how to display unobtrusive ads // during the download process, but OpenDesktop.org would need to add back // in the direct download ability for this to even be considered. if (entry->payload().url().contains(OPENDESKTOP_REDIRECT_URL)) { TDEIO::TransferJob *job = TDEIO::get( KURL( entry->payload() ), false, false ); connect( job, TQT_SIGNAL( result( TDEIO::Job * ) ), TQT_SLOT( slotJobResult( TDEIO::Job * ) ) ); connect( job, TQT_SIGNAL( data( TDEIO::Job *, const TQByteArray & ) ), TQT_SLOT( slotJobData( TDEIO::Job *, const TQByteArray & ) ) ); } else { slotInstallPhase2(); } } void Dialog::slotInstallPhase2() { m_manager->install(m_type, mJobEntry); delete m_cursorSaver; m_cursorSaver = 0; } void Dialog::slotJobData( TDEIO::Job *, const TQByteArray &data ) { kdDebug() << "DownloadDialog::slotJobData()" << endl; if ( data.size() == 0 ) return; TQCString str( data, data.size() + 1 ); mJobData.append( TQString::fromUtf8( str ) ); } void Dialog::slotJobResult( TDEIO::Job *job ) { if ( job->error() ) { job->showErrorDialog( this ); slotInstallPhase2(); return; } // See previous note regarding OpenDesktop.org if (mJobEntry->payload().url().contains(OPENDESKTOP_REDIRECT_URL)) { int pos = mJobData.find("
= 0) { TQString realURL = mJobData.mid(pos); realURL = realURL.mid(0, realURL.find("\">")); realURL = realURL.mid(strlen("payload().protocol() + "://opendesktop.org" + realURL; mJobEntry->setPayload(realURL); } else if ((pos = mJobData.find(OPENDESKTOP_REDIRECT_TEXT)) > 0) { pos = pos + strlen(OPENDESKTOP_REDIRECT_TEXT); TQString realURL = mJobData.mid(pos); realURL = realURL.mid(0, realURL.find("\">")); mJobEntry->setPayload(realURL); } } // Reset for next load mJobData = TQString::null; slotInstallPhase2(); } void Dialog::slotDoneInstall(KNS::Entry* entry_) { TQMap::Iterator it; for(it = m_entryMap.begin(); entry_ && it != m_entryMap.end(); ++it) { if(it.data() == entry_) { InstallStatus installed = Manager::installStatus(entry_); static_cast(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(pct_), 100); } } void Dialog::slotPreviewResult(TDEIO::Job* job_) { TDEIO::FileCopyJob* job = static_cast(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"