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

KFile

kfileplacesview.cpp

Go to the documentation of this file.
00001 /*  This file is part of the KDE project
00002     Copyright (C) 2007 Kevin Ottens <ervin@kde.org>
00003     Copyright (C) 2008 Rafael Fernández López <ereslibre@kde.org>
00004 
00005     This library is free software; you can redistribute it and/or
00006     modify it under the terms of the GNU Library General Public
00007     License version 2 as published by the Free Software Foundation.
00008 
00009     This library is distributed in the hope that it will be useful,
00010     but WITHOUT ANY WARRANTY; without even the implied warranty of
00011     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012     Library General Public License for more details.
00013 
00014     You should have received a copy of the GNU Library General Public License
00015     along with this library; see the file COPYING.LIB.  If not, write to
00016     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017     Boston, MA 02110-1301, USA.
00018 
00019 */
00020 
00021 #include "kfileplacesview.h"
00022 #include "kfileplacesview_p.h"
00023 
00024 #include <QtCore/QTimeLine>
00025 #include <QtCore/QTimer>
00026 #include <QtGui/QPainter>
00027 #include <QtGui/QAbstractItemDelegate>
00028 #include <QtGui/QKeyEvent>
00029 #include <QtGui/QApplication>
00030 
00031 #include <kdebug.h>
00032 
00033 #include <kmenu.h>
00034 #include <kcomponentdata.h>
00035 #include <kdirnotify.h>
00036 #include <kglobalsettings.h>
00037 #include <kiconloader.h>
00038 #include <klocale.h>
00039 #include <kmessagebox.h>
00040 #include <knotification.h>
00041 #include <kio/job.h>
00042 #include <kio/jobuidelegate.h>
00043 #include <kjob.h>
00044 #include <kcapacitybar.h>
00045 #include <kdiskfreespaceinfo.h>
00046 #include <solid/storageaccess.h>
00047 #include <solid/storagedrive.h>
00048 #include <solid/storagevolume.h>
00049 #include <solid/opticaldrive.h>
00050 #include <solid/opticaldisc.h>
00051 
00052 #include "kfileplaceeditdialog.h"
00053 #include "kfileplacesmodel.h"
00054 
00055 #define LATERAL_MARGIN 4
00056 #define CAPACITYBAR_HEIGHT 6
00057 
00058 class KFilePlacesViewDelegate : public QAbstractItemDelegate
00059 {
00060 public:
00061     KFilePlacesViewDelegate(KFilePlacesView *parent);
00062     virtual ~KFilePlacesViewDelegate();
00063     virtual QSize sizeHint(const QStyleOptionViewItem &option,
00064                            const QModelIndex &index) const;
00065     virtual void paint(QPainter *painter,
00066                        const QStyleOptionViewItem &option,
00067                        const QModelIndex &index) const;
00068 
00069     int iconSize() const;
00070     void setIconSize(int newSize);
00071 
00072     void addAppearingItem(const QModelIndex &index);
00073     void setAppearingItemProgress(qreal value);
00074     void addDisappearingItem(const QModelIndex &index);
00075     void setDisappearingItemProgress(qreal value);
00076 
00077     void setShowHoverIndication(bool show);
00078 
00079     void addFadeAnimation(const QModelIndex &index, QTimeLine *timeLine);
00080     void removeFadeAnimation(const QModelIndex &index);
00081     QModelIndex indexForFadeAnimation(QTimeLine *timeLine) const;
00082     QTimeLine *fadeAnimationForIndex(const QModelIndex &index) const;
00083 
00084     qreal contentsOpacity(const QModelIndex &index) const;
00085 
00086 private:
00087     KFilePlacesView *m_view;
00088     int m_iconSize;
00089 
00090     QList<QPersistentModelIndex> m_appearingItems;
00091     int m_appearingIconSize;
00092     qreal m_appearingOpacity;
00093 
00094     QList<QPersistentModelIndex> m_disappearingItems;
00095     int m_disappearingIconSize;
00096     qreal m_disappearingOpacity;
00097 
00098     bool m_showHoverIndication;
00099 
00100     QMap<QPersistentModelIndex, QTimeLine*> m_timeLineMap;
00101     QMap<QTimeLine*, QPersistentModelIndex> m_timeLineInverseMap;
00102 };
00103 
00104 KFilePlacesViewDelegate::KFilePlacesViewDelegate(KFilePlacesView *parent) :
00105     QAbstractItemDelegate(parent),
00106     m_view(parent),
00107     m_iconSize(48),
00108     m_appearingIconSize(0),
00109     m_appearingOpacity(0.0),
00110     m_disappearingIconSize(0),
00111     m_disappearingOpacity(0.0),
00112     m_showHoverIndication(true)
00113 {
00114 }
00115 
00116 KFilePlacesViewDelegate::~KFilePlacesViewDelegate()
00117 {
00118 }
00119 
00120 QSize KFilePlacesViewDelegate::sizeHint(const QStyleOptionViewItem &option,
00121                                         const QModelIndex &index) const
00122 {
00123     int iconSize = m_iconSize;
00124     if (m_appearingItems.contains(index)) {
00125         iconSize = m_appearingIconSize;
00126     } else if (m_disappearingItems.contains(index)) {
00127         iconSize = m_disappearingIconSize;
00128     }
00129 
00130     const KFilePlacesModel *filePlacesModel = static_cast<const KFilePlacesModel*>(index.model());
00131     Solid::Device device = filePlacesModel->deviceForIndex(index);
00132 
00133     return QSize(option.rect.width(), option.fontMetrics.height() / 2 + qMax(iconSize, option.fontMetrics.height()));
00134 }
00135 
00136 void KFilePlacesViewDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
00137 {
00138     painter->save();
00139 
00140     if (m_appearingItems.contains(index)) {
00141         painter->setOpacity(m_appearingOpacity);
00142     } else if (m_disappearingItems.contains(index)) {
00143         painter->setOpacity(m_disappearingOpacity);
00144     }
00145 
00146     QStyleOptionViewItemV4 opt = option;
00147     if (!m_showHoverIndication) {
00148         opt.state &= ~QStyle::State_MouseOver;
00149     }
00150     QApplication::style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter);
00151     const KFilePlacesModel *placesModel = static_cast<const KFilePlacesModel*>(index.model());
00152     bool isRemovableDevice = false;
00153     Solid::Device device;
00154     if (placesModel->isDevice(index)) {
00155         device = placesModel->deviceForIndex(index);
00156         if (((device.is<Solid::StorageAccess>() && device.as<Solid::StorageAccess>()->isAccessible()) ||
00157              (device.parent().is<Solid::StorageAccess>() && device.parent().as<Solid::StorageAccess>()->isAccessible())) &&
00158             ((device.is<Solid::StorageDrive>() && device.as<Solid::StorageDrive>()->isRemovable()) ||
00159              (device.parent().is<Solid::StorageDrive>() && device.parent().as<Solid::StorageDrive>()->isRemovable())) &&
00160             ((device.is<Solid::StorageDrive>() && device.as<Solid::StorageDrive>()->driveType() != Solid::StorageDrive::CdromDrive) ||
00161              (device.parent().is<Solid::StorageDrive>() && device.parent().as<Solid::StorageDrive>()->driveType() != Solid::StorageDrive::CdromDrive))) {
00162             isRemovableDevice = true;
00163         }
00164     }
00165 
00166     bool isLTR = option.direction == Qt::LeftToRight;
00167 
00168     QIcon icon = index.model()->data(index, Qt::DecorationRole).value<QIcon>();
00169     QPixmap pm = icon.pixmap(m_iconSize, m_iconSize);
00170     QPoint point(isLTR ? option.rect.left() + LATERAL_MARGIN
00171                        : option.rect.right() - LATERAL_MARGIN - m_iconSize, option.rect.top() + (option.rect.height() - m_iconSize) / 2);
00172     painter->drawPixmap(point, pm);
00173 
00174     if (option.state & QStyle::State_Selected) {
00175         painter->setPen(option.palette.highlightedText().color());
00176     }
00177 
00178     QRect rectText;
00179     if (isRemovableDevice && contentsOpacity(index) > 0) {
00180         painter->save();
00181         painter->setOpacity(painter->opacity() * contentsOpacity(index));
00182 
00183         int height = option.fontMetrics.height() + CAPACITYBAR_HEIGHT;
00184         rectText = QRect(isLTR ? m_iconSize + LATERAL_MARGIN * 2 + option.rect.left()
00185                                : 0, option.rect.top() + (option.rect.height() / 2 - height / 2), option.rect.width() - m_iconSize - LATERAL_MARGIN * 2, option.fontMetrics.height());
00186         painter->drawText(rectText, Qt::AlignLeft | Qt::AlignTop, option.fontMetrics.elidedText(index.model()->data(index).toString(), Qt::ElideRight, rectText.width()));
00187         QRect capacityRect(isLTR ? rectText.x() : LATERAL_MARGIN, rectText.bottom() - 1, rectText.width() - LATERAL_MARGIN, CAPACITYBAR_HEIGHT);
00188         Solid::StorageAccess *storage = device.as<Solid::StorageAccess>();
00189         KDiskFreeSpaceInfo info = KDiskFreeSpaceInfo::freeSpaceInfo(storage->filePath());
00190         if (info.size()) {
00191             KCapacityBar capacityBar(KCapacityBar::DrawTextInline);
00192             capacityBar.setValue((info.used() * 100) / info.size());
00193             capacityBar.drawCapacityBar(painter, capacityRect);
00194         }
00195 
00196         painter->restore();
00197 
00198         painter->save();
00199         painter->setOpacity(painter->opacity() * (1 - contentsOpacity(index)));
00200     }
00201 
00202     rectText = QRect(isLTR ? m_iconSize + LATERAL_MARGIN * 2 + option.rect.left()
00203                            : 0, option.rect.top(), option.rect.width() - m_iconSize - LATERAL_MARGIN * 2, option.rect.height());
00204     painter->drawText(rectText, Qt::AlignLeft | Qt::AlignVCenter, option.fontMetrics.elidedText(index.model()->data(index).toString(), Qt::ElideRight, rectText.width()));
00205 
00206     if (isRemovableDevice && contentsOpacity(index) > 0) {
00207         painter->restore();
00208     }
00209 
00210     painter->restore();
00211 }
00212 
00213 int KFilePlacesViewDelegate::iconSize() const
00214 {
00215     return m_iconSize;
00216 }
00217 
00218 void KFilePlacesViewDelegate::setIconSize(int newSize)
00219 {
00220     m_iconSize = newSize;
00221 }
00222 
00223 void KFilePlacesViewDelegate::addAppearingItem(const QModelIndex &index)
00224 {
00225     m_appearingItems << index;
00226 }
00227 
00228 void KFilePlacesViewDelegate::setAppearingItemProgress(qreal value)
00229 {
00230     if (value<=0.25) {
00231         m_appearingOpacity = 0.0;
00232         m_appearingIconSize = iconSize()*value*4;
00233 
00234         if (m_appearingIconSize>=m_iconSize) {
00235             m_appearingIconSize = m_iconSize;
00236         }
00237     } else {
00238         m_appearingIconSize = m_iconSize;
00239         m_appearingOpacity = (value-0.25)*4/3;
00240 
00241         if (value>=1.0) {
00242             m_appearingItems.clear();
00243         }
00244     }
00245 }
00246 
00247 void KFilePlacesViewDelegate::addDisappearingItem(const QModelIndex &index)
00248 {
00249     m_disappearingItems << index;
00250 }
00251 
00252 void KFilePlacesViewDelegate::setDisappearingItemProgress(qreal value)
00253 {
00254     value = 1.0 - value;
00255 
00256     if (value<=0.25) {
00257         m_disappearingOpacity = 0.0;
00258         m_disappearingIconSize = iconSize()*value*4;
00259 
00260         if (m_disappearingIconSize>=m_iconSize) {
00261             m_disappearingIconSize = m_iconSize;
00262         }
00263 
00264         if (value<=0.0) {
00265             m_disappearingItems.clear();
00266         }
00267     } else {
00268         m_disappearingIconSize = m_iconSize;
00269         m_disappearingOpacity = (value-0.25)*4/3;
00270     }
00271 }
00272 
00273 void KFilePlacesViewDelegate::setShowHoverIndication(bool show)
00274 {
00275     m_showHoverIndication = show;
00276 }
00277 
00278 void KFilePlacesViewDelegate::addFadeAnimation(const QModelIndex &index, QTimeLine *timeLine)
00279 {
00280     m_timeLineMap.insert(index, timeLine);
00281     m_timeLineInverseMap.insert(timeLine, index);
00282 }
00283 
00284 void KFilePlacesViewDelegate::removeFadeAnimation(const QModelIndex &index)
00285 {
00286     QTimeLine *timeLine = m_timeLineMap.value(index, 0);
00287     m_timeLineMap.remove(index);
00288     m_timeLineInverseMap.remove(timeLine);
00289 }
00290 
00291 QModelIndex KFilePlacesViewDelegate::indexForFadeAnimation(QTimeLine *timeLine) const
00292 {
00293     return m_timeLineInverseMap.value(timeLine, QModelIndex());
00294 }
00295 
00296 QTimeLine *KFilePlacesViewDelegate::fadeAnimationForIndex(const QModelIndex &index) const
00297 {
00298     return m_timeLineMap.value(index, 0);
00299 }
00300 
00301 qreal KFilePlacesViewDelegate::contentsOpacity(const QModelIndex &index) const
00302 {
00303     QTimeLine *timeLine = fadeAnimationForIndex(index);
00304     if (timeLine) {
00305         return timeLine->currentValue();
00306     }
00307     return 0;
00308 }
00309 
00310 class KFilePlacesView::Private
00311 {
00312 public:
00313     Private(KFilePlacesView *parent) : q(parent), watcher(new KFilePlacesEventWatcher(q)) { }
00314 
00315     enum FadeType {
00316         FadeIn = 0,
00317         FadeOut
00318     };
00319 
00320     KFilePlacesView * const q;
00321 
00322     KUrl currentUrl;
00323     bool autoResizeItems;
00324     bool showAll;
00325     bool smoothItemResizing;
00326     bool dropOnPlace;
00327     bool dragging;
00328     Solid::StorageAccess *lastClickedStorage;
00329     QPersistentModelIndex lastClickedIndex;
00330 
00331     QRect dropRect;
00332 
00333     void setCurrentIndex(const QModelIndex &index);
00334     void adaptItemSize();
00335     void updateHiddenRows();
00336     bool insertAbove(const QRect &itemRect, const QPoint &pos) const;
00337     bool insertBelow(const QRect &itemRect, const QPoint &pos) const;
00338     int insertIndicatorHeight(int itemHeight) const;
00339     void fadeCapacityBar(const QModelIndex &index, FadeType fadeType);
00340 
00341     void _k_placeClicked(const QModelIndex &index);
00342     void _k_placeEntered(const QModelIndex &index);
00343     void _k_placeLeft(const QModelIndex &index);
00344     void _k_storageSetupDone(const QModelIndex &index, bool success);
00345     void _k_adaptItemsUpdate(qreal value);
00346     void _k_itemAppearUpdate(qreal value);
00347     void _k_itemDisappearUpdate(qreal value);
00348     void _k_enableSmoothItemResizing();
00349     void _k_trashUpdated(KJob *job);
00350     void _k_capacityBarFadeValueChanged();
00351     void _k_triggerDevicePolling();
00352 
00353     QTimeLine adaptItemsTimeline;
00354     int oldSize, endSize;
00355 
00356     QTimeLine itemAppearTimeline;
00357     QTimeLine itemDisappearTimeline;
00358 
00359     KFilePlacesEventWatcher *const watcher;
00360     KFilePlacesViewDelegate *delegate;
00361     QTimer pollDevices;
00362     int pollingRequestCount;
00363 };
00364 
00365 KFilePlacesView::KFilePlacesView(QWidget *parent)
00366     : QListView(parent), d(new Private(this))
00367 {
00368     d->showAll = false;
00369     d->smoothItemResizing = false;
00370     d->dropOnPlace = false;
00371     d->autoResizeItems = true;
00372     d->dragging = false;
00373     d->lastClickedStorage = 0;
00374     d->pollingRequestCount = 0;
00375     d->delegate = new KFilePlacesViewDelegate(this);
00376 
00377     setSelectionRectVisible(false);
00378     setSelectionMode(SingleSelection);
00379 
00380     setDragEnabled(true);
00381     setAcceptDrops(true);
00382     setMouseTracking(true);
00383     setDropIndicatorShown(false);
00384     setFrameStyle(QFrame::NoFrame);
00385 
00386     setResizeMode(Adjust);
00387     setItemDelegate(d->delegate);
00388 
00389     QPalette palette = viewport()->palette();
00390     palette.setColor(viewport()->backgroundRole(), Qt::transparent);
00391     palette.setColor(viewport()->foregroundRole(), palette.color(QPalette::WindowText));
00392     viewport()->setPalette(palette);
00393 
00394     connect(this, SIGNAL(clicked(const QModelIndex&)),
00395             this, SLOT(_k_placeClicked(const QModelIndex&)));
00396     // Note: Don't connect to the activated() signal, as the behavior when it is
00397     // committed depends on the used widget style. The click behavior of
00398     // KFilePlacesView should be style independent.
00399 
00400     connect(&d->adaptItemsTimeline, SIGNAL(valueChanged(qreal)),
00401             this, SLOT(_k_adaptItemsUpdate(qreal)));
00402     d->adaptItemsTimeline.setDuration(500);
00403     d->adaptItemsTimeline.setUpdateInterval(5);
00404     d->adaptItemsTimeline.setCurveShape(QTimeLine::EaseInOutCurve);
00405 
00406     connect(&d->itemAppearTimeline, SIGNAL(valueChanged(qreal)),
00407             this, SLOT(_k_itemAppearUpdate(qreal)));
00408     d->itemAppearTimeline.setDuration(500);
00409     d->itemAppearTimeline.setUpdateInterval(5);
00410     d->itemAppearTimeline.setCurveShape(QTimeLine::EaseInOutCurve);
00411 
00412     connect(&d->itemDisappearTimeline, SIGNAL(valueChanged(qreal)),
00413             this, SLOT(_k_itemDisappearUpdate(qreal)));
00414     d->itemDisappearTimeline.setDuration(500);
00415     d->itemDisappearTimeline.setUpdateInterval(5);
00416     d->itemDisappearTimeline.setCurveShape(QTimeLine::EaseInOutCurve);
00417 
00418     viewport()->installEventFilter(d->watcher);
00419     connect(d->watcher, SIGNAL(entryEntered(const QModelIndex&)),
00420             this, SLOT(_k_placeEntered(const QModelIndex&)));
00421     connect(d->watcher, SIGNAL(entryLeft(const QModelIndex&)),
00422             this, SLOT(_k_placeLeft(const QModelIndex&)));
00423 
00424     d->pollDevices.setInterval(5000);
00425     connect(&d->pollDevices, SIGNAL(timeout()), this, SLOT(_k_triggerDevicePolling()));
00426 }
00427 
00428 KFilePlacesView::~KFilePlacesView()
00429 {
00430     delete d;
00431 }
00432 
00433 void KFilePlacesView::setDropOnPlaceEnabled(bool enabled)
00434 {
00435     d->dropOnPlace = enabled;
00436 }
00437 
00438 bool KFilePlacesView::isDropOnPlaceEnabled() const
00439 {
00440     return d->dropOnPlace;
00441 }
00442 
00443 void KFilePlacesView::setAutoResizeItemsEnabled(bool enabled)
00444 {
00445     d->autoResizeItems = enabled;
00446 }
00447 
00448 bool KFilePlacesView::isAutoResizeItemsEnabled() const
00449 {
00450     return d->autoResizeItems;
00451 }
00452 
00453 void KFilePlacesView::setUrl(const KUrl &url)
00454 {
00455     KUrl oldUrl = d->currentUrl;
00456     KFilePlacesModel *placesModel = qobject_cast<KFilePlacesModel*>(model());
00457 
00458     if (placesModel==0) return;
00459 
00460     QModelIndex index = placesModel->closestItem(url);
00461     QModelIndex current = selectionModel()->currentIndex();
00462 
00463     if (index.isValid()) {
00464         if (current!=index && placesModel->isHidden(current) && !d->showAll) {
00465             KFilePlacesViewDelegate *delegate = dynamic_cast<KFilePlacesViewDelegate*>(itemDelegate());
00466             delegate->addDisappearingItem(current);
00467 
00468             if (d->itemDisappearTimeline.state()!=QTimeLine::Running) {
00469                 delegate->setDisappearingItemProgress(0.0);
00470                 d->itemDisappearTimeline.start();
00471             }
00472         }
00473 
00474         if (current!=index && placesModel->isHidden(index) && !d->showAll) {
00475             KFilePlacesViewDelegate *delegate = dynamic_cast<KFilePlacesViewDelegate*>(itemDelegate());
00476             delegate->addAppearingItem(index);
00477 
00478             if (d->itemAppearTimeline.state()!=QTimeLine::Running) {
00479                 delegate->setAppearingItemProgress(0.0);
00480                 d->itemAppearTimeline.start();
00481             }
00482 
00483             setRowHidden(index.row(), false);
00484         }
00485 
00486         d->currentUrl = url;
00487         selectionModel()->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect);
00488     } else {
00489         d->currentUrl = KUrl();
00490         selectionModel()->clear();
00491     }
00492 
00493     if (!current.isValid()) {
00494         d->updateHiddenRows();
00495     }
00496 }
00497 
00498 void KFilePlacesView::setShowAll(bool showAll)
00499 {
00500     KFilePlacesModel *placesModel = qobject_cast<KFilePlacesModel*>(model());
00501 
00502     if (placesModel==0) return;
00503 
00504     d->showAll = showAll;
00505 
00506     KFilePlacesViewDelegate *delegate = dynamic_cast<KFilePlacesViewDelegate*>(itemDelegate());
00507 
00508     int rowCount = placesModel->rowCount();
00509     QModelIndex current = placesModel->closestItem(d->currentUrl);
00510 
00511     if (showAll) {
00512         d->updateHiddenRows();
00513 
00514         for (int i=0; i<rowCount; ++i) {
00515             QModelIndex index = placesModel->index(i, 0);
00516             if (index!=current && placesModel->isHidden(index)) {
00517                 delegate->addAppearingItem(index);
00518             }
00519         }
00520 
00521         if (d->itemAppearTimeline.state()!=QTimeLine::Running) {
00522             delegate->setAppearingItemProgress(0.0);
00523             d->itemAppearTimeline.start();
00524         }
00525     } else {
00526         for (int i=0; i<rowCount; ++i) {
00527             QModelIndex index = placesModel->index(i, 0);
00528             if (index!=current && placesModel->isHidden(index)) {
00529                 delegate->addDisappearingItem(index);
00530             }
00531         }
00532 
00533         if (d->itemDisappearTimeline.state()!=QTimeLine::Running) {
00534             delegate->setDisappearingItemProgress(0.0);
00535             d->itemDisappearTimeline.start();
00536         }
00537     }
00538 }
00539 
00540 void KFilePlacesView::keyPressEvent(QKeyEvent *event)
00541 {
00542     QListView::keyPressEvent(event);
00543     if ((event->key() == Qt::Key_Return) || (event->key() == Qt::Key_Enter)) {
00544         d->_k_placeClicked(currentIndex());
00545     }
00546 }
00547 
00548 void KFilePlacesView::contextMenuEvent(QContextMenuEvent *event)
00549 {
00550     KFilePlacesModel *placesModel = qobject_cast<KFilePlacesModel*>(model());
00551     KFilePlacesViewDelegate *delegate = dynamic_cast<KFilePlacesViewDelegate*>(itemDelegate());
00552 
00553     if (placesModel==0) return;
00554 
00555     QModelIndex index = indexAt(event->pos());
00556     QString label = placesModel->text(index).replace('&',"&&");
00557 
00558     KMenu menu;
00559 
00560     QAction *edit = 0;
00561     QAction *hide = 0;
00562     QAction *emptyTrash = 0;
00563     QAction *eject = 0;
00564     QAction *teardown = 0;
00565     QAction *add = 0;
00566     QAction *mainSeparator = 0;
00567 
00568     if (index.isValid()) {
00569         if (!placesModel->isDevice(index)) {
00570             if (placesModel->url(index) == KUrl("trash:/")) {
00571                 emptyTrash = menu.addAction(KIcon("trash-empty"), i18nc("@action:inmenu", "Empty Trash"));
00572                 KConfig trashConfig("trashrc", KConfig::SimpleConfig);
00573                 emptyTrash->setEnabled(!trashConfig.group("Status").readEntry("Empty", true));
00574                 menu.addSeparator();
00575             }
00576             add = menu.addAction(KIcon("document-new"), i18n("Add Entry..."));
00577             mainSeparator = menu.addSeparator();
00578             edit = menu.addAction(KIcon("document-properties"), i18n("&Edit '%1'...", label));
00579         } else {
00580             eject = placesModel->ejectActionForIndex(index);
00581             if (eject!=0) {
00582                 eject->setParent(&menu);
00583                 menu.addAction(eject);
00584             }
00585 
00586             teardown = placesModel->teardownActionForIndex(index);
00587             if (teardown!=0) {
00588                 teardown->setParent(&menu);
00589                 menu.addAction(teardown);
00590             }
00591 
00592             if (teardown!=0 || eject!=0) {
00593                 mainSeparator = menu.addSeparator();
00594             }
00595         }
00596         if (add == 0) {
00597             add = menu.addAction(KIcon("document-new"), i18n("Add Entry..."));
00598         }
00599 
00600         hide = menu.addAction(i18n("&Hide '%1'", label));
00601         hide->setCheckable(true);
00602         hide->setChecked(placesModel->isHidden(index));
00603     } else {
00604         add = menu.addAction(KIcon("document-new"), i18n("Add Entry..."));
00605     }
00606 
00607     QAction *showAll = 0;
00608     if (placesModel->hiddenCount()>0) {
00609         showAll = new QAction(i18n("&Show All Entries"), &menu);
00610         showAll->setCheckable(true);
00611         showAll->setChecked(d->showAll);
00612         if (mainSeparator == 0) {
00613             mainSeparator = menu.addSeparator();
00614         }
00615         menu.insertAction(mainSeparator, showAll);
00616     }
00617 
00618     QAction* remove = 0;
00619     if (index.isValid() && !placesModel->isDevice(index)) {
00620         remove = menu.addAction( KIcon("edit-delete"), i18n("&Remove '%1'", label));
00621     }
00622 
00623     if (menu.isEmpty()) {
00624         return;
00625     }
00626 
00627     QAction *result = menu.exec(event->globalPos());
00628 
00629     if (emptyTrash != 0 && result == emptyTrash) {
00630         const QString text = i18nc("@info", "Do you really want to empty the Trash? All items will be deleted.");
00631         const bool del = KMessageBox::warningContinueCancel(window(),
00632                                                             text,
00633                                                             QString(),
00634                                                             KGuiItem(i18nc("@action:button", "Empty Trash"),
00635                                                                      KIcon("user-trash"))
00636                                                            ) == KMessageBox::Continue;
00637         if (del) {
00638             QByteArray packedArgs;
00639             QDataStream stream(&packedArgs, QIODevice::WriteOnly);
00640             stream << int(1);
00641             KIO::Job *job = KIO::special(KUrl("trash:/"), packedArgs);
00642             KNotification::event("Trash: emptied", QString() , QPixmap() , 0, KNotification::DefaultEvent);
00643             job->ui()->setWindow(parentWidget());
00644             connect(job, SIGNAL(result(KJob*)), SLOT(_k_trashUpdated(KJob*)));
00645         }
00646     } else if (edit != 0 && result == edit) {
00647         KBookmark bookmark = placesModel->bookmarkForIndex(index);
00648         KUrl url = bookmark.url();
00649         QString description = bookmark.text();
00650         QString iconName = bookmark.icon();
00651         bool appLocal = !bookmark.metaDataItem("OnlyInApp").isEmpty();
00652 
00653         if (KFilePlaceEditDialog::getInformation(true, url, description,
00654                                                  iconName, appLocal, 64, this))
00655         {
00656             QString appName;
00657             if (appLocal) appName = KGlobal::mainComponent().componentName();
00658 
00659             placesModel->editPlace(index, description, url, iconName, appName);
00660         }
00661 
00662     } else if (remove != 0 && result == remove) {
00663         placesModel->removePlace(index);
00664     } else if (hide != 0 && result == hide) {
00665         placesModel->setPlaceHidden(index, hide->isChecked());
00666         QModelIndex current = placesModel->closestItem(d->currentUrl);
00667 
00668         if (index!=current && !d->showAll && hide->isChecked()) {
00669             delegate->addDisappearingItem(index);
00670 
00671             if (d->itemDisappearTimeline.state()!=QTimeLine::Running) {
00672                 delegate->setDisappearingItemProgress(0.0);
00673                 d->itemDisappearTimeline.start();
00674             }
00675         }
00676     } else if (showAll != 0 && result == showAll) {
00677         setShowAll(showAll->isChecked());
00678     } else if (teardown != 0 && result == teardown) {
00679         placesModel->requestTeardown(index);
00680     } else if (eject != 0 && result == eject) {
00681         placesModel->requestEject(index);
00682     } else if (add != 0 && result == add) {
00683         KUrl url = QDir::homePath();
00684         QString description = i18n("Enter a description");
00685         QString iconName = "folder";
00686         bool appLocal = true;
00687         if (KFilePlaceEditDialog::getInformation(true, url, description,
00688                                                  iconName, appLocal, 64, this))
00689         {
00690             QString appName;
00691             if (appLocal) appName = KGlobal::mainComponent().componentName();
00692 
00693             placesModel->addPlace(description, url, iconName, appName);
00694         }
00695     }
00696 
00697     index = placesModel->closestItem(d->currentUrl);
00698     selectionModel()->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect);
00699 }
00700 
00701 void KFilePlacesView::resizeEvent(QResizeEvent *event)
00702 {
00703     QListView::resizeEvent(event);
00704     d->adaptItemSize();
00705 }
00706 
00707 void KFilePlacesView::showEvent(QShowEvent *event)
00708 {
00709     QListView::showEvent(event);
00710     QTimer::singleShot(100, this, SLOT(_k_enableSmoothItemResizing()));
00711 }
00712 
00713 void KFilePlacesView::hideEvent(QHideEvent *event)
00714 {
00715     QListView::hideEvent(event);
00716     d->smoothItemResizing = false;
00717 }
00718 
00719 void KFilePlacesView::dragEnterEvent(QDragEnterEvent *event)
00720 {
00721     QListView::dragEnterEvent(event);
00722     d->dragging = true;
00723 
00724     KFilePlacesViewDelegate *delegate = dynamic_cast<KFilePlacesViewDelegate*>(itemDelegate());
00725     delegate->setShowHoverIndication(false);
00726 
00727     d->dropRect = QRect();
00728 }
00729 
00730 void KFilePlacesView::dragLeaveEvent(QDragLeaveEvent *event)
00731 {
00732     QListView::dragLeaveEvent(event);
00733     d->dragging = false;
00734 
00735     KFilePlacesViewDelegate *delegate = dynamic_cast<KFilePlacesViewDelegate*>(itemDelegate());
00736     delegate->setShowHoverIndication(true);
00737 
00738     setDirtyRegion(d->dropRect);
00739 }
00740 
00741 void KFilePlacesView::dragMoveEvent(QDragMoveEvent *event)
00742 {
00743     QListView::dragMoveEvent(event);
00744 
00745     // update the drop indicator
00746     const QPoint pos = event->pos();
00747     const QModelIndex index = indexAt(pos);
00748     setDirtyRegion(d->dropRect);
00749     if (index.isValid()) {
00750         const QRect rect = visualRect(index);
00751         const int gap = d->insertIndicatorHeight(rect.height());
00752         if (d->insertAbove(rect, pos)) {
00753             // indicate that the item will be inserted above the current place
00754             d->dropRect = QRect(rect.left(), rect.top() - gap / 2,
00755                                 rect.width(), gap);
00756         } else if (d->insertBelow(rect, pos)) {
00757             // indicate that the item will be inserted below the current place
00758             d->dropRect = QRect(rect.left(), rect.bottom() + 1 -  gap / 2,
00759                                 rect.width(), gap);
00760         } else {
00761             // indicate that the item be dropped above the current place
00762             d->dropRect = rect;
00763         }
00764     }
00765 
00766     setDirtyRegion(d->dropRect);
00767 }
00768 
00769 void KFilePlacesView::dropEvent(QDropEvent *event)
00770 {
00771     const QPoint pos = event->pos();
00772     const QModelIndex index = indexAt(pos);
00773     if (index.isValid()) {
00774         const QRect rect = visualRect(index);
00775         if (!d->insertAbove(rect, pos) && !d->insertBelow(rect, pos)) {
00776             KFilePlacesModel *placesModel = qobject_cast<KFilePlacesModel*>(model());
00777             Q_ASSERT(placesModel != 0);
00778             emit urlsDropped(placesModel->url(index), event, this);
00779             event->acceptProposedAction();
00780         }
00781     }
00782 
00783     QListView::dropEvent(event);
00784     d->dragging = false;
00785 
00786     KFilePlacesViewDelegate *delegate = dynamic_cast<KFilePlacesViewDelegate*>(itemDelegate());
00787     delegate->setShowHoverIndication(true);
00788 }
00789 
00790 void KFilePlacesView::paintEvent(QPaintEvent* event)
00791 {
00792     QListView::paintEvent(event);
00793     if (d->dragging && !d->dropRect.isEmpty()) {
00794         // draw drop indicator
00795         QPainter painter(viewport());
00796 
00797         const QModelIndex index = indexAt(d->dropRect.topLeft());
00798         const QRect itemRect = visualRect(index);
00799         const bool drawInsertIndicator = !d->dropOnPlace ||
00800                                          d->dropRect.height() <= d->insertIndicatorHeight(itemRect.height());
00801 
00802         if (drawInsertIndicator) {
00803             // draw indicator for inserting items
00804             QBrush blendedBrush = viewOptions().palette.brush(QPalette::Normal, QPalette::Highlight);
00805             QColor color = blendedBrush.color();
00806 
00807             const int y = (d->dropRect.top() + d->dropRect.bottom()) / 2;
00808             const int thickness = d->dropRect.height() / 2;
00809             Q_ASSERT(thickness >= 1);
00810             int alpha = 255;
00811             const int alphaDec = alpha / (thickness + 1);
00812             for (int i = 0; i < thickness; i++) {
00813                 color.setAlpha(alpha);
00814                 alpha -= alphaDec;
00815                 painter.setPen(color);
00816                 painter.drawLine(d->dropRect.left(), y - i, d->dropRect.right(), y - i);
00817                 painter.drawLine(d->dropRect.left(), y + i, d->dropRect.right(), y + i);
00818             }
00819         } else {
00820             // draw indicator for copying/moving/linking to items
00821             QStyleOptionViewItemV4 opt;
00822             opt.initFrom(this);
00823             opt.rect = itemRect;
00824             opt.state = QStyle::State_Enabled | QStyle::State_MouseOver;
00825             style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, &painter, this);
00826         }
00827     }
00828 }
00829 
00830 void KFilePlacesView::setModel(QAbstractItemModel *model)
00831 {
00832     QListView::setModel(model);
00833     d->updateHiddenRows();
00834     connect(model, SIGNAL(rowsRemoved(const QModelIndex&, int, int)),
00835             this, SLOT(adaptItemSize()));
00836     connect(selectionModel(), SIGNAL(currentChanged(const QModelIndex&,const QModelIndex&)),
00837             d->watcher, SLOT(currentIndexChanged(const QModelIndex&)));
00838 }
00839 
00840 void KFilePlacesView::rowsInserted(const QModelIndex &parent, int start, int end)
00841 {
00842     QListView::rowsInserted(parent, start, end);
00843     setUrl(d->currentUrl);
00844 
00845     KFilePlacesViewDelegate *delegate = dynamic_cast<KFilePlacesViewDelegate*>(itemDelegate());
00846     KFilePlacesModel *placesModel = qobject_cast<KFilePlacesModel*>(model());
00847 
00848     for (int i=start; i<=end; ++i) {
00849         QModelIndex index = placesModel->index(i, 0, parent);
00850         if (d->showAll || !placesModel->isHidden(index)) {
00851             delegate->addAppearingItem(index);
00852         } else {
00853             setRowHidden(i, true);
00854         }
00855     }
00856 
00857     if (d->itemAppearTimeline.state()!=QTimeLine::Running) {
00858         delegate->setAppearingItemProgress(0.0);
00859         d->itemAppearTimeline.start();
00860     }
00861 
00862     d->adaptItemSize();
00863 }
00864 
00865 QSize KFilePlacesView::sizeHint() const
00866 {
00867     KFilePlacesModel *placesModel = qobject_cast<KFilePlacesModel*>(model());
00868     if (!placesModel) {
00869         return QListView::sizeHint();
00870     }
00871     const int height = QListView::sizeHint().height();
00872     QFontMetrics fm = d->q->fontMetrics();
00873     int textWidth = 0;
00874 
00875     for (int i=0; i<placesModel->rowCount(); ++i) {
00876         QModelIndex index = placesModel->index(i, 0);
00877         if (!placesModel->isHidden(index))
00878            textWidth = qMax(textWidth,fm.width(index.data(Qt::DisplayRole).toString()));
00879     }
00880 
00881     const int iconSize = KIconLoader::global()->currentSize(KIconLoader::Dialog);
00882     return QSize(iconSize + textWidth + fm.height() / 2, height);
00883 }
00884 
00885 void KFilePlacesView::Private::setCurrentIndex(const QModelIndex &index)
00886 {
00887     KFilePlacesModel *placesModel = qobject_cast<KFilePlacesModel*>(q->model());
00888 
00889     if (placesModel==0) return;
00890 
00891     KUrl url = placesModel->url(index);
00892 
00893     if (url.isValid()) {
00894         currentUrl = url;
00895         updateHiddenRows();
00896         emit q->urlChanged(url);
00897         if (showAll) {
00898             q->setShowAll(false);
00899         }
00900     } else {
00901         q->setUrl(currentUrl);
00902     }
00903 }
00904 
00905 void KFilePlacesView::Private::adaptItemSize()
00906 {
00907     KFilePlacesViewDelegate *delegate = dynamic_cast<KFilePlacesViewDelegate*>(q->itemDelegate());
00908     if (!delegate) return;
00909 
00910     if (!autoResizeItems) {
00911         int size = q->iconSize().width(); // Assume width == height
00912         delegate->setIconSize(size);
00913         q->scheduleDelayedItemsLayout();
00914         return;
00915     }
00916 
00917     KFilePlacesModel *placesModel = qobject_cast<KFilePlacesModel*>(q->model());
00918 
00919     if (placesModel==0) return;
00920 
00921     int rowCount = placesModel->rowCount();
00922 
00923     if (!showAll) {
00924         rowCount-= placesModel->hiddenCount();
00925 
00926         QModelIndex current = placesModel->closestItem(currentUrl);
00927 
00928         if (placesModel->isHidden(current)) {
00929             rowCount++;
00930         }
00931     }
00932 
00933     if (rowCount==0) return; // We've nothing to display anyway
00934 
00935     const int minSize = 16;
00936     const int maxSize = 64;
00937 
00938     int textWidth = 0;
00939     QFontMetrics fm = q->fontMetrics();
00940     for (int i=0; i<placesModel->rowCount(); ++i) {
00941         QModelIndex index = placesModel->index(i, 0);
00942 
00943         if (!placesModel->isHidden(index))
00944            textWidth = qMax(textWidth,fm.width(index.data(Qt::DisplayRole).toString()));
00945     }
00946 
00947     const int margin = q->style()->pixelMetric(QStyle::PM_FocusFrameHMargin, 0, q) + 1;
00948     const int maxWidth = q->viewport()->width() - textWidth - 4 * margin - 1;
00949     const int maxHeight = ((q->height() - (fm.height() / 2) * rowCount) / rowCount) - 1;
00950 
00951     int size = qMin(maxHeight, maxWidth);
00952 
00953     if (size<minSize) {
00954         size = minSize;
00955     } else if (size>maxSize) {
00956         size = maxSize;
00957     } else {
00958         // Make it a multiple of 16
00959         size &= ~0xf;
00960     }
00961 
00962     if (size==delegate->iconSize()) return;
00963 
00964     if (smoothItemResizing) {
00965         oldSize = delegate->iconSize();
00966         endSize = size;
00967         if (adaptItemsTimeline.state()!=QTimeLine::Running) {
00968             adaptItemsTimeline.start();
00969         }
00970     } else {
00971         delegate->setIconSize(size);
00972         q->scheduleDelayedItemsLayout();
00973     }
00974 }
00975 
00976 void KFilePlacesView::Private::updateHiddenRows()
00977 {
00978     KFilePlacesModel *placesModel = qobject_cast<KFilePlacesModel*>(q->model());
00979 
00980     if (placesModel==0) return;
00981 
00982     int rowCount = placesModel->rowCount();
00983     QModelIndex current = placesModel->closestItem(currentUrl);
00984 
00985     for (int i=0; i<rowCount; ++i) {
00986         QModelIndex index = placesModel->index(i, 0);
00987         if (index!=current && placesModel->isHidden(index) && !showAll) {
00988             q->setRowHidden(i, true);
00989         } else {
00990             q->setRowHidden(i, false);
00991         }
00992     }
00993 
00994     adaptItemSize();
00995 }
00996 
00997 bool KFilePlacesView::Private::insertAbove(const QRect &itemRect, const QPoint &pos) const
00998 {
00999     if (dropOnPlace) {
01000         return pos.y() < itemRect.top() + insertIndicatorHeight(itemRect.height()) / 2;
01001     }
01002 
01003     return pos.y() < itemRect.top() + (itemRect.height() / 2);
01004 }
01005 
01006 bool KFilePlacesView::Private::insertBelow(const QRect &itemRect, const QPoint &pos) const
01007 {
01008     if (dropOnPlace) {
01009         return pos.y() > itemRect.bottom() - insertIndicatorHeight(itemRect.height()) / 2;
01010     }
01011 
01012     return pos.y() >= itemRect.top() + (itemRect.height() / 2);
01013 }
01014 
01015 int KFilePlacesView::Private::insertIndicatorHeight(int itemHeight) const
01016 {
01017     const int min = 4;
01018     const int max = 12;
01019 
01020     int height = itemHeight / 4;
01021     if (height < min) {
01022         height = min;
01023     } else if (height > max) {
01024         height = max;
01025     }
01026     return height;
01027 }
01028 
01029 void KFilePlacesView::Private::fadeCapacityBar(const QModelIndex &index, FadeType fadeType)
01030 {
01031     QTimeLine *timeLine = delegate->fadeAnimationForIndex(index);
01032     delete timeLine;
01033     delegate->removeFadeAnimation(index);
01034     timeLine = new QTimeLine(250, q);
01035     connect(timeLine, SIGNAL(valueChanged(qreal)), q, SLOT(_k_capacityBarFadeValueChanged()));
01036     if (fadeType == FadeIn) {
01037         timeLine->setDirection(QTimeLine::Forward);
01038         timeLine->setCurrentTime(0);
01039     } else {
01040         timeLine->setDirection(QTimeLine::Backward);
01041         timeLine->setCurrentTime(250);
01042     }
01043     delegate->addFadeAnimation(index, timeLine);
01044     timeLine->start();
01045 }
01046 
01047 void KFilePlacesView::Private::_k_placeClicked(const QModelIndex &index)
01048 {
01049     KFilePlacesModel *placesModel = qobject_cast<KFilePlacesModel*>(q->model());
01050 
01051     if (placesModel==0) return;
01052 
01053     lastClickedIndex = QPersistentModelIndex();
01054 
01055     if (placesModel->setupNeeded(index)) {
01056         QObject::connect(placesModel, SIGNAL(setupDone(const QModelIndex &, bool)),
01057                          q, SLOT(_k_storageSetupDone(const QModelIndex &, bool)));
01058 
01059         lastClickedIndex = index;
01060         placesModel->requestSetup(index);
01061         return;
01062     }
01063 
01064     setCurrentIndex(index);
01065 }
01066 
01067 void KFilePlacesView::Private::_k_placeEntered(const QModelIndex &index)
01068 {
01069     fadeCapacityBar(index, FadeIn);
01070     pollingRequestCount++;
01071     if (pollingRequestCount == 1) {
01072         pollDevices.start();
01073     }
01074 }
01075 
01076 void KFilePlacesView::Private::_k_placeLeft(const QModelIndex &index)
01077 {
01078     fadeCapacityBar(index, FadeOut);
01079     pollingRequestCount--;
01080     if (!pollingRequestCount) {
01081         pollDevices.stop();
01082     }
01083 }
01084 
01085 void KFilePlacesView::Private::_k_storageSetupDone(const QModelIndex &index, bool success)
01086 {
01087     if (index!=lastClickedIndex) {
01088         return;
01089     }
01090 
01091     KFilePlacesModel *placesModel = qobject_cast<KFilePlacesModel*>(q->model());
01092 
01093     QObject::disconnect(placesModel, SIGNAL(setupDone(const QModelIndex &, bool)),
01094                         q, SLOT(_k_storageSetupDone(const QModelIndex &, bool)));
01095 
01096     if (success) {
01097         setCurrentIndex(lastClickedIndex);
01098     } else {
01099         q->setUrl(currentUrl);
01100     }
01101 
01102     lastClickedIndex = QPersistentModelIndex();
01103 }
01104 
01105 void KFilePlacesView::Private::_k_adaptItemsUpdate(qreal value)
01106 {
01107     int add = (endSize-oldSize)*value;
01108 
01109     int size = oldSize+add;
01110 
01111     KFilePlacesViewDelegate *delegate = dynamic_cast<KFilePlacesViewDelegate*>(q->itemDelegate());
01112     delegate->setIconSize(size);
01113     q->scheduleDelayedItemsLayout();
01114 }
01115 
01116 void KFilePlacesView::Private::_k_itemAppearUpdate(qreal value)
01117 {
01118     KFilePlacesViewDelegate *delegate = dynamic_cast<KFilePlacesViewDelegate*>(q->itemDelegate());
01119 
01120     delegate->setAppearingItemProgress(value);
01121     q->scheduleDelayedItemsLayout();
01122 }
01123 
01124 void KFilePlacesView::Private::_k_itemDisappearUpdate(qreal value)
01125 {
01126     KFilePlacesViewDelegate *delegate = dynamic_cast<KFilePlacesViewDelegate*>(q->itemDelegate());
01127 
01128     delegate->setDisappearingItemProgress(value);
01129 
01130     if (value>=1.0) {
01131         updateHiddenRows();
01132     }
01133 
01134     q->scheduleDelayedItemsLayout();
01135 }
01136 
01137 void KFilePlacesView::Private::_k_enableSmoothItemResizing()
01138 {
01139     smoothItemResizing = true;
01140 }
01141 
01142 void KFilePlacesView::Private::_k_trashUpdated(KJob *job)
01143 {
01144     if (job->error()) {
01145         static_cast<KIO::Job*>(job)->ui()->showErrorMessage();
01146     }
01147     org::kde::KDirNotify::emitFilesAdded("trash:/");
01148 }
01149 
01150 void KFilePlacesView::Private::_k_capacityBarFadeValueChanged()
01151 {
01152     const QModelIndex index = delegate->indexForFadeAnimation(static_cast<QTimeLine*>(q->sender()));
01153     if (!index.isValid()) {
01154         return;
01155     }
01156     q->update(index);
01157 }
01158 
01159 void KFilePlacesView::Private::_k_triggerDevicePolling()
01160 {
01161     const QModelIndex hoveredIndex = watcher->hoveredIndex();
01162     if (hoveredIndex.isValid()) {
01163         const KFilePlacesModel *placesModel = static_cast<const KFilePlacesModel*>(hoveredIndex.model());
01164         if (placesModel->isDevice(hoveredIndex)) {
01165             q->update(hoveredIndex);
01166         }
01167     }
01168     const QModelIndex focusedIndex = watcher->focusedIndex();
01169     if (focusedIndex.isValid() && focusedIndex != hoveredIndex) {
01170         const KFilePlacesModel *placesModel = static_cast<const KFilePlacesModel*>(focusedIndex.model());
01171         if (placesModel->isDevice(focusedIndex)) {
01172             q->update(focusedIndex);
01173         }
01174     }
01175 }
01176 
01177 void KFilePlacesView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
01178 {
01179     QListView::dataChanged(topLeft, bottomRight);
01180     d->adaptItemSize();
01181 }
01182 
01183 #include "kfileplacesview.moc"
01184 #include "kfileplacesview_p.moc"

KFile

Skip menu "KFile"
  • Main Page
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • 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
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
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