00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "kdirmodel.h"
00021 #include "kdirlister.h"
00022 #include "kfileitem.h"
00023 #include <kdatetime.h>
00024 #include <kicon.h>
00025 #include <klocale.h>
00026 #include <kglobal.h>
00027 #include <kio/copyjob.h>
00028 #include <kio/jobuidelegate.h>
00029 #include <kurl.h>
00030 #include <kdebug.h>
00031 #include <QMimeData>
00032 #include <QFile>
00033 #include <QFileInfo>
00034 #include <QDir>
00035 #include <sys/types.h>
00036 #include <dirent.h>
00037
00038 class KDirModelNode;
00039 class KDirModelDirNode;
00040
00041
00042
00043 class KDirModelNode
00044 {
00045 public:
00046 KDirModelNode( KDirModelDirNode* parent, const KFileItem& item ) :
00047 m_item(item),
00048 m_parent(parent),
00049 m_preview()
00050 {
00051 }
00052
00053 const KFileItem& item() const { return m_item; }
00054 void setItem(const KFileItem& item) { m_item = item; }
00055 KDirModelDirNode* parent() const { return m_parent; }
00056
00057 int rowNumber() const;
00058 QIcon preview() const { return m_preview; }
00059 void addPreview( const QPixmap& pix ) { m_preview.addPixmap(pix); }
00060 void setPreview( const QIcon& icn ) { m_preview = icn; }
00061
00062 private:
00063 KFileItem m_item;
00064 KDirModelDirNode* const m_parent;
00065 QIcon m_preview;
00066 };
00067
00068
00069 class KDirModelDirNode : public KDirModelNode
00070 {
00071 public:
00072 KDirModelDirNode( KDirModelDirNode* parent, const KFileItem& item)
00073 : KDirModelNode( parent, item),
00074 m_childNodes(),
00075 m_childCount(KDirModel::ChildCountUnknown),
00076 m_populated(false)
00077 {}
00078 ~KDirModelDirNode() {
00079 qDeleteAll(m_childNodes);
00080 }
00081 QList<KDirModelNode *> m_childNodes;
00082 QHash<QString, KDirModelNode *> m_childNodesByName;
00083
00084
00085 int childCount() const { return m_childNodes.isEmpty() ? m_childCount : m_childNodes.count(); }
00086 void setChildCount(int count) { m_childCount = count; }
00087 bool isPopulated() const { return m_populated; }
00088 void setPopulated( bool populated ) { m_populated = populated; }
00089
00090 private:
00091 int m_childCount:31;
00092 bool m_populated:1;
00093 };
00094
00095 int KDirModelNode::rowNumber() const
00096 {
00097 if (!m_parent) return 0;
00098 return m_parent->m_childNodes.indexOf(const_cast<KDirModelNode*>(this));
00099 }
00100
00102
00103 class KDirModelPrivate
00104 {
00105 public:
00106 KDirModelPrivate( KDirModel* model )
00107 : q(model), m_dirLister(0),
00108 m_rootNode(new KDirModelDirNode(0, KFileItem())),
00109 m_dropsAllowed(KDirModel::NoDrops)
00110 {
00111 }
00112 ~KDirModelPrivate() {
00113 delete m_rootNode;
00114 }
00115
00116 void _k_slotNewItems(const KFileItemList&);
00117 void _k_slotDeleteItems(const KFileItemList&);
00118 void _k_slotRefreshItems(const QList<QPair<KFileItem, KFileItem> >&);
00119 void _k_slotClear();
00120
00121 void clear() {
00122 delete m_rootNode;
00123 m_rootNode = new KDirModelDirNode(0, KFileItem());
00124 }
00125
00126
00127
00128
00129
00130 KDirModelNode* nodeForUrl(const KUrl& url, bool returnLastParent = false) const;
00131 KDirModelNode* nodeForIndex(const QModelIndex& index) const;
00132 QModelIndex indexForNode(KDirModelNode* node, int rowNumber = -1 ) const;
00133 bool isDir(KDirModelNode* node) const {
00134 return (node == m_rootNode) || node->item().isDir();
00135 }
00136 KUrl urlForNode(KDirModelNode* node) const {
00144 KUrl url(node == m_rootNode ? m_dirLister->url() : node->item().url());
00145 if (url.hasQuery() || url.hasRef()) {
00146 url.setQuery(QString());
00147 url.setRef(QString());
00148 }
00149 return url;
00150 }
00151
00152 KDirModel* q;
00153 KDirLister* m_dirLister;
00154 KDirModelDirNode* m_rootNode;
00155 KDirModel::DropsAllowed m_dropsAllowed;
00156
00157
00158 QMap<KDirModelNode*, KUrl::List> m_urlsBeingFetched;
00159 };
00160
00161
00162
00163
00164
00165 KDirModelNode* KDirModelPrivate::nodeForUrl(const KUrl& _url, bool returnLastParent) const
00166 {
00167 KUrl url(_url);
00168 url.adjustPath(KUrl::RemoveTrailingSlash);
00169 url.setQuery(QString());
00170 url.setRef(QString());
00171
00172
00173 KUrl nodeUrl = urlForNode(m_rootNode);
00174
00175
00176
00177
00178
00179 if (nodeUrl.path().isEmpty())
00180 nodeUrl.setPath("/");
00181
00182 if (url == nodeUrl)
00183 return m_rootNode;
00184
00185
00186 if (url.protocol() != nodeUrl.protocol())
00187 return 0;
00188
00189 const QString pathStr = url.path();
00190 KDirModelDirNode* dirNode = m_rootNode;
00191
00192 if (!pathStr.startsWith(nodeUrl.path())) {
00193 return 0;
00194 }
00195
00196 for (;;) {
00197 const QString nodePath = nodeUrl.path(KUrl::AddTrailingSlash);
00198 if(!pathStr.startsWith(nodePath)) {
00199 kError(7008) << "The kioslave for" << url.protocol() << "violates the hierarchy structure:"
00200 << "I arrived at node" << nodePath << ", but" << pathStr << "does not start with that path.";
00201 return 0;
00202 }
00203
00204
00205 const QString relativePath = pathStr.mid(nodePath.length());
00206 Q_ASSERT(!relativePath.startsWith('/'));
00207 const int nextSlash = relativePath.indexOf('/');
00208 const QString fileName = relativePath.left(nextSlash);
00209 KDirModelNode* node = dirNode->m_childNodesByName.value(fileName);
00210 if (!node) {
00211
00212 if (returnLastParent)
00213 return dirNode;
00214 else
00215 return 0;
00216 }
00217 nodeUrl = urlForNode(node);
00218 nodeUrl.adjustPath(KUrl::RemoveTrailingSlash);
00219
00220 if (nodeUrl == url) {
00221
00222 return node;
00223 }
00224
00225 Q_ASSERT(isDir(node));
00226 dirNode = static_cast<KDirModelDirNode *>(node);
00227 }
00228
00229
00230 }
00231
00232
00233 QModelIndex KDirModelPrivate::indexForNode(KDirModelNode* node, int rowNumber) const
00234 {
00235 if (node == m_rootNode)
00236 return QModelIndex();
00237
00238 Q_ASSERT(node->parent());
00239 return q->createIndex(rowNumber == -1 ? node->rowNumber() : rowNumber, 0, node);
00240 }
00241
00242
00243 KDirModelNode* KDirModelPrivate::nodeForIndex(const QModelIndex& index) const
00244 {
00245 return index.isValid()
00246 ? static_cast<KDirModelNode*>(index.internalPointer())
00247 : m_rootNode;
00248 }
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266 #ifndef NDEBUG
00267 static QString debugIndex(const QModelIndex& index)
00268 {
00269 QString str;
00270 if (!index.isValid())
00271 str = "[invalid index, i.e. root]";
00272 else {
00273 KDirModelNode* node = static_cast<KDirModelNode*>(index.internalPointer());
00274 str = "[index for " + node->item().url().pathOrUrl();
00275 if (index.column() > 0)
00276 str += ", column " + QString::number(index.column());
00277 str += ']';
00278 }
00279 return str;
00280 }
00281 #endif
00282
00283 KDirModel::KDirModel(QObject* parent)
00284 : QAbstractItemModel(parent),
00285 d(new KDirModelPrivate(this))
00286 {
00287 setDirLister(new KDirLister(this));
00288 }
00289
00290 KDirModel::~KDirModel()
00291 {
00292 delete d;
00293 }
00294
00295 void KDirModel::setDirLister(KDirLister* dirLister)
00296 {
00297 if (d->m_dirLister) {
00298 d->clear();
00299 delete d->m_dirLister;
00300 }
00301 d->m_dirLister = dirLister;
00302 d->m_dirLister->setParent(this);
00303 connect( d->m_dirLister, SIGNAL(newItems(KFileItemList)),
00304 this, SLOT(_k_slotNewItems(KFileItemList)) );
00305 connect( d->m_dirLister, SIGNAL(itemsDeleted(KFileItemList)),
00306 this, SLOT(_k_slotDeleteItems(KFileItemList)) );
00307 connect( d->m_dirLister, SIGNAL(refreshItems(QList<QPair<KFileItem, KFileItem> >)),
00308 this, SLOT(_k_slotRefreshItems(QList<QPair<KFileItem, KFileItem> >)) );
00309 connect( d->m_dirLister, SIGNAL(clear()),
00310 this, SLOT(_k_slotClear()) );
00311 }
00312
00313 KDirLister* KDirModel::dirLister() const
00314 {
00315 return d->m_dirLister;
00316 }
00317
00318 void KDirModelPrivate::_k_slotNewItems(const KFileItemList& items)
00319 {
00320
00321
00322
00323
00324
00325
00326 KUrl firstItemUrl = items.first().url();
00327 firstItemUrl.setQuery(QString());
00328 firstItemUrl.setRef(QString());
00329 KUrl dir(firstItemUrl);
00330 dir.setPath(dir.directory());
00331
00332
00333
00334 KDirModelNode* result = nodeForUrl(dir);
00335
00336
00337 if (!result) {
00338 kError(7008) << "First item has URL" << firstItemUrl
00339 << "-> parent directory would be" << dir
00340 << "but that directory isn't in KDirModel!"
00341 << "Root directory:" << urlForNode(m_rootNode);
00342 Q_ASSERT(result);
00343 }
00344 Q_ASSERT(isDir(result));
00345 KDirModelDirNode* dirNode = static_cast<KDirModelDirNode *>(result);
00346
00347 const QModelIndex index = indexForNode(dirNode);
00348 const int newItemsCount = items.count();
00349 const int newRowCount = dirNode->m_childNodes.count() + newItemsCount;
00350 #if 0
00351 #ifndef NDEBUG // debugIndex only defined in debug mode
00352 kDebug(7008) << items.count() << "in" << dir
00353 << "index=" << debugIndex(index) << "newRowCount=" << newRowCount;
00354 #endif
00355 #endif
00356 q->beginInsertRows( index, newRowCount - newItemsCount, newRowCount - 1 );
00357
00358 const KUrl::List urlsBeingFetched = m_urlsBeingFetched.value(dirNode);
00359
00360
00361 QList<QModelIndex> emitExpandFor;
00362
00363 KFileItemList::const_iterator it = items.begin();
00364 KFileItemList::const_iterator end = items.end();
00365 for ( ; it != end ; ++it ) {
00366 const bool isDir = it->isDir();
00367 KDirModelNode* node = isDir
00368 ? new KDirModelDirNode( dirNode, *it )
00369 : new KDirModelNode( dirNode, *it );
00370 dirNode->m_childNodes.append(node);
00371 const KUrl url = it->url();
00372 dirNode->m_childNodesByName.insert(url.fileName(), node);
00373
00374
00375 if (isDir && !urlsBeingFetched.isEmpty()) {
00376 const KUrl dirUrl = url;
00377 foreach(const KUrl& urlFetched, urlsBeingFetched) {
00378 if (dirUrl.isParentOf(urlFetched)) {
00379
00380 const QModelIndex parentIndex = indexForNode(node, dirNode->m_childNodes.count()-1);
00381 Q_ASSERT(parentIndex.isValid());
00382 emitExpandFor.append(parentIndex);
00383 if (dirUrl != urlFetched) {
00384 q->fetchMore(parentIndex);
00385 m_urlsBeingFetched[node].append(urlFetched);
00386 }
00387 }
00388 }
00389 }
00390 }
00391
00392 m_urlsBeingFetched.remove(dirNode);
00393
00394 q->endInsertRows();
00395
00396
00397
00398 Q_FOREACH(const QModelIndex& idx, emitExpandFor) {
00399 emit q->expand(idx);
00400 }
00401 }
00402
00403 void KDirModelPrivate::_k_slotDeleteItems(const KFileItemList& items)
00404 {
00405
00406
00407
00408
00409 const KFileItem item = items.first();
00410 Q_ASSERT(!item.isNull());
00411 KUrl url = item.url();
00412 KDirModelNode* node = nodeForUrl(url);
00413 if (!node)
00414 return;
00415
00416 KDirModelDirNode* dirNode = node->parent();
00417 if (!dirNode)
00418 return;
00419
00420 QModelIndex parentIndex = indexForNode(dirNode);
00421
00422
00423 if (items.count() == 1) {
00424 const int r = node->rowNumber();
00425 q->beginRemoveRows(parentIndex, r, r);
00426 delete dirNode->m_childNodes.takeAt(r);
00427 q->endRemoveRows();
00428 Q_ASSERT(dirNode->m_childNodesByName.contains(url.fileName()));
00429 dirNode->m_childNodesByName.remove(url.fileName());
00430 return;
00431 }
00432
00433
00434
00435 const int childCount = dirNode->m_childNodes.count();
00436 QBitArray rowNumbers(childCount, false);
00437 Q_FOREACH(const KFileItem& item, items) {
00438 if (!node) {
00439 url = item.url();
00440 node = nodeForUrl(url);
00441 Q_ASSERT(node);
00442 }
00443 rowNumbers.setBit(node->rowNumber(), 1);
00444 Q_ASSERT(dirNode->m_childNodesByName.contains(url.fileName()));
00445 dirNode->m_childNodesByName.remove(url.fileName());
00446 node = 0;
00447 }
00448
00449 int start = -1;
00450 int end = -1;
00451 bool lastVal = false;
00452
00453 for (int i = childCount - 1; i >= 0; --i) {
00454 const bool val = rowNumbers.testBit(i);
00455 if (!lastVal && val) {
00456 end = i;
00457
00458 }
00459 if ((lastVal && !val) || (i == 0 && val)) {
00460 start = val ? i : i + 1;
00461
00462 q->beginRemoveRows(parentIndex, start, end);
00463 for (int r = end; r >= start; --r) {
00464
00465 delete dirNode->m_childNodes.takeAt(r);
00466 }
00467 q->endRemoveRows();
00468 }
00469 lastVal = val;
00470 }
00471 }
00472
00473 void KDirModelPrivate::_k_slotRefreshItems(const QList<QPair<KFileItem, KFileItem> >& items)
00474 {
00475 QModelIndex topLeft, bottomRight;
00476
00477
00478
00479 for ( QList<QPair<KFileItem, KFileItem> >::const_iterator fit = items.begin(), fend = items.end() ; fit != fend ; ++fit ) {
00480 Q_ASSERT(!fit->first.isNull());
00481 Q_ASSERT(!fit->second.isNull());
00482 const KUrl oldUrl = fit->first.url();
00483 const KUrl newUrl = fit->second.url();
00484 const QModelIndex index = q->indexForUrl(oldUrl);
00485 KDirModelNode* node = nodeForIndex(index);
00486 if (node != m_rootNode) {
00487 node->setItem(fit->second);
00488
00489 if (oldUrl.fileName() != newUrl.fileName()) {
00490 KDirModelDirNode* parentNode = node->parent();
00491 Q_ASSERT(parentNode);
00492 parentNode->m_childNodesByName.remove(oldUrl.fileName());
00493 parentNode->m_childNodesByName.insert(newUrl.fileName(), node);
00494 }
00495 if (!topLeft.isValid() || index.row() < topLeft.row()) {
00496 topLeft = index;
00497 }
00498 if (!bottomRight.isValid() || index.row() > bottomRight.row()) {
00499 bottomRight = index;
00500 }
00501 }
00502 }
00503 #ifndef NDEBUG // debugIndex only defined in debug mode
00504 kDebug(7008) << "slotRefreshItems: dataChanged(" << debugIndex(topLeft) << " - " << debugIndex(bottomRight);
00505 #endif
00506 bottomRight = bottomRight.sibling(bottomRight.row(), q->columnCount(QModelIndex())-1);
00507 emit q->dataChanged(topLeft, bottomRight);
00508 }
00509
00510 void KDirModelPrivate::_k_slotClear()
00511 {
00512 const int numRows = m_rootNode->m_childNodes.count();
00513 q->beginRemoveRows( QModelIndex(), 0, numRows );
00514 q->endRemoveRows();
00515
00516
00517 clear();
00518
00519 }
00520
00521 void KDirModel::itemChanged( const QModelIndex& index )
00522 {
00523 emit dataChanged(index, index);
00524 }
00525
00526 int KDirModel::columnCount( const QModelIndex & ) const
00527 {
00528 return ColumnCount;
00529 }
00530
00531 QVariant KDirModel::data( const QModelIndex & index, int role ) const
00532 {
00533 if (index.isValid()) {
00534 KDirModelNode* node = static_cast<KDirModelNode*>(index.internalPointer());
00535 const KFileItem& item( node->item() );
00536 switch (role) {
00537 case Qt::DisplayRole:
00538 switch (index.column()) {
00539 case Name:
00540 return item.text();
00541 case Size:
00542
00543
00544
00545 return KGlobal::locale()->formatNumber(item.size(), 0);
00546 case ModifiedTime: {
00547 KDateTime dt = item.time(KFileItem::ModificationTime);
00548 return KGlobal::locale()->formatDateTime(dt);
00549 }
00550 case Permissions:
00551 return item.permissionsString();
00552 case Owner:
00553 return item.user();
00554 case Group:
00555 return item.group();
00556 case Type:
00557 return item.mimeComment();
00558 }
00559 break;
00560 case Qt::EditRole:
00561 switch (index.column()) {
00562 case Name:
00563 return item.text();
00564 }
00565 break;
00566 case Qt::DecorationRole:
00567 if (index.column() == Name) {
00568 if (!node->preview().isNull()) {
00569
00570 return node->preview();
00571 }
00572 Q_ASSERT(!item.isNull());
00573
00574 return KIcon(item.iconName(), 0, item.overlays());
00575 }
00576 break;
00577 case Qt::TextAlignmentRole:
00578 if (index.column() == Size) {
00579
00580 const Qt::Alignment alignment = Qt::AlignRight | Qt::AlignVCenter;
00581 return int(alignment);
00582 }
00583 break;
00584 case FileItemRole:
00585 return QVariant::fromValue(item);
00586 case ChildCountRole:
00587 if (!item.isDir())
00588 return ChildCountUnknown;
00589 else {
00590 KDirModelDirNode* dirNode = static_cast<KDirModelDirNode *>(node);
00591 int count = dirNode->childCount();
00592 if (count == ChildCountUnknown && item.isReadable()) {
00593 const QString path = item.localPath();
00594 if (!path.isEmpty()) {
00595 #if 0 // slow
00596 QDir dir(path);
00597 count = dir.entryList(QDir::AllEntries|QDir::NoDotAndDotDot|QDir::System).count();
00598 #else
00599 DIR* dir = ::opendir(QFile::encodeName(path));
00600 if (dir) {
00601 count = 0;
00602 struct dirent *dirEntry = 0;
00603 while ((dirEntry = ::readdir(dir))) {
00604 if (dirEntry->d_name[0] == '.') {
00605 if (dirEntry->d_name[1] == '\0')
00606 continue;
00607 if (dirEntry->d_name[1] == '.' && dirEntry->d_name[2] == '\0')
00608 continue;
00609 }
00610 ++count;
00611 }
00612 ::closedir(dir);
00613 }
00614 #endif
00615
00616 dirNode->setChildCount(count);
00617 }
00618 }
00619 return count;
00620 }
00621 }
00622 }
00623 return QVariant();
00624 }
00625
00626 void KDirModel::sort( int column, Qt::SortOrder order )
00627 {
00628
00629 return QAbstractItemModel::sort(column, order);
00630 }
00631
00632 bool KDirModel::setData( const QModelIndex & index, const QVariant & value, int role )
00633 {
00634 switch (role) {
00635 case Qt::EditRole:
00636 if (index.column() == Name && value.type() == QVariant::String) {
00637 Q_ASSERT(index.isValid());
00638 KDirModelNode* node = static_cast<KDirModelNode*>(index.internalPointer());
00639 const KFileItem& item = node->item();
00640 const QString newName = value.toString();
00641 if (newName.isEmpty() || newName == item.text())
00642 return true;
00643 KUrl newurl(item.url());
00644 newurl.setPath(newurl.directory(KUrl::AppendTrailingSlash) + newName);
00645 KIO::Job * job = KIO::moveAs(item.url(), newurl, newurl.isLocalFile() ? KIO::HideProgressInfo : KIO::DefaultFlags);
00646 job->ui()->setAutoErrorHandlingEnabled(true);
00647
00648 return true;
00649 }
00650 break;
00651 case Qt::DecorationRole:
00652 if (index.column() == Name) {
00653 Q_ASSERT(index.isValid());
00654
00655 KDirModelNode* node = static_cast<KDirModelNode*>(index.internalPointer());
00656
00657 Q_ASSERT(node);
00658 if (value.type() == QVariant::Icon) {
00659 const QIcon icon(qvariant_cast<QIcon>(value));
00660 Q_ASSERT(!icon.isNull());
00661 node->setPreview(icon);
00662 } else if (value.type() == QVariant::Pixmap) {
00663 node->addPreview(qvariant_cast<QPixmap>(value));
00664 }
00665 emit dataChanged(index, index);
00666 return true;
00667 }
00668 break;
00669 default:
00670 break;
00671 }
00672 return false;
00673 }
00674
00675 int KDirModel::rowCount( const QModelIndex & parent ) const
00676 {
00677 KDirModelDirNode* parentNode = static_cast<KDirModelDirNode *>(d->nodeForIndex(parent));
00678 Q_ASSERT(parentNode);
00679 const int count = parentNode->m_childNodes.count();
00680 #if 0
00681 QStringList filenames;
00682 for (int i = 0; i < count; ++i) {
00683 filenames << d->urlForNode(parentNode->m_childNodes.at(i)).fileName();
00684 }
00685 kDebug(7008) << "rowCount for " << d->urlForNode(parentNode) << ": " << count << filenames;
00686 #endif
00687 return count;
00688 }
00689
00690
00691 QModelIndex KDirModel::parent( const QModelIndex & index ) const
00692 {
00693 if (!index.isValid())
00694 return QModelIndex();
00695 KDirModelNode* childNode = static_cast<KDirModelNode*>(index.internalPointer());
00696 Q_ASSERT(childNode);
00697 KDirModelNode* parentNode = childNode->parent();
00698 Q_ASSERT(parentNode);
00699 return d->indexForNode(parentNode);
00700 }
00701
00702 QStringList KDirModel::mimeTypes( ) const
00703 {
00704 return QStringList() << QLatin1String("text/uri-list")
00705 << QLatin1String( "application/x-kde-cutselection" )
00706 << QLatin1String( "text/plain" )
00707 << QLatin1String( "application/x-kde-urilist" );
00708 }
00709
00710 QMimeData * KDirModel::mimeData( const QModelIndexList & indexes ) const
00711 {
00712 KUrl::List urls;
00713 foreach ( const QModelIndex &index, indexes ) {
00714 urls << d->nodeForIndex( index )->item().url();
00715 }
00716 QMimeData *data = new QMimeData();
00717 urls.populateMimeData( data );
00718 return data;
00719 }
00720
00721
00722 KFileItem KDirModel::itemForIndex( const QModelIndex& index ) const
00723 {
00724 if (!index.isValid()) {
00725 return d->m_dirLister->rootItem();
00726 } else {
00727 return static_cast<KDirModelNode*>(index.internalPointer())->item();
00728 }
00729 }
00730
00731 QModelIndex KDirModel::indexForItem( const KFileItem* item ) const
00732 {
00733
00734
00735 return indexForUrl(item->url());
00736 }
00737
00738 QModelIndex KDirModel::indexForItem( const KFileItem& item ) const
00739 {
00740
00741
00742 return indexForUrl(item.url());
00743 }
00744
00745
00746 QModelIndex KDirModel::indexForUrl(const KUrl& url) const
00747 {
00748 KDirModelNode* node = d->nodeForUrl(url);
00749 if (!node) {
00750 kDebug(7007) << url << "not found";
00751 return QModelIndex();
00752 }
00753 return d->indexForNode(node);
00754 }
00755
00756 QModelIndex KDirModel::index( int row, int column, const QModelIndex & parent ) const
00757 {
00758 KDirModelNode* parentNode = d->nodeForIndex(parent);
00759 Q_ASSERT(parentNode);
00760 Q_ASSERT(d->isDir(parentNode));
00761 KDirModelNode* childNode = static_cast<KDirModelDirNode *>(parentNode)->m_childNodes.value(row);
00762 if (childNode)
00763 return createIndex(row, column, childNode);
00764 else
00765 return QModelIndex();
00766 }
00767
00768 QVariant KDirModel::headerData( int section, Qt::Orientation orientation, int role ) const
00769 {
00770 Q_UNUSED(orientation);
00771 switch (role) {
00772 case Qt::DisplayRole:
00773 switch (section) {
00774 case Name:
00775 return i18nc("@title:column","Name");
00776 case Size:
00777 return i18nc("@title:column","Size");
00778 case ModifiedTime:
00779 return i18nc("@title:column","Date");
00780 case Permissions:
00781 return i18nc("@title:column","Permissions");
00782 case Owner:
00783 return i18nc("@title:column","Owner");
00784 case Group:
00785 return i18nc("@title:column","Group");
00786 case Type:
00787 return i18nc("@title:column","Type");
00788 }
00789 }
00790 return QVariant();
00791 }
00792
00793 bool KDirModel::hasChildren( const QModelIndex & parent ) const
00794 {
00795 if (!parent.isValid())
00796 return true;
00797
00798 const KFileItem& parentItem = static_cast<KDirModelNode*>(parent.internalPointer())->item();
00799 Q_ASSERT(!parentItem.isNull());
00800 return parentItem.isDir();
00801 }
00802
00803 Qt::ItemFlags KDirModel::flags( const QModelIndex & index ) const
00804 {
00805 Qt::ItemFlags f = Qt::ItemIsEnabled;
00806 if (index.column() == Name) {
00807 f |= Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsDragEnabled;
00808 }
00809
00810
00811 if (d->m_dropsAllowed != NoDrops) {
00812 if(!index.isValid()) {
00813 if (d->m_dropsAllowed & DropOnDirectory) {
00814 f |= Qt::ItemIsDropEnabled;
00815 }
00816 } else {
00817 KFileItem item = itemForIndex(index);
00818 if (item.isNull()) {
00819 kWarning(7007) << "Invalid item returned for index";
00820 } else if (item.isDir()) {
00821 if (d->m_dropsAllowed & DropOnDirectory) {
00822 f |= Qt::ItemIsDropEnabled;
00823 }
00824 } else {
00825 if (d->m_dropsAllowed & DropOnAnyFile)
00826 f |= Qt::ItemIsDropEnabled;
00827 else if (d->m_dropsAllowed & DropOnLocalExecutable) {
00828 if (item.isLocalFile()) {
00829
00830 if (item.mimeTypePtr()->is("application/x-desktop"))
00831 f |= Qt::ItemIsDropEnabled;
00832
00833 else if ( QFileInfo( item.localPath() ).isExecutable() )
00834 f |= Qt::ItemIsDropEnabled;
00835 }
00836 }
00837 }
00838 }
00839 }
00840
00841 return f;
00842 }
00843
00844 bool KDirModel::canFetchMore( const QModelIndex & parent ) const
00845 {
00846 if (!parent.isValid())
00847 return false;
00848
00849
00850
00851
00852
00853
00854 KDirModelNode* node = static_cast<KDirModelNode*>(parent.internalPointer());
00855 const KFileItem& item = node->item();
00856 return item.isDir() && !static_cast<KDirModelDirNode *>(node)->isPopulated()
00857 && static_cast<KDirModelDirNode *>(node)->m_childNodes.isEmpty();
00858 }
00859
00860 void KDirModel::fetchMore( const QModelIndex & parent )
00861 {
00862 if (!parent.isValid())
00863 return;
00864
00865 KDirModelNode* parentNode = static_cast<KDirModelNode*>(parent.internalPointer());
00866
00867 KFileItem parentItem = parentNode->item();
00868 Q_ASSERT(!parentItem.isNull());
00869 Q_ASSERT(parentItem.isDir());
00870 KDirModelDirNode* dirNode = static_cast<KDirModelDirNode *>(parentNode);
00871 if( dirNode->isPopulated() )
00872 return;
00873 dirNode->setPopulated( true );
00874
00875 const KUrl parentUrl = parentItem.url();
00876 d->m_dirLister->openUrl(parentUrl, KDirLister::Keep);
00877 }
00878
00879 bool KDirModel::dropMimeData( const QMimeData * data, Qt::DropAction action, int row, int column, const QModelIndex & parent )
00880 {
00881
00882
00883 Q_UNUSED(data);
00884 Q_UNUSED(action);
00885 Q_UNUSED(row);
00886 Q_UNUSED(column);
00887 Q_UNUSED(parent);
00888 return false;
00889 }
00890
00891 void KDirModel::setDropsAllowed(DropsAllowed dropsAllowed)
00892 {
00893 d->m_dropsAllowed = dropsAllowed;
00894 }
00895
00896 void KDirModel::expandToUrl(const KUrl& url)
00897 {
00898 KDirModelNode* result = d->nodeForUrl(url, true );
00899
00900 if (!result)
00901 return;
00902 if (!(result->item().isNull()) && result->item().url() == url) {
00903
00904 kDebug(7008) << "have it already item=" <<url ;
00905 return;
00906 }
00907
00908 d->m_urlsBeingFetched[result].append(url);
00909
00910 if (result == d->m_rootNode) {
00911 kDebug(7008) << "Remembering to emit expand after listing the root url";
00912
00913 return;
00914 }
00915
00916 kDebug(7008) << "Remembering to emit expand after listing" << result->item().url();
00917
00918
00919 const QModelIndex parentIndex = d->indexForNode(result);
00920 Q_ASSERT(parentIndex.isValid());
00921 fetchMore(parentIndex);
00922 }
00923
00924 bool KDirModel::insertRows(int , int, const QModelIndex&)
00925 {
00926 return false;
00927 }
00928
00929 bool KDirModel::insertColumns(int, int, const QModelIndex&)
00930 {
00931 return false;
00932 }
00933
00934 bool KDirModel::removeRows(int, int, const QModelIndex&)
00935 {
00936 return false;
00937 }
00938
00939 bool KDirModel::removeColumns(int, int, const QModelIndex&)
00940 {
00941 return false;
00942 }
00943
00944 #include "kdirmodel.moc"