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

KDEUI

kwidgetjobtracker.cpp

Go to the documentation of this file.
00001 /*  This file is part of the KDE project
00002     Copyright (C) 2000 Matej Koss <koss@miesto.sk>
00003     Copyright (C) 2007 Kevin Ottens <ervin@kde.org>
00004     Copyright (C) 2007 Rafael Fernández López <ereslibre@kde.org>
00005 
00006     This library is free software; you can redistribute it and/or
00007     modify it under the terms of the GNU Library General Public
00008     License version 2 as published by the Free Software Foundation.
00009 
00010     This library is distributed in the hope that it will be useful,
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013     Library General Public License for more details.
00014 
00015     You should have received a copy of the GNU Library General Public License
00016     along with this library; see the file COPYING.LIB.  If not, write to
00017     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018     Boston, MA 02110-1301, USA.
00019 
00020 */
00021 
00022 #include "kwidgetjobtracker.h"
00023 #include "kwidgetjobtracker_p.h"
00024 
00025 #include <QProcess>
00026 #include <QTimer>
00027 #include <QLabel>
00028 #include <QCheckBox>
00029 #include <QProgressBar>
00030 #include <QVBoxLayout>
00031 #include <QGridLayout>
00032 #include <QMenu>
00033 #include <QEvent>
00034 
00035 #include <kurl.h>
00036 #include <kpushbutton.h>
00037 #include <ksqueezedtextlabel.h>
00038 #include <kguiitem.h>
00039 #include <kiconloader.h>
00040 #include <kdialog.h>
00041 #include <kstandarddirs.h>
00042 #include <kdebug.h>
00043 #include <klocale.h>
00044 #include <kwindowsystem.h>
00045 
00046 void KWidgetJobTracker::Private::_k_slotShowProgressWidget()
00047 {
00048     if (progressWidgetsToBeShown.isEmpty()) {
00049         return;
00050     }
00051 
00052     KJob *job = progressWidgetsToBeShown.dequeue();
00053 
00054     // If the job has been unregistered before reaching this point, widget will
00055     // return 0.
00056     QWidget *widget = q->widget(job);
00057 
00058     if (widget) {
00059         widget->show();
00060     }
00061 }
00062 
00063 KWidgetJobTracker::KWidgetJobTracker(QWidget *parent)
00064     : KAbstractWidgetJobTracker(parent), d(new Private(parent, this))
00065 {
00066 }
00067 
00068 KWidgetJobTracker::~KWidgetJobTracker()
00069 {
00070     delete d;
00071 }
00072 
00073 QWidget *KWidgetJobTracker::widget(KJob *job)
00074 {
00075     return d->progressWidget.value(job, 0);
00076 }
00077 
00078 void KWidgetJobTracker::registerJob(KJob *job)
00079 {
00080     KAbstractWidgetJobTracker::registerJob(job);
00081 
00082     Private::ProgressWidget *vi = new Private::ProgressWidget(job, this, d->parent);
00083     vi->jobRegistered = true;
00084     vi->setAttribute(Qt::WA_DeleteOnClose);
00085     d->progressWidget.insert(job, vi);
00086     d->progressWidgetsToBeShown.enqueue(job);
00087 
00088     QTimer::singleShot(500, this, SLOT(_k_slotShowProgressWidget()));
00089 }
00090 
00091 void KWidgetJobTracker::unregisterJob(KJob *job)
00092 {
00093     KAbstractWidgetJobTracker::unregisterJob(job);
00094 
00095     KWidgetJobTracker::Private::ProgressWidget *pWidget = d->progressWidget.value(job, 0);
00096     if (!pWidget) {
00097         return;
00098     }
00099 
00100     pWidget->jobRegistered = false;
00101     pWidget->deref();
00102 }
00103 
00104 bool KWidgetJobTracker::keepOpen(KJob *job) const
00105 {
00106     KWidgetJobTracker::Private::ProgressWidget *pWidget = d->progressWidget.value(job, 0);
00107     if (!pWidget) {
00108         return false;
00109     }
00110 
00111     return pWidget->keepOpen();
00112 }
00113 
00114 void KWidgetJobTracker::infoMessage(KJob *job, const QString &plain, const QString &rich)
00115 {
00116     KWidgetJobTracker::Private::ProgressWidget *pWidget = d->progressWidget.value(job, 0);
00117     if (!pWidget) {
00118         return;
00119     }
00120 
00121     pWidget->infoMessage(plain, rich);
00122 }
00123 
00124 void KWidgetJobTracker::description(KJob *job, const QString &title,
00125                                     const QPair<QString, QString> &field1,
00126                                     const QPair<QString, QString> &field2)
00127 {
00128     KWidgetJobTracker::Private::ProgressWidget *pWidget = d->progressWidget.value(job, 0);
00129     if (!pWidget) {
00130         return;
00131     }
00132 
00133     pWidget->description(title, field1, field2);
00134 }
00135 
00136 void KWidgetJobTracker::totalAmount(KJob *job, KJob::Unit unit, qulonglong amount)
00137 {
00138     KWidgetJobTracker::Private::ProgressWidget *pWidget = d->progressWidget.value(job, 0);
00139     if (!pWidget) {
00140         return;
00141     }
00142 
00143     pWidget->totalAmount(unit, amount);
00144 }
00145 
00146 void KWidgetJobTracker::processedAmount(KJob *job, KJob::Unit unit, qulonglong amount)
00147 {
00148     KWidgetJobTracker::Private::ProgressWidget *pWidget = d->progressWidget.value(job, 0);
00149     if (!pWidget) {
00150         return;
00151     }
00152 
00153     pWidget->processedAmount(unit, amount);
00154 }
00155 
00156 void KWidgetJobTracker::percent(KJob *job, unsigned long percent)
00157 {
00158     KWidgetJobTracker::Private::ProgressWidget *pWidget = d->progressWidget.value(job, 0);
00159     if (!pWidget) {
00160         return;
00161     }
00162 
00163     pWidget->percent(percent);
00164 }
00165 
00166 void KWidgetJobTracker::speed(KJob *job, unsigned long value)
00167 {
00168     KWidgetJobTracker::Private::ProgressWidget *pWidget = d->progressWidget.value(job, 0);
00169     if (!pWidget) {
00170         return;
00171     }
00172 
00173     pWidget->speed(value);
00174 }
00175 
00176 void KWidgetJobTracker::slotClean(KJob *job)
00177 {
00178     KWidgetJobTracker::Private::ProgressWidget *pWidget = d->progressWidget.value(job, 0);
00179     if (!pWidget) {
00180         return;
00181     }
00182 
00183     pWidget->slotClean();
00184 }
00185 
00186 void KWidgetJobTracker::suspended(KJob *job)
00187 {
00188     KWidgetJobTracker::Private::ProgressWidget *pWidget = d->progressWidget.value(job, 0);
00189     if (!pWidget) {
00190         return;
00191     }
00192 
00193     pWidget->suspended();
00194 }
00195 
00196 void KWidgetJobTracker::resumed(KJob *job)
00197 {
00198     KWidgetJobTracker::Private::ProgressWidget *pWidget = d->progressWidget.value(job, 0);
00199     if (!pWidget) {
00200         return;
00201     }
00202 
00203     pWidget->resumed();
00204 }
00205 
00206 bool KWidgetJobTracker::Private::ProgressWidget::keepOpen() const
00207 {
00208     return keepOpenChecked;
00209 }
00210 
00211 void KWidgetJobTracker::Private::ProgressWidget::ref()
00212 {
00213     refCount++;
00214 }
00215 
00216 void KWidgetJobTracker::Private::ProgressWidget::deref()
00217 {
00218     if (refCount) {
00219         refCount--;
00220     }
00221 
00222     if (!refCount) {
00223         if (!keepOpenChecked) {
00224             closeNow();
00225         } else {
00226             slotClean();
00227         }
00228     }
00229 }
00230 
00231 void KWidgetJobTracker::Private::ProgressWidget::closeNow()
00232 {
00233     close();
00234 
00235     // It might happen the next scenario:
00236     // - Start a job which opens a progress widget. Keep it open. Address job is 0xdeadbeef
00237     // - Start a new job, which is given address 0xdeadbeef. A new window is opened.
00238     //   This one will take much longer to complete. The key 0xdeadbeef on the widget map now
00239     //   stores the new widget address.
00240     // - Close the first progress widget that was opened (and has already finished) while the
00241     //   last one is still running. We remove its reference on the map. Wrong.
00242     // For that reason we have to check if the map stores the widget as the current one.
00243     // ereslibre
00244     if (tracker->d->progressWidget[job] == this) {
00245         tracker->d->progressWidget.remove(job);
00246         tracker->d->progressWidgetsToBeShown.removeAll(job);
00247     }
00248 }
00249 
00250 bool KWidgetJobTracker::Private::ProgressWidget::eventFilter(QObject *watched, QEvent *event)
00251 {
00252     // Handle context menu events for the source/dest labels here, so that we are ref()ed while the
00253     // menu is exec()ed, to avoid a crash if the job finishes meanwhile. #159621.
00254     if ((watched == sourceEdit || watched == destEdit) && event->type() == QEvent::ContextMenu) {
00255         ref();
00256         watched->event(event);
00257         deref();
00258         return true;
00259     }
00260 
00261     return QWidget::eventFilter(watched, event);
00262 }
00263 
00264 void KWidgetJobTracker::Private::ProgressWidget::infoMessage(const QString &plain, const QString &/*rich*/)
00265 {
00266     speedLabel->setText(plain);
00267     speedLabel->setAlignment(speedLabel->alignment() & ~Qt::TextWordWrap);
00268 }
00269 
00270 void KWidgetJobTracker::Private::ProgressWidget::description(const QString &title,
00271                                                                 const QPair<QString, QString> &field1,
00272                                                                 const QPair<QString, QString> &field2)
00273 {
00274     setWindowTitle(title);
00275     caption = title;
00276 
00277     sourceInvite->setText(field1.first);
00278     sourceEdit->setText(field1.second);
00279 
00280     if (field2.first.isEmpty()) {
00281         setDestVisible(false);
00282     } else {
00283         setDestVisible(true);
00284         checkDestination(KUrl(field2.second));
00285         destInvite->setText(field2.first);
00286         destEdit->setText(field2.second);
00287     }
00288 }
00289 
00290 void KWidgetJobTracker::Private::ProgressWidget::totalAmount(KJob::Unit unit, qulonglong amount)
00291 {
00292     switch(unit)
00293     {
00294     case KJob::Bytes:
00295         totalSizeKnown = true;
00296         // size is measured in bytes
00297         if (totalSize == amount)
00298             return;
00299         totalSize = amount;
00300         if (startTime.isNull())
00301             startTime.start();
00302         break;
00303 
00304     case KJob::Files:
00305         if (totalFiles == amount)
00306             return;
00307         totalFiles = amount;
00308         showTotals();
00309         break;
00310 
00311     case KJob::Directories:
00312         if (totalDirs == amount)
00313             return;
00314         totalDirs = amount;
00315         showTotals();
00316         break;
00317     }
00318 }
00319 
00320 void KWidgetJobTracker::Private::ProgressWidget::processedAmount(KJob::Unit unit, qulonglong amount)
00321 {
00322     QString tmp;
00323 
00324     switch(unit)
00325     {
00326     case KJob::Bytes:
00327         if (processedSize == amount)
00328             return;
00329         processedSize = amount;
00330 
00331         if (totalSizeKnown) {
00332             tmp = i18np( "%2 of %3 complete", "%2 of %3 complete",
00333                         amount,
00334                         KGlobal::locale()->formatByteSize(amount),
00335                         KGlobal::locale()->formatByteSize(totalSize));
00336         } else {
00337             tmp = KGlobal::locale()->formatByteSize(amount);
00338         }
00339         sizeLabel->setText(tmp);
00340         if (!totalSizeKnown) // update jumping progressbar
00341             progressBar->setValue(amount);
00342         break;
00343 
00344     case KJob::Directories:
00345         if (processedDirs == amount)
00346             return;
00347         processedDirs = amount;
00348 
00349         tmp = i18np("%2 / %1 folder", "%2 / %1 folders", totalDirs,  processedDirs);
00350         tmp += "   ";
00351         tmp += i18np("%2 / %1 file", "%2 / %1 files", totalFiles,  processedFiles);
00352         progressLabel->setText(tmp);
00353         break;
00354 
00355     case KJob::Files:
00356         if (processedFiles == amount)
00357             return;
00358         processedFiles = amount;
00359 
00360         if (totalDirs > 1) {
00361             tmp = i18np("%2 / %1 folder", "%2 / %1 folders", totalDirs,  processedDirs);
00362             tmp += "   ";
00363         }
00364         tmp += i18np("%2 / %1 file", "%2 / %1 files", totalFiles,  processedFiles);
00365         progressLabel->setText(tmp);
00366     }
00367 }
00368 
00369 void KWidgetJobTracker::Private::ProgressWidget::percent(unsigned long percent)
00370 {
00371     QString title = caption + " (";
00372 
00373     if (totalSizeKnown) {
00374         title += i18n("%1 % of %2 ", percent,
00375                       KGlobal::locale()->formatByteSize(totalSize));
00376     } else if (totalFiles) {
00377         title += i18np("%2 % of 1 file", "%2 % of %1 files", totalFiles, percent);
00378     } else {
00379         title += i18n("%1 %", percent);
00380     }
00381 
00382     title += ')';
00383 
00384     progressBar->setMaximum(100);
00385     progressBar->setValue(percent);
00386     setWindowTitle(title);
00387 }
00388 
00389 void KWidgetJobTracker::Private::ProgressWidget::speed(unsigned long value)
00390 {
00391     if (value == 0) {
00392         speedLabel->setText(i18n("Stalled"));
00393     } else {
00394         const QString speedStr = KGlobal::locale()->formatByteSize(value);
00395         if (totalSizeKnown) {
00396             const int remaining = 1000*(totalSize - processedSize)/value;
00397             speedLabel->setText(i18np("%2/s ( %3 remaining )", "%2/s ( %3 remaining )", remaining, speedStr,
00398                                      KGlobal::locale()->formatDuration(remaining)));
00399         } else { // total size is not known (#24228)
00400             speedLabel->setText(i18nc("speed in bytes per second", "%1/s", speedStr));
00401         }
00402     }
00403 }
00404 
00405 void KWidgetJobTracker::Private::ProgressWidget::slotClean()
00406 {
00407     percent(100);
00408     cancelClose->setGuiItem(KStandardGuiItem::close());
00409     openFile->setEnabled(true);
00410     if (!totalSizeKnown || totalSize < processedSize)
00411         totalSize = processedSize;
00412     processedAmount(KJob::Bytes, totalSize);
00413     keepOpenCheck->setEnabled(false);
00414     pauseButton->setEnabled(false);
00415     if (!startTime.isNull()) {
00416         int s = startTime.elapsed();
00417         if (!s)
00418             s = 1;
00419         speedLabel->setText(i18n("%1/s (done)",
00420                                     KGlobal::locale()->formatByteSize(1000 * totalSize / s)));
00421     }
00422 }
00423 
00424 void KWidgetJobTracker::Private::ProgressWidget::suspended()
00425 {
00426     pauseButton->setText(i18n("Resume"));
00427     suspendedProperty = true;
00428 }
00429 
00430 void KWidgetJobTracker::Private::ProgressWidget::resumed()
00431 {
00432     pauseButton->setText(i18n("Pause"));
00433     suspendedProperty = false;
00434 }
00435 
00436 void KWidgetJobTracker::Private::ProgressWidget::closeEvent(QCloseEvent *event)
00437 {
00438     if (jobRegistered && tracker->stopOnClose(job)) {
00439         tracker->slotStop(job);
00440     }
00441 
00442     QWidget::closeEvent(event);
00443 }
00444 
00445 void KWidgetJobTracker::Private::ProgressWidget::init()
00446 {
00447     // Set a useful icon for this window!
00448     KWindowSystem::setIcons( winId(),
00449                              KIconLoader::global()->loadIcon( "document-save", KIconLoader::NoGroup, 32 ),
00450                              KIconLoader::global()->loadIcon( "document-save", KIconLoader::NoGroup, 16 ) );
00451 
00452     QVBoxLayout *topLayout = new QVBoxLayout(this);
00453     topLayout->setMargin(KDialog::marginHint());
00454     topLayout->setSpacing(KDialog::spacingHint() );
00455     topLayout->addStrut( 360 );   // makes dlg at least that wide
00456 
00457     QGridLayout *grid = new QGridLayout();
00458     topLayout->addLayout(grid);
00459     grid->addItem(new QSpacerItem(KDialog::spacingHint(),0),0,1); //addColSpacing(1, KDialog::spacingHint());
00460     // filenames or action name
00461     sourceInvite = new QLabel(i18n("Source:"), this);
00462     grid->addWidget(sourceInvite, 0, 0);
00463 
00464     sourceEdit = new KSqueezedTextLabel(this);
00465     sourceEdit->setTextInteractionFlags(Qt::TextSelectableByMouse);
00466     sourceEdit->installEventFilter(this);
00467     grid->addWidget(sourceEdit, 0, 2);
00468 
00469     destInvite = new QLabel(i18n("Destination:"), this);
00470     grid->addWidget(destInvite, 1, 0);
00471 
00472     destEdit = new KSqueezedTextLabel(this);
00473     destEdit->setTextInteractionFlags(Qt::TextSelectableByMouse);
00474     destEdit->installEventFilter(this);
00475     grid->addWidget(destEdit, 1, 2);
00476 
00477     QHBoxLayout *progressHBox = new QHBoxLayout();
00478     topLayout->addLayout(progressHBox);
00479 
00480     progressBar = new QProgressBar(this);
00481     progressBar->setMaximum(0); // want a jumping progress bar if percent is not emitted
00482     progressHBox->addWidget(progressBar);
00483 
00484     suspendedProperty = false;
00485     pauseButton = new KPushButton(i18n("Pause"), this);
00486     QObject::connect(pauseButton, SIGNAL(clicked()),
00487                      this, SLOT(_k_pauseResumeClicked()));
00488     progressHBox->addWidget(pauseButton);
00489 
00490     // processed info
00491     QHBoxLayout *hBox = new QHBoxLayout();
00492     topLayout->addLayout(hBox);
00493 
00494     sizeLabel = new QLabel(this);
00495     hBox->addWidget(sizeLabel);
00496 
00497     resumeLabel = new QLabel(this);
00498     hBox->addWidget(resumeLabel);
00499 
00500     progressLabel = new QLabel(this);
00501 /*    progressLabel->setSizePolicy(QSizePolicy(QSizePolicy::MinimumExpanding,
00502                                             QSizePolicy::Preferred));*/
00503     progressLabel->setAlignment(Qt::AlignRight);
00504     hBox->addWidget(progressLabel);
00505 
00506     hBox = new QHBoxLayout();
00507     topLayout->addLayout(hBox);
00508 
00509     speedLabel = new QLabel(this);
00510     hBox->addWidget(speedLabel, 1);
00511 
00512     QFrame *line = new QFrame(this);
00513     line->setFrameShape(QFrame::HLine);
00514     line->setFrameShadow(QFrame::Sunken);
00515     topLayout->addWidget(line);
00516 
00517     keepOpenCheck = new QCheckBox(i18n("&Keep this window open after transfer is complete"), this);
00518     QObject::connect(keepOpenCheck, SIGNAL(toggled(bool)),
00519                      this, SLOT(_k_keepOpenToggled(bool)));
00520     topLayout->addWidget(keepOpenCheck);
00521     keepOpenCheck->hide();
00522 
00523     hBox = new QHBoxLayout();
00524     topLayout->addLayout(hBox);
00525 
00526     openFile = new KPushButton(i18n("Open &File"), this);
00527     QObject::connect(openFile, SIGNAL(clicked()),
00528                      this, SLOT(_k_openFile()));
00529     hBox->addWidget(openFile);
00530     openFile->setEnabled(false);
00531     openFile->hide();
00532 
00533     openLocation = new KPushButton(i18n("Open &Destination"), this);
00534     QObject::connect(openLocation, SIGNAL(clicked()),
00535                      this, SLOT(_k_openLocation()));
00536     hBox->addWidget(openLocation);
00537     openLocation->hide();
00538 
00539     hBox->addStretch(1);
00540 
00541     cancelClose = new KPushButton(KStandardGuiItem::cancel(), this);
00542     QObject::connect(cancelClose, SIGNAL(clicked()),
00543                      this, SLOT(_k_stop()));
00544     hBox->addWidget(cancelClose);
00545 
00546     resize(sizeHint());
00547     setMaximumHeight(sizeHint().height());
00548 
00549     keepOpenChecked = false;
00550     setWindowTitle(i18n("Progress Dialog")); // show something better than kuiserver
00551 }
00552 
00553 void KWidgetJobTracker::Private::ProgressWidget::showTotals()
00554 {
00555     // Show the totals in the progress label, if we still haven't
00556     // processed anything. This is useful when the stat'ing phase
00557     // of CopyJob takes a long time (e.g. over networks).
00558     if (processedFiles == 0 && processedDirs == 0)
00559     {
00560         QString tmps;
00561         if (totalDirs > 1)
00562             // that we have a singular to translate looks weired but is only logical
00563             tmps = i18np("%1 folder", "%1 folders", totalDirs) + "   ";
00564         tmps += i18np("%1 file", "%1 files", totalFiles);
00565         progressLabel->setText( tmps );
00566     }
00567 }
00568 
00569 void KWidgetJobTracker::Private::ProgressWidget::setDestVisible(bool visible)
00570 {
00571     // We can't hide the destInvite/destEdit labels,
00572     // because it screws up the QGridLayout.
00573     if (visible)
00574     {
00575         destInvite->show();
00576         destEdit->show();
00577     }
00578     else
00579     {
00580         destInvite->hide();
00581         destEdit->hide();
00582         destInvite->setText( QString() );
00583         destEdit->setText( QString() );
00584     }
00585 }
00586 
00587 void KWidgetJobTracker::Private::ProgressWidget::checkDestination(const KUrl &dest)
00588 {
00589     bool ok = true;
00590 
00591     if (dest.isLocalFile()) {
00592         QString path = dest.path( KUrl::RemoveTrailingSlash );
00593         const QStringList tmpDirs = KGlobal::dirs()->resourceDirs( "tmp" );
00594         for (QStringList::ConstIterator it = tmpDirs.begin() ; ok && it != tmpDirs.end() ; ++it)
00595             if (path.contains(*it))
00596                 ok = false; // it's in the tmp resource
00597     }
00598 
00599     if (ok) {
00600         openFile->show();
00601         openLocation->show();
00602         keepOpenCheck->show();
00603         location=dest;
00604     }
00605 }
00606 
00607 void KWidgetJobTracker::Private::ProgressWidget::_k_keepOpenToggled(bool keepOpen)
00608 {
00609     if (keepOpen) {
00610         KGlobal::ref();
00611     } else {
00612         KGlobal::deref();
00613     }
00614 
00615     keepOpenChecked = keepOpen;
00616 }
00617 
00618 void KWidgetJobTracker::Private::ProgressWidget::_k_openFile()
00619 {
00620     QProcess::startDetached("kde-open", QStringList() << location.prettyUrl());
00621 }
00622 
00623 void KWidgetJobTracker::Private::ProgressWidget::_k_openLocation()
00624 {
00625     KUrl dirLocation(location);
00626     dirLocation.setFileName(QString());
00627     QProcess::startDetached("kde-open", QStringList() << dirLocation.prettyUrl());
00628 }
00629 
00630 void KWidgetJobTracker::Private::ProgressWidget::_k_pauseResumeClicked()
00631 {
00632     if (jobRegistered && !suspendedProperty) {
00633         tracker->slotSuspend(job);
00634     } else if (jobRegistered) {
00635         tracker->slotResume(job);
00636     }
00637 }
00638 
00639 void KWidgetJobTracker::Private::ProgressWidget::_k_stop()
00640 {
00641     if (jobRegistered) {
00642         tracker->slotStop(job);
00643     }
00644     closeNow();
00645 }
00646 
00647 #include "kwidgetjobtracker.moc"
00648 #include "kwidgetjobtracker_p.moc"

KDEUI

Skip menu "KDEUI"
  • Main Page
  • Modules
  • 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