• Skip to content
  • Skip to link menu
KDE 4.1 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KNewStuff

downloaddialog.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (C) 2005 by Enrico Ros <eros.kde@email.it>                  *
00003  *   Copyright (C) 2005 - 2007 Josef Spillner <spillner@kde.org>           *
00004  *             (C) 2007 Dirk Mueller <mueller@kde.org>                     *
00005  *   Copyright (C) 2007 Jeremy Whiting <jeremy@scitools.com>               *
00006  *                                                                         *
00007  *   This library is free software; you can redistribute it and/or         *
00008  *   modify it under the terms of the GNU Lesser General Public            *
00009  *   License as published by the Free Software Foundation; either          *
00010  *   version 2 of the License, or (at your option) any later version.      *
00011  *                                                                         *
00012  *   This library is distributed in the hope that it will be useful,       *
00013  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00014  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
00015  *   Lesser General Public License for more details.                       *
00016  *                                                                         *
00017  *   You should have received a copy of the GNU Lesser General Public      *
00018  *   License along with this library; if not, write to the                 *
00019  *   Free Software Foundation, Inc.,                                       *
00020  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA          *
00021  ***************************************************************************/
00022 
00023 // own include
00024 #include "downloaddialog.h"
00025 
00026 // qt/kde includes
00027 #include <QtCore/QTimer>
00028 #include <QtGui/QPixmap>
00029 #include <QtGui/QSortFilterProxyModel>
00030 #include <kaboutdata.h>
00031 #include <kcomponentdata.h>
00032 #include <kmessagebox.h>
00033 #include <ktoolinvocation.h>
00034 
00035 #include <kdebug.h>
00036 
00037 #include "knewstuff2/core/provider.h"
00038 #include "knewstuff2/core/providerhandler.h"
00039 #include "knewstuff2/core/entry.h"
00040 #include "knewstuff2/core/entryhandler.h"
00041 #include "knewstuff2/core/category.h"
00042 
00043 #include "knewstuff2/dxs/dxs.h"
00044 
00045 // local includes
00046 #include "ui_DownloadDialog.h"
00047 #include "itemsmodel.h"
00048 #include "itemsviewdelegate.h"
00049 #include "kdxsrating.h"
00050 #include "kdxscomment.h"
00051 #include "kdxscomments.h"
00052 
00053 const char * ConfigGroup = "DownloadDialog Settings";
00054 
00055 using namespace KNS;
00056 
00057 DownloadDialog::DownloadDialog(DxsEngine* _engine, QWidget * _parent)
00058         : KDialog(_parent)
00059 {
00060     setButtons(0);
00061 
00062     m_engine = _engine;
00063     connect(m_engine, SIGNAL(signalProgress(QString, int)), SLOT(slotProgress(QString, int)));
00064     connect(m_engine, SIGNAL(signalEntryChanged(KNS::Entry*)), SLOT(slotEntryChanged(KNS::Entry*)));
00065     connect(m_engine, SIGNAL(signalPayloadFailed(KNS::Entry*)), SLOT(slotPayloadFailed(KNS::Entry*)));
00066     connect(m_engine, SIGNAL(signalProvidersFailed()), SLOT(slotProvidersFailed()));
00067     connect(m_engine, SIGNAL(signalEntriesFailed()), SLOT(slotEntriesFailed()));
00068 
00069     connect(m_engine, SIGNAL(signalEntryLoaded(KNS::Entry*, const KNS::Feed*, const KNS::Provider*)),
00070             this, SLOT(slotEntryLoaded(KNS::Entry*, const KNS::Feed*, const KNS::Provider*)));
00071     connect(m_engine, SIGNAL(signalEntryRemoved(KNS::Entry*, const KNS::Feed*)),
00072             this, SLOT(slotEntryRemoved(KNS::Entry *, const KNS::Feed *)));
00073 
00074     // initialize the private classes
00075     messageTimer = new QTimer(this);
00076     messageTimer->setSingleShot(true);
00077     connect(messageTimer, SIGNAL(timeout()), SLOT(slotResetMessage()));
00078 
00079     networkTimer = new QTimer(this);
00080     connect(networkTimer, SIGNAL(timeout()), SLOT(slotNetworkTimeout()));
00081 
00082     m_searchTimer = new QTimer(this);
00083     m_searchTimer->setSingleShot(true);
00084     m_searchTimer->setInterval(1000);   // timeout after 30 seconds
00085     connect(m_searchTimer, SIGNAL(timeout()), SLOT(slotUpdateSearch()));
00086 
00087     // popuplate dialog with stuff
00088     QWidget* _mainWidget = new QWidget(this);
00089     setMainWidget(_mainWidget);
00090     setupUi(_mainWidget);
00091 
00092     // create the delegate
00093     mDelegate = new ItemsViewDelegate(m_listView);
00094     m_listView->setItemDelegate(mDelegate);
00095     connect(mDelegate, SIGNAL(performAction(DownloadDialog::EntryAction, KNS::Entry *)),
00096             SLOT(slotPerformAction(DownloadDialog::EntryAction, KNS::Entry *)));
00097 
00098     // create the filter model
00099     m_filteredModel = new QSortFilterProxyModel(this);
00100     m_filteredModel->setFilterRole(ItemsModel::kNameRole);
00101     m_filteredModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
00102     m_listView->setModel(m_filteredModel);
00103     connect(m_listView->selectionModel(), SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)),
00104             this, SLOT(slotListIndexChanged(const QModelIndex &, const QModelIndex &)));
00105 
00106     // create left picture widget (if picture found)
00107     //QPixmap p( KStandardDirs::locate( "data", "knewstuff/pics/ghns.png" ) );
00108     //if ( !p.isNull() )
00109     //   horLay->addWidget( new ExtendImageWidget( p, this ) );
00110     // FIXME KDE4PORT: if we use a left bar image, find a better way
00111 
00112 
00113     connect(m_sourceCombo, SIGNAL(currentIndexChanged(int)), SLOT(slotLoadProviderDXS()));
00114     connect(m_sortCombo, SIGNAL(currentIndexChanged(int)), SLOT(slotSortingSelected(int)));
00115     connect(m_searchEdit, SIGNAL(textChanged(const QString &)), SLOT(slotSearchTextChanged()));
00116     connect(m_searchEdit, SIGNAL(editingFinished()), SLOT(slotUpdateSearch()));
00117 
00118     // FIXME: not sure if this is better, or setting openExternalLinks
00119     //connect( m_providerLinkLabel, SIGNAL( linkActivated(const QString &)),
00120     //        KToolInvocation::self(), SLOT(invokeBrowser(const QString &)));
00121 
00122     // load the last size from config
00123     KConfigGroup group(KGlobal::config(), ConfigGroup);
00124     restoreDialogSize(group);
00125     setMinimumSize(700, 400);
00126 
00127     setCaption(i18n("Get Hot New Stuff"));
00128     m_titleWidget->setText(i18nc("Program name followed by 'Add On Installer'",
00129                                  "%1 Add-On Installer",
00130                                  KGlobal::activeComponent().aboutData()->programName()));
00131     m_titleWidget->setPixmap(KIcon(KGlobal::activeComponent().aboutData()->programIconName()));
00132 
00133     connect(m_buttonBox, SIGNAL(rejected()), this, SLOT(accept()));
00134 
00135     KMenu * collabMenu = new KMenu(m_collaborationButton);
00136     QAction * action_collabrating = collabMenu->addAction(i18n("Add Rating"));
00137     action_collabrating->setData(DownloadDialog::kCollabRate);
00138 
00139     QAction * action_collabcomment = collabMenu->addAction(i18n("Add Comment"));
00140     action_collabcomment->setData(DownloadDialog::kCollabComment);
00141 
00142     QAction * action_comment = collabMenu->addAction(SmallIcon("help-about"), i18n("View Comments"));
00143     action_comment->setData(DownloadDialog::kComments);
00144 
00145     QAction * action_collabtranslation = collabMenu->addAction(i18n("Translate"));
00146     action_collabtranslation->setData(DownloadDialog::kCollabTranslate);
00147 
00148     QAction * action_collabsubscribe = collabMenu->addAction(i18n("Subscribe"));
00149     action_collabsubscribe->setData(DownloadDialog::kCollabSubscribe);
00150 
00151     QAction * action_collabremoval = collabMenu->addAction(i18n("Report bad entry"));
00152     action_collabremoval->setData(DownloadDialog::kCollabRemoval);
00153 
00154     m_collaborationButton->setMenu(collabMenu);
00155 }
00156 
00157 DownloadDialog::~DownloadDialog()
00158 {
00159     KConfigGroup group(KGlobal::config(), ConfigGroup);
00160     saveDialogSize(group, KConfigBase::Persistent);
00161 }
00162 
00163 void DownloadDialog::slotPerformAction(DownloadDialog::EntryAction action, KNS::Entry * entry)
00164 {
00165     kDebug(551) << "perform action: " << action;
00166     const Provider * provider = m_providers.contains(entry) ? m_providers[entry] : NULL;
00167     Dxs * dxs = m_engine->dxsObject(provider);
00168     switch (action) {
00169     case kViewInfo:
00170         if (provider != NULL) {
00171             if (provider->webService().isValid()) {
00172                 m_engine->dxsObject(provider)->call_info();
00173             } else {
00174                 slotInfo(provider->name().representation(),
00175                          provider->webAccess().pathOrUrl(),
00176                          QString());
00177             }
00178         }
00179         break;
00180     case kComments:
00181         // show the entry's comments
00182         if (provider != NULL) {
00183             connect(dxs, SIGNAL(signalComments(QStringList)), this, SLOT(slotComments(QStringList)));
00184             dxs->call_comments(entry->idNumber());
00185         }
00186         break;
00187     case kChanges:
00188         // show the entry's changelog
00189         break;
00190     case kContactEmail:
00191         // invoke mail with the address of the author
00192         KToolInvocation::invokeMailer(entry->author().email(), i18n("Re: %1", entry->name().representation()));
00193         break;
00194     case kContactJabber:
00195         // start jabber with author's info
00196         break;
00197     case kCollabTranslate:
00198         // open translation dialog
00199         break;
00200     case kCollabRemoval:
00201         // verify removal, maybe authenticate?
00202         break;
00203     case kCollabSubscribe:
00204         // subscribe to changes
00205         break;
00206     case kUninstall:
00207         // uninstall
00208         m_engine->uninstall(entry);
00209         break;
00210     case kInstall:
00211         // install
00212         m_engine->downloadPayload(entry);
00213         break;
00214     case kCollabComment: {
00215         // open comment dialog
00216         KDXSComment * commentDialog = new KDXSComment(this);
00217         int ret = commentDialog->exec();
00218         if (ret == QDialog::Accepted) {
00219             QString s = commentDialog->comment();
00220             if (!s.isEmpty()) {
00221                 dxs->call_comment(entry->idNumber(), s);
00222             }
00223         }
00224     }
00225     break;
00226     case kCollabRate: {
00227         // prompt for rating, and send to provider
00228         KDXSRating * ratingDialog = new KDXSRating(this);
00229         ratingDialog->exec();
00230     }
00231     break;
00232     }
00233 }
00234 
00235 void DownloadDialog::slotCollabAction(DownloadDialog::EntryAction action)
00236 {
00237     QModelIndex currentIndex = m_listView->currentIndex();
00238     const ItemsModel * realmodel = qobject_cast<const ItemsModel*>(m_filteredModel->sourceModel());
00239     QModelIndex index = m_filteredModel->mapToSource(currentIndex);
00240     KNS::Entry * entry = realmodel->entryForIndex(index);
00241     slotPerformAction(action, entry);
00242 }
00243 
00244 void DownloadDialog::slotListIndexChanged(const QModelIndex &index, const QModelIndex &/*old */)
00245 {
00246     //kDebug() << "slotListIndexChanged called";
00247 
00248     m_collaborationButton->setEnabled(index.isValid());
00249 }
00250 
00251 void DownloadDialog::hideEvent(QHideEvent * event)
00252 {
00253     KConfigGroup group(KGlobal::config(), ConfigGroup);
00254     saveDialogSize(group, KConfigBase::Persistent);
00255     KDialog::hideEvent(event);
00256 }
00257 
00258 void DownloadDialog::displayMessage(const QString & msg, KTitleWidget::MessageType type, int timeOutMs)
00259 {
00260     // stop the pending timer if present
00261     messageTimer->stop();
00262 
00263     // set text to messageLabel
00264     m_titleWidget->setComment(msg, type);
00265 
00266     // single shot the resetColors timer (and create it if null)
00267     if (timeOutMs > 0) {
00268         //kDebug(551) << "starting the message timer for " << timeOutMs;
00269         messageTimer->start(timeOutMs);
00270     }
00271 }
00272 
00273 void DownloadDialog::installItem(Entry *entry)
00274 {
00275     // safety check
00276 //    if ( item->url().isEmpty() || item->destinationPath().isEmpty() )
00277 //    {
00278 //        displayMessage( i18n("I don't know how to install this. Sorry, my fault."), Info );
00279 //        return;
00280 //    }
00281 
00282     //TODO check for AvailableItem deletion! (avoid broken pointers) -> cancel old jobs
00283     slotEntryChanged(entry);
00284 }
00285 
00286 void DownloadDialog::removeItem(Entry *entry)
00287 {
00288     Q_UNUSED(entry);
00289 //    displayMessage( i18n("%1 is no more installed.").arg( item->name().representation() ) );
00290 }
00291 
00292 void DownloadDialog::slotResetMessage() // SLOT
00293 {
00294     m_titleWidget->setComment(QString());
00295 }
00296 
00297 void DownloadDialog::slotNetworkTimeout() // SLOT
00298 {
00299     displayMessage(i18n("Timeout. Check Internet connection!"), KTitleWidget::ErrorMessage);
00300 }
00301 
00302 void DownloadDialog::slotSortingSelected(int sortType)   // SLOT
00303 {
00304     if (sortType >= 0) {
00305         //kDebug(551) << "sorting Selected, setting the sourcemodel for the view";
00306         QString feedName = m_sortCombo->currentText();
00307         QString feedType = m_sortCombo->itemData(sortType).toString();
00308 
00309         const Provider * currentProvider = m_entriesByProvider.keys()[m_sourceCombo->currentIndex()];
00310         Feed * selectedFeed = currentProvider->downloadUrlFeed(feedType);
00311         m_filteredModel->setSourceModel(m_models.value(selectedFeed));
00312         m_collaborationButton->setEnabled(false);
00313     }
00314 }
00315 
00316 
00318 
00319 void DownloadDialog::slotLoadProviderDXS()
00320 {
00321     kDebug(551) << "slotLoadProviderDXS called";
00322     //QString category = m_sourceCombo->currentText();
00323     //QString categoryname = categorymap[category];
00324     QString providerName = m_sourceCombo->currentText();
00325 
00326     QList<const Provider*> providers = m_entriesByProvider.keys();
00327 
00328     for (int i = 0; i < providers.size(); ++i) {
00329         if (providers[i]->name().representation() == providerName) {
00330             // update the sortCombo with this provider's feeds
00331             populateSortCombo(providers[i]);
00332 
00333             Feed * selectedFeed = providers[i]->downloadUrlFeed(m_sortCombo->itemData(m_sortCombo->currentIndex()).toString());
00334             m_filteredModel->setSourceModel(m_models.value(selectedFeed));
00335             //m_list->setProvider(providers[i],
00336             //    providers[i]->downloadUrlFeed(m_sortCombo->itemData(m_sortCombo->currentIndex()).toString()));
00337             break;
00338         }
00339     }
00340 }
00341 
00342 void DownloadDialog::slotUpdateSearch()
00343 {
00344     m_searchTimer->stop();
00345     m_filteredModel->setFilterFixedString(m_searchEdit->text());
00346 }
00347 
00348 void DownloadDialog::slotLoadProvidersListDXS()
00349 {
00350 }
00351 
00352 void DownloadDialog::slotSearchTextChanged()
00353 {
00354     m_searchTimer->start();
00355 }
00356 
00357 void DownloadDialog::slotCategories(QList<KNS::Category*> categories)
00358 {
00359     categorymap.clear();
00360 
00361     for (QList<KNS::Category*>::Iterator it = categories.begin(); it != categories.end(); ++it) {
00362         KNS::Category *category = (*it);
00363         //kDebug(551) << "Category: " << category->name().representation();
00364         QPixmap icon = DesktopIcon(category->icon().url(), 16);
00365         // FIXME: use icon from remote URLs (see non-DXS providers as well)
00366         m_sourceCombo->addItem(icon, category->name().representation());
00367         categorymap[category->name().representation()] = category->id();
00368         // FIXME: better use global id, since names are not guaranteed
00369         //        to be unique
00370     }
00371 
00372     //m_sourceCombo->setEnabled(true);
00373 
00374     slotLoadProviderDXS();
00375 }
00376 
00377 void DownloadDialog::slotEntries(QList<KNS::Entry*> _entries)
00378 {
00379     Q_UNUSED(_entries);
00380 
00381     //d->itemsView->setItems( entries );
00382     // FIXME: old API here
00383 }
00384 
00385 void DownloadDialog::slotEntriesFailed()
00386 {
00387     displayMessage(i18n("Entries failed to load"));
00388 }
00389 // FIXME: below here, those are for traditional GHNS
00390 
00391 void DownloadDialog::slotEntryLoaded(Entry *entry, const Feed *feed, const Provider *provider)
00392 {
00393     Entry::List e = entries[feed];
00394     e.append(entry);
00395     entries[feed] = e;
00396 
00397     if (!m_entriesByProvider.contains(provider)) {
00398         kDebug(551) << "adding provider " << provider->name().representation() << " to combobox";
00399         m_sourceCombo->addItem(provider->name().representation());
00400     }
00401     m_entriesByProvider[provider].append(entry);
00402 
00403     // FIXME: what if entry belongs to more than one provider at once?
00404     m_providers[entry] = provider;
00405 
00406     mMutex.lock();
00407 
00408     if (!m_models.value(feed)) {
00409         // new feed
00410         kDebug(551) << "making a new model for this feed" << feed;
00411         m_models[feed] = new KNS::ItemsModel(this, provider->webService().isValid());
00412         if (provider->name().representation() == m_sourceCombo->currentText()) {
00413             // this provider is selected, so refresh the feed combobox
00414             populateSortCombo(provider);
00415         }
00416     }
00417     mMutex.unlock();
00418 
00419     KNS::ItemsModel* thisModel = m_models.value(feed);
00420 
00421     Q_ASSERT(thisModel != NULL);
00422     thisModel->addEntry(entry);
00423 }
00424 
00425 void DownloadDialog::slotEntryRemoved(KNS::Entry *entry, const KNS::Feed *feed)
00426 {
00427     Q_ASSERT(m_models[feed] != NULL);
00428 
00429     m_models[feed]->removeEntry(entry);
00430 }
00431 
00432 void DownloadDialog::refresh()
00433 {
00434     m_sourceCombo->clear();
00435 
00436     Q_ASSERT(m_entriesByProvider.keys().size() > 0);
00437 
00438     for (int i = 0; i < m_entriesByProvider.keys().count(); i++) {
00439         const Provider *provider = m_entriesByProvider.keys().at(i);
00440         if (!provider) {
00441             //kDebug(551) << "INVALID FEED?!";
00442             continue;
00443         }
00444         //QPixmap icon = DesktopIcon(QString(), 16);
00445         //d->m_typeCombo->addItem(icon, feed->name().representation());
00446         m_sourceCombo->addItem(provider->name().representation());
00447         // FIXME: see DXS categories
00448     }
00449 
00450     slotLoadProviderDXS();
00451 
00453     //const Provider * selectedProvider = m_entriesByProvider.keys()[0];
00454 
00455     //populateSortCombo(selectedProvider);
00456 
00457     //m_sourceCombo->setEnabled(true);
00458     //m_sortCombo->setEnabled(true);
00459     //m_searchEdit->setEnabled(true);
00460 }
00461 
00462 void DownloadDialog::populateSortCombo(const Provider * provider)
00463 {
00464     QString url = provider->webAccess().pathOrUrl();
00465     if (url.isEmpty()) {
00466         m_providerLinkLabel->hide();
00467     } else {
00468         m_providerLinkLabel->setText(QString("<a href=\"%1\">?</a>").arg(url));
00469     }
00470 
00471     QStringList feeds = provider->feeds();
00472     m_sortCombo->clear();
00473     for (int i = 0; i < feeds.size(); ++i) {
00474         QString feedName = provider->downloadUrlFeed(feeds[i])->name().representation();
00475         kDebug(551) << "adding feed " << feeds[i] << " to combobox";
00476         m_sortCombo->addItem(feedName, feeds[i]); // put in the name for the text, and feeds[i] for the userData
00477     }
00478 }
00479 
00480 void DownloadDialog::slotInfo(QString provider, QString server, QString version)
00481 {
00482     QString link = QString("<a href=\"%1\">%1</a>").arg(server);
00483     QString infostring = i18n("Server: %1", link);
00484     infostring += i18n("<br />Provider: %1", provider);
00485     infostring += i18n("<br />Version: %1", version);
00486 
00487     KMessageBox::information(this,
00488                              infostring,
00489                              i18n("Provider information"));
00490 }
00491 
00492 void DownloadDialog::slotComments(QStringList comments)
00493 {
00494     KDXSComments commentsdlg(this);
00495 
00496     for (QStringList::Iterator it = comments.begin(); it != comments.end(); it++) {
00497         //kDebug() << "Comment: " << (*it);
00498         commentsdlg.addComment("foo", (*it));
00499     }
00500 
00501     commentsdlg.exec();
00502 }
00503 
00505 
00506 void DownloadDialog::slotEntryChanged(KNS::Entry * entry)
00507 {
00508     // FIXMEE: tell the model to emit dataChanged for this entry
00509     Q_UNUSED(entry);
00510     //m_list->updateItem(entry);
00511 }
00512 
00513 void DownloadDialog::slotPayloadFailed(KNS::Entry * entry)
00514 {
00515     KMessageBox::error(this, i18n("Could not install %1", entry->name().representation()),
00516                        i18n("Get Hot New Stuff!"));
00517 }
00518 
00519 void DownloadDialog::slotProgress(const QString & text, int percentage)
00520 {
00521     m_progress->addProgress(text, percentage);
00522 }
00523 
00524 void DownloadDialog::slotProvidersFailed()
00525 {
00526     kDebug(551) << "slotProvidersFailed";
00527     KMessageBox::error(this,
00528                        i18n("There was an error loading data providers."),
00529                        i18n("Get Hot New Stuff"));
00530 }
00531 
00532 /*void DownloadDialog::slotItemMessage( KJob * job, const QString & message )
00533 {
00534     AvailableItem * item = d->transferJobs[ job ].item;
00535     kDebug(551) << "Name: " << item->name().representation() << " msg: '" << message << "'.";
00536     d->itemsView->updateItem( item );
00537 }
00538 
00539 void DownloadDialog::slotItemPercentage( KJob * job, unsigned long percent )
00540 {
00541     AvailableItem * item = d->transferJobs[ job ].item;
00542     item->setProgress( (float)percent / 100.0 );
00543     d->itemsView->updateItem( item );
00544 }
00545 
00546 void DownloadDialog::slotItemResult( KJob * job )
00547 {
00548     item->setState( AvailableItem::Normal );
00549     item->setProgress( 100.0 );
00550     d->itemsView->updateItem( item );
00551 
00552 }*/
00553 //END File(s) Transferring
00554 
00555 // fault/error from kdxsbutton
00556 void DownloadDialog::slotFault()
00557 {
00558     KMessageBox::error(this,
00559                        i18n("A protocol fault has occurred. The request has failed."),
00560                        i18n("Desktop Exchange Service"));
00561 }
00562 
00563 void DownloadDialog::slotError()
00564 {
00565     KMessageBox::error(this,
00566                        i18n("A network error has occurred. The request has failed."),
00567                        i18n("Desktop Exchange Service"));
00568 }
00569 
00570 #include "downloaddialog.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
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • KIO
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.4
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