KFile
kfileplacesmodel.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) 2007 David Faure <faure@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 #include "kfileplacesmodel.h" 00021 #include "kfileplacesitem_p.h" 00022 #include "kfileplacessharedbookmarks_p.h" 00023 00024 #ifdef Q_OS_WIN 00025 #include "Windows.h" 00026 #include "WinBase.h" 00027 #include <QtCore/QDir> 00028 #endif 00029 00030 #include <QtCore/QMimeData> 00031 #include <QtCore/QTimer> 00032 #include <QtCore/QFile> 00033 #include <QtGui/QColor> 00034 #include <QtGui/QAction> 00035 00036 #include <kfileitem.h> 00037 #include <kglobal.h> 00038 #include <klocale.h> 00039 #include <kuser.h> 00040 #include <kstandarddirs.h> 00041 #include <kcomponentdata.h> 00042 #include <kicon.h> 00043 #include <kmimetype.h> 00044 #include <kdebug.h> 00045 00046 #include <kbookmarkmanager.h> 00047 #include <kbookmark.h> 00048 00049 #include <kio/netaccess.h> 00050 00051 #include <solid/devicenotifier.h> 00052 #include <solid/storageaccess.h> 00053 #include <solid/storagedrive.h> 00054 #include <solid/storagevolume.h> 00055 #include <solid/opticaldrive.h> 00056 #include <solid/opticaldisc.h> 00057 #include <solid/predicate.h> 00058 00059 class KFilePlacesModel::Private 00060 { 00061 public: 00062 Private(KFilePlacesModel *self) : q(self), bookmarkManager(0), sharedBookmarks(0) {} 00063 ~Private() 00064 { 00065 delete sharedBookmarks; 00066 qDeleteAll(items); 00067 } 00068 00069 KFilePlacesModel *q; 00070 00071 QList<KFilePlacesItem*> items; 00072 QSet<QString> availableDevices; 00073 QMap<QObject*, QPersistentModelIndex> setupInProgress; 00074 00075 Solid::Predicate predicate; 00076 KBookmarkManager *bookmarkManager; 00077 KFilePlacesSharedBookmarks * sharedBookmarks; 00078 00079 void reloadAndSignal(); 00080 QList<KFilePlacesItem *> loadBookmarkList(); 00081 00082 void _k_initDeviceList(); 00083 void _k_deviceAdded(const QString &udi); 00084 void _k_deviceRemoved(const QString &udi); 00085 void _k_itemChanged(const QString &udi); 00086 void _k_reloadBookmarks(); 00087 void _k_storageSetupDone(Solid::ErrorType error, QVariant errorData); 00088 void _k_storageTeardownDone(Solid::ErrorType error, QVariant errorData); 00089 }; 00090 00091 KFilePlacesModel::KFilePlacesModel(QObject *parent) 00092 : QAbstractItemModel(parent), d(new Private(this)) 00093 { 00094 const QString file = KStandardDirs::locateLocal("data", "kfileplaces/bookmarks.xml"); 00095 d->bookmarkManager = KBookmarkManager::managerForFile(file, "kfilePlaces"); 00096 00097 // Let's put some places in there if it's empty. We have a corner case here: 00098 // Given you have bookmarked some folders (which have been saved on 00099 // ~/.local/share/user-places.xbel (according to freedesktop bookmarks spec), and 00100 // deleted the home directory ~/.kde, the call managerForFile() will return the 00101 // bookmark manager for the fallback "kfilePlaces", making root.first().isNull() being 00102 // false (you have your own items bookmarked), resulting on only being added your own 00103 // bookmarks, and not the default ones too. So, we also check if kfileplaces/bookmarks.xml 00104 // file exists, and if it doesn't, we also add the default places. (ereslibre) 00105 KBookmarkGroup root = d->bookmarkManager->root(); 00106 if (root.first().isNull() || !QFile::exists(file)) { 00107 00108 // NOTE: The context for these I18N_NOOP2 calls has to be "KFile System Bookmarks". 00109 // The real i18nc call is made later, with this context, so the two must match. 00110 // 00111 // createSystemBookmark actually does nothing with its third argument, 00112 // but we have to give it something so the I18N_NOOP2 calls stay here for now. 00113 // 00114 // (coles, 13th May 2009) 00115 00116 KFilePlacesItem::createSystemBookmark(d->bookmarkManager, 00117 "Home", I18N_NOOP2("KFile System Bookmarks", "Home"), 00118 KUrl(KUser().homeDir()), "user-home"); 00119 KFilePlacesItem::createSystemBookmark(d->bookmarkManager, 00120 "Network", I18N_NOOP2("KFile System Bookmarks", "Network"), 00121 KUrl("remote:/"), "network-workgroup"); 00122 #ifdef Q_OS_WIN 00123 // adding drives 00124 foreach ( const QFileInfo& info, QDir::drives() ) { 00125 #ifndef _WIN32_WCE 00126 uint type = DRIVE_UNKNOWN; 00127 #endif 00128 QString driveIcon = "drive-harddisk"; 00129 #ifndef _WIN32_WCE 00130 QT_WA({ type = GetDriveTypeW((wchar_t *)info.absoluteFilePath().utf16()); }, 00131 { type = GetDriveTypeA(info.absoluteFilePath().toLocal8Bit()); }); 00132 // qDebug() << "drive " << info.absoluteFilePath() << " type: " << type; 00133 switch (type) { 00134 case DRIVE_REMOVABLE: 00135 driveIcon = "drive-removable-media"; 00136 break; 00137 case DRIVE_FIXED: 00138 driveIcon = "drive-harddisk"; 00139 break; 00140 case DRIVE_REMOTE: 00141 driveIcon = "network-server"; 00142 break; 00143 case DRIVE_CDROM: 00144 driveIcon = "drive-optical"; 00145 break; 00146 case DRIVE_RAMDISK: 00147 case DRIVE_UNKNOWN: 00148 case DRIVE_NO_ROOT_DIR: 00149 default: 00150 driveIcon = "drive-harddisk"; 00151 } 00152 #endif 00153 KFilePlacesItem::createSystemBookmark(d->bookmarkManager, 00154 info.absoluteFilePath(), info.absoluteFilePath(), 00155 KUrl(info.absoluteFilePath()), driveIcon); 00156 } 00157 #else 00158 KFilePlacesItem::createSystemBookmark(d->bookmarkManager, 00159 "Root", I18N_NOOP2("KFile System Bookmarks", "Root"), 00160 KUrl("/"), "folder-red"); 00161 #endif 00162 KFilePlacesItem::createSystemBookmark(d->bookmarkManager, 00163 "Trash", I18N_NOOP2("KFile System Bookmarks", "Trash"), 00164 KUrl("trash:/"), "user-trash"); 00165 00166 // Force bookmarks to be saved. If on open/save dialog and the bookmarks are not saved, QFile::exists 00167 // will always return false, which opening/closing all the time the open/save dialog would case the 00168 // bookmarks to be added once each time, having lots of times each bookmark. This forces the defaults 00169 // to be saved on the bookmarks.xml file. Of course, the complete list of bookmarks (those that come from 00170 // user-places.xbel will be filled later). (ereslibre) 00171 d->bookmarkManager->saveAs(file); 00172 } 00173 00174 // create after, so if we have own places, they are added afterwards, in case of equal priorities 00175 d->sharedBookmarks = new KFilePlacesSharedBookmarks(d->bookmarkManager); 00176 00177 d->predicate = Solid::Predicate::fromString( 00178 "[[[[ StorageVolume.ignored == false AND [ StorageVolume.usage == 'FileSystem' OR StorageVolume.usage == 'Encrypted' ]]" 00179 " OR " 00180 "[ IS StorageAccess AND StorageDrive.driveType == 'Floppy' ]]" 00181 " OR " 00182 "OpticalDisc.availableContent & 'Audio' ]" 00183 " OR " 00184 "StorageAccess.ignored == false ]"); 00185 Q_ASSERT(d->predicate.isValid()); 00186 00187 connect(d->bookmarkManager, SIGNAL(changed(const QString&, const QString&)), 00188 this, SLOT(_k_reloadBookmarks())); 00189 connect(d->bookmarkManager, SIGNAL(bookmarksChanged(const QString&)), 00190 this, SLOT(_k_reloadBookmarks())); 00191 00192 d->_k_reloadBookmarks(); 00193 QTimer::singleShot(0, this, SLOT(_k_initDeviceList())); 00194 } 00195 00196 KFilePlacesModel::~KFilePlacesModel() 00197 { 00198 delete d; 00199 } 00200 00201 KUrl KFilePlacesModel::url(const QModelIndex &index) const 00202 { 00203 return KUrl(data(index, UrlRole).toUrl()); 00204 } 00205 00206 bool KFilePlacesModel::setupNeeded(const QModelIndex &index) const 00207 { 00208 return data(index, SetupNeededRole).toBool(); 00209 } 00210 00211 KIcon KFilePlacesModel::icon(const QModelIndex &index) const 00212 { 00213 return KIcon(data(index, Qt::DecorationRole).value<QIcon>()); 00214 } 00215 00216 QString KFilePlacesModel::text(const QModelIndex &index) const 00217 { 00218 return data(index, Qt::DisplayRole).toString(); 00219 } 00220 00221 bool KFilePlacesModel::isHidden(const QModelIndex &index) const 00222 { 00223 return data(index, HiddenRole).toBool(); 00224 } 00225 00226 bool KFilePlacesModel::isDevice(const QModelIndex &index) const 00227 { 00228 if (!index.isValid()) 00229 return false; 00230 00231 KFilePlacesItem *item = static_cast<KFilePlacesItem*>(index.internalPointer()); 00232 00233 return item->isDevice(); 00234 } 00235 00236 Solid::Device KFilePlacesModel::deviceForIndex(const QModelIndex &index) const 00237 { 00238 if (!index.isValid()) 00239 return Solid::Device(); 00240 00241 KFilePlacesItem *item = static_cast<KFilePlacesItem*>(index.internalPointer()); 00242 00243 if (item->isDevice()) { 00244 return item->device(); 00245 } else { 00246 return Solid::Device(); 00247 } 00248 } 00249 00250 KBookmark KFilePlacesModel::bookmarkForIndex(const QModelIndex &index) const 00251 { 00252 if (!index.isValid()) 00253 return KBookmark(); 00254 00255 KFilePlacesItem *item = static_cast<KFilePlacesItem*>(index.internalPointer()); 00256 00257 if (!item->isDevice()) { 00258 return item->bookmark(); 00259 } else { 00260 return KBookmark(); 00261 } 00262 } 00263 00264 QVariant KFilePlacesModel::data(const QModelIndex &index, int role) const 00265 { 00266 if (!index.isValid()) 00267 return QVariant(); 00268 00269 KFilePlacesItem *item = static_cast<KFilePlacesItem*>(index.internalPointer()); 00270 return item->data(role); 00271 } 00272 00273 QModelIndex KFilePlacesModel::index(int row, int column, const QModelIndex &parent) const 00274 { 00275 if (row<0 || column!=0 || row>=d->items.size()) 00276 return QModelIndex(); 00277 00278 if (parent.isValid()) 00279 return QModelIndex(); 00280 00281 return createIndex(row, column, d->items.at(row)); 00282 } 00283 00284 QModelIndex KFilePlacesModel::parent(const QModelIndex &child) const 00285 { 00286 Q_UNUSED(child); 00287 return QModelIndex(); 00288 } 00289 00290 int KFilePlacesModel::rowCount(const QModelIndex &parent) const 00291 { 00292 if (parent.isValid()) 00293 return 0; 00294 else 00295 return d->items.size(); 00296 } 00297 00298 int KFilePlacesModel::columnCount(const QModelIndex &parent) const 00299 { 00300 Q_UNUSED(parent) 00301 // We only know 1 piece of information for a particular entry 00302 return 1; 00303 } 00304 00305 QModelIndex KFilePlacesModel::closestItem(const KUrl &url) const 00306 { 00307 int foundRow = -1; 00308 int maxLength = 0; 00309 00310 // Search the item which is equal to the URL or at least is a parent URL. 00311 // If there are more than one possible item URL candidates, choose the item 00312 // which covers the bigger range of the URL. 00313 for (int row = 0; row<d->items.size(); ++row) { 00314 KFilePlacesItem *item = d->items[row]; 00315 KUrl itemUrl = KUrl(item->data(UrlRole).toUrl()); 00316 00317 if (itemUrl.isParentOf(url)) { 00318 const int length = itemUrl.prettyUrl().length(); 00319 if (length > maxLength) { 00320 foundRow = row; 00321 maxLength = length; 00322 } 00323 } 00324 } 00325 00326 if (foundRow==-1) 00327 return QModelIndex(); 00328 else 00329 return createIndex(foundRow, 0, d->items[foundRow]); 00330 } 00331 00332 void KFilePlacesModel::Private::_k_initDeviceList() 00333 { 00334 Solid::DeviceNotifier *notifier = Solid::DeviceNotifier::instance(); 00335 00336 connect(notifier, SIGNAL(deviceAdded(const QString&)), 00337 q, SLOT(_k_deviceAdded(const QString&))); 00338 connect(notifier, SIGNAL(deviceRemoved(const QString&)), 00339 q, SLOT(_k_deviceRemoved(const QString&))); 00340 00341 const QList<Solid::Device> &deviceList = Solid::Device::listFromQuery(predicate); 00342 00343 foreach(const Solid::Device &device, deviceList) { 00344 availableDevices << device.udi(); 00345 } 00346 00347 _k_reloadBookmarks(); 00348 } 00349 00350 void KFilePlacesModel::Private::_k_deviceAdded(const QString &udi) 00351 { 00352 Solid::Device d(udi); 00353 00354 if (predicate.matches(d)) { 00355 availableDevices << udi; 00356 _k_reloadBookmarks(); 00357 } 00358 } 00359 00360 void KFilePlacesModel::Private::_k_deviceRemoved(const QString &udi) 00361 { 00362 if (availableDevices.contains(udi)) { 00363 availableDevices.remove(udi); 00364 _k_reloadBookmarks(); 00365 } 00366 } 00367 00368 void KFilePlacesModel::Private::_k_itemChanged(const QString &id) 00369 { 00370 for (int row = 0; row<items.size(); ++row) { 00371 if (items.at(row)->id()==id) { 00372 QModelIndex index = q->index(row, 0); 00373 emit q->dataChanged(index, index); 00374 } 00375 } 00376 } 00377 00378 void KFilePlacesModel::Private::_k_reloadBookmarks() 00379 { 00380 QList<KFilePlacesItem*> currentItems = loadBookmarkList(); 00381 00382 QList<KFilePlacesItem*>::Iterator it_i = items.begin(); 00383 QList<KFilePlacesItem*>::Iterator it_c = currentItems.begin(); 00384 00385 QList<KFilePlacesItem*>::Iterator end_i = items.end(); 00386 QList<KFilePlacesItem*>::Iterator end_c = currentItems.end(); 00387 00388 while (it_i!=end_i || it_c!=end_c) { 00389 if (it_i==end_i && it_c!=end_c) { 00390 int row = items.count(); 00391 00392 q->beginInsertRows(QModelIndex(), row, row); 00393 it_i = items.insert(it_i, *it_c); 00394 ++it_i; 00395 it_c = currentItems.erase(it_c); 00396 00397 end_i = items.end(); 00398 end_c = currentItems.end(); 00399 q->endInsertRows(); 00400 00401 } else if (it_i!=end_i && it_c==end_c) { 00402 int row = items.indexOf(*it_i); 00403 00404 q->beginRemoveRows(QModelIndex(), row, row); 00405 delete *it_i; 00406 it_i = items.erase(it_i); 00407 00408 end_i = items.end(); 00409 end_c = currentItems.end(); 00410 q->endRemoveRows(); 00411 00412 } else if ((*it_i)->id()==(*it_c)->id()) { 00413 bool shouldEmit = !((*it_i)->bookmark()==(*it_c)->bookmark()); 00414 (*it_i)->setBookmark((*it_c)->bookmark()); 00415 if (shouldEmit) { 00416 int row = items.indexOf(*it_i); 00417 QModelIndex idx = q->index(row, 0); 00418 emit q->dataChanged(idx, idx); 00419 } 00420 ++it_i; 00421 ++it_c; 00422 } else if ((*it_i)->id()!=(*it_c)->id()) { 00423 int row = items.indexOf(*it_i); 00424 00425 if (it_i+1!=end_i && (*(it_i+1))->id()==(*it_c)->id()) { // if the next one matches, it's a remove 00426 q->beginRemoveRows(QModelIndex(), row, row); 00427 delete *it_i; 00428 it_i = items.erase(it_i); 00429 00430 end_i = items.end(); 00431 end_c = currentItems.end(); 00432 q->endRemoveRows(); 00433 } else { 00434 q->beginInsertRows(QModelIndex(), row, row); 00435 it_i = items.insert(it_i, *it_c); 00436 ++it_i; 00437 it_c = currentItems.erase(it_c); 00438 00439 end_i = items.end(); 00440 end_c = currentItems.end(); 00441 q->endInsertRows(); 00442 } 00443 } 00444 } 00445 00446 qDeleteAll(currentItems); 00447 currentItems.clear(); 00448 } 00449 00450 QList<KFilePlacesItem *> KFilePlacesModel::Private::loadBookmarkList() 00451 { 00452 QList<KFilePlacesItem*> items; 00453 00454 KBookmarkGroup root = bookmarkManager->root(); 00455 KBookmark bookmark = root.first(); 00456 QSet<QString> devices = availableDevices; 00457 00458 while (!bookmark.isNull()) { 00459 QString udi = bookmark.metaDataItem("UDI"); 00460 QString appName = bookmark.metaDataItem("OnlyInApp"); 00461 bool deviceAvailable = devices.remove(udi); 00462 00463 bool allowedHere = appName.isEmpty() || (appName==KGlobal::mainComponent().componentName()); 00464 00465 if ((udi.isEmpty() && allowedHere) || deviceAvailable) { 00466 KFilePlacesItem *item; 00467 if (deviceAvailable) { 00468 item = new KFilePlacesItem(bookmarkManager, bookmark.address(), udi); 00469 // TODO: Update bookmark internal element 00470 } else { 00471 item = new KFilePlacesItem(bookmarkManager, bookmark.address()); 00472 } 00473 connect(item, SIGNAL(itemChanged(const QString&)), 00474 q, SLOT(_k_itemChanged(const QString&))); 00475 items << item; 00476 } 00477 00478 bookmark = root.next(bookmark); 00479 } 00480 00481 // Add bookmarks for the remaining devices, they were previously unknown 00482 foreach (const QString &udi, devices) { 00483 bookmark = KFilePlacesItem::createDeviceBookmark(bookmarkManager, udi); 00484 if (!bookmark.isNull()) { 00485 KFilePlacesItem *item = new KFilePlacesItem(bookmarkManager, 00486 bookmark.address(), udi); 00487 connect(item, SIGNAL(itemChanged(const QString&)), 00488 q, SLOT(_k_itemChanged(const QString&))); 00489 // TODO: Update bookmark internal element 00490 items << item; 00491 } 00492 } 00493 00494 return items; 00495 } 00496 00497 void KFilePlacesModel::Private::reloadAndSignal() 00498 { 00499 bookmarkManager->emitChanged(bookmarkManager->root()); // ... we'll get relisted anyway 00500 } 00501 00502 Qt::DropActions KFilePlacesModel::supportedDropActions() const 00503 { 00504 return Qt::ActionMask; 00505 } 00506 00507 Qt::ItemFlags KFilePlacesModel::flags(const QModelIndex &index) const 00508 { 00509 Qt::ItemFlags res = Qt::ItemIsSelectable|Qt::ItemIsEnabled; 00510 00511 if (index.isValid()) 00512 res|= Qt::ItemIsDragEnabled; 00513 00514 if (!index.isValid()) 00515 res|= Qt::ItemIsDropEnabled; 00516 00517 return res; 00518 } 00519 00520 static QString _k_internalMimetype(const KFilePlacesModel * const self) 00521 { 00522 return QString("application/x-kfileplacesmodel-")+QString::number((qptrdiff)self); 00523 } 00524 00525 QStringList KFilePlacesModel::mimeTypes() const 00526 { 00527 QStringList types; 00528 00529 types << _k_internalMimetype(this) << "text/uri-list"; 00530 00531 return types; 00532 } 00533 00534 QMimeData *KFilePlacesModel::mimeData(const QModelIndexList &indexes) const 00535 { 00536 KUrl::List urls; 00537 QByteArray itemData; 00538 00539 QDataStream stream(&itemData, QIODevice::WriteOnly); 00540 00541 foreach (const QModelIndex &index, indexes) { 00542 KUrl itemUrl = url(index); 00543 if (itemUrl.isValid()) 00544 urls << itemUrl; 00545 stream << index.row(); 00546 } 00547 00548 QMimeData *mimeData = new QMimeData(); 00549 00550 if (!urls.isEmpty()) 00551 urls.populateMimeData(mimeData); 00552 00553 mimeData->setData(_k_internalMimetype(this), itemData); 00554 00555 return mimeData; 00556 } 00557 00558 bool KFilePlacesModel::dropMimeData(const QMimeData *data, Qt::DropAction action, 00559 int row, int column, const QModelIndex &parent) 00560 { 00561 if (action == Qt::IgnoreAction) 00562 return true; 00563 00564 if (column > 0) 00565 return false; 00566 00567 if (row==-1 && parent.isValid()) { 00568 return false; // Don't allow to move an item onto another one, 00569 // too easy for the user to mess something up 00570 // If we really really want to allow copying files this way, 00571 // let's do it in the views to get the good old drop menu 00572 } 00573 00574 00575 KBookmark afterBookmark; 00576 00577 if (row==-1) { 00578 // The dropped item is moved or added to the last position 00579 00580 KFilePlacesItem *lastItem = d->items.last(); 00581 afterBookmark = lastItem->bookmark(); 00582 00583 } else { 00584 // The dropped item is moved or added before position 'row', ie after position 'row-1' 00585 00586 if (row>0) { 00587 KFilePlacesItem *afterItem = d->items[row-1]; 00588 afterBookmark = afterItem->bookmark(); 00589 } 00590 } 00591 00592 if (data->hasFormat(_k_internalMimetype(this))) { 00593 // The operation is an internal move 00594 QByteArray itemData = data->data(_k_internalMimetype(this)); 00595 QDataStream stream(&itemData, QIODevice::ReadOnly); 00596 int itemRow; 00597 00598 stream >> itemRow; 00599 00600 KFilePlacesItem *item = d->items[itemRow]; 00601 KBookmark bookmark = item->bookmark(); 00602 00603 d->bookmarkManager->root().moveBookmark(bookmark, afterBookmark); 00604 00605 } else if (data->hasFormat("text/uri-list")) { 00606 // The operation is an add 00607 KUrl::List urls = KUrl::List::fromMimeData(data); 00608 00609 KBookmarkGroup group = d->bookmarkManager->root(); 00610 00611 foreach (const KUrl &url, urls) { 00612 KMimeType::Ptr mimetype = KMimeType::mimeType(KIO::NetAccess::mimetype(url, 0)); 00613 00614 if (!mimetype) { 00615 kWarning() << "URL not added to Places as mimetype could not be determined!"; 00616 continue; 00617 } 00618 00619 if (!mimetype->is("inode/directory")) { 00620 // Only directories are allowed 00621 continue; 00622 } 00623 00624 KBookmark bookmark = KFilePlacesItem::createBookmark(d->bookmarkManager, 00625 url.fileName(), url, 00626 mimetype->iconName(url)); 00627 group.moveBookmark(bookmark, afterBookmark); 00628 afterBookmark = bookmark; 00629 } 00630 00631 } else { 00632 // Oops, shouldn't happen thanks to mimeTypes() 00633 kWarning() << ": received wrong mimedata, " << data->formats(); 00634 return false; 00635 } 00636 00637 d->reloadAndSignal(); 00638 00639 return true; 00640 } 00641 00642 void KFilePlacesModel::addPlace(const QString &text, const KUrl &url, 00643 const QString &iconName, const QString &appName) 00644 { 00645 addPlace(text, url, iconName, appName, QModelIndex()); 00646 } 00647 00648 void KFilePlacesModel::addPlace(const QString &text, const KUrl &url, 00649 const QString &iconName, const QString &appName, 00650 const QModelIndex &after) 00651 { 00652 KBookmark bookmark = KFilePlacesItem::createBookmark(d->bookmarkManager, 00653 text, url, iconName); 00654 00655 if (!appName.isEmpty()) { 00656 bookmark.setMetaDataItem("OnlyInApp", appName); 00657 } 00658 00659 if (after.isValid()) { 00660 KFilePlacesItem *item = static_cast<KFilePlacesItem*>(after.internalPointer()); 00661 d->bookmarkManager->root().moveBookmark(bookmark, item->bookmark()); 00662 } 00663 00664 d->reloadAndSignal(); 00665 } 00666 00667 void KFilePlacesModel::editPlace(const QModelIndex &index, const QString &text, const KUrl &url, 00668 const QString &iconName, const QString &appName) 00669 { 00670 if (!index.isValid()) return; 00671 00672 KFilePlacesItem *item = static_cast<KFilePlacesItem*>(index.internalPointer()); 00673 00674 if (item->isDevice()) return; 00675 00676 KBookmark bookmark = item->bookmark(); 00677 00678 if (bookmark.isNull()) return; 00679 00680 bookmark.setFullText(text); 00681 bookmark.setUrl(url); 00682 bookmark.setIcon(iconName); 00683 bookmark.setMetaDataItem("OnlyInApp", appName); 00684 00685 d->reloadAndSignal(); 00686 emit dataChanged(index, index); 00687 } 00688 00689 void KFilePlacesModel::removePlace(const QModelIndex &index) const 00690 { 00691 if (!index.isValid()) return; 00692 00693 KFilePlacesItem *item = static_cast<KFilePlacesItem*>(index.internalPointer()); 00694 00695 if (item->isDevice()) return; 00696 00697 KBookmark bookmark = item->bookmark(); 00698 00699 if (bookmark.isNull()) return; 00700 00701 d->bookmarkManager->root().deleteBookmark(bookmark); 00702 d->reloadAndSignal(); 00703 } 00704 00705 void KFilePlacesModel::setPlaceHidden(const QModelIndex &index, bool hidden) 00706 { 00707 if (!index.isValid()) return; 00708 00709 KFilePlacesItem *item = static_cast<KFilePlacesItem*>(index.internalPointer()); 00710 00711 KBookmark bookmark = item->bookmark(); 00712 00713 if (bookmark.isNull()) return; 00714 00715 bookmark.setMetaDataItem("IsHidden", (hidden ? "true" : "false")); 00716 00717 d->reloadAndSignal(); 00718 emit dataChanged(index, index); 00719 } 00720 00721 int KFilePlacesModel::hiddenCount() const 00722 { 00723 int rows = rowCount(); 00724 int hidden = 0; 00725 00726 for (int i=0; i<rows; ++i) { 00727 if (isHidden(index(i, 0))) { 00728 hidden++; 00729 } 00730 } 00731 00732 return hidden; 00733 } 00734 00735 QAction *KFilePlacesModel::teardownActionForIndex(const QModelIndex &index) const 00736 { 00737 Solid::Device device = deviceForIndex(index); 00738 00739 if (device.is<Solid::StorageAccess>() && device.as<Solid::StorageAccess>()->isAccessible()) { 00740 00741 Solid::StorageDrive *drive = device.as<Solid::StorageDrive>(); 00742 00743 if (drive==0) { 00744 drive = device.parent().as<Solid::StorageDrive>(); 00745 } 00746 00747 bool hotpluggable = false; 00748 bool removable = false; 00749 00750 if (drive!=0) { 00751 hotpluggable = drive->isHotpluggable(); 00752 removable = drive->isRemovable(); 00753 } 00754 00755 QString iconName; 00756 QString text; 00757 QString label = data(index, Qt::DisplayRole).toString().replace('&',"&&"); 00758 00759 if (device.is<Solid::OpticalDisc>()) { 00760 text = i18n("&Release '%1'", label); 00761 } else if (removable || hotpluggable) { 00762 text = i18n("&Safely Remove '%1'", label); 00763 iconName = "media-eject"; 00764 } else { 00765 text = i18n("&Unmount '%1'", label); 00766 iconName = "media-eject"; 00767 } 00768 00769 if (!iconName.isEmpty()) { 00770 return new QAction(KIcon(iconName), text, 0); 00771 } else { 00772 return new QAction(text, 0); 00773 } 00774 } 00775 00776 return 0; 00777 } 00778 00779 QAction *KFilePlacesModel::ejectActionForIndex(const QModelIndex &index) const 00780 { 00781 Solid::Device device = deviceForIndex(index); 00782 00783 if (device.is<Solid::OpticalDisc>()) { 00784 00785 QString label = data(index, Qt::DisplayRole).toString().replace('&',"&&"); 00786 QString text = i18n("&Eject '%1'", label); 00787 00788 return new QAction(KIcon("media-eject"), text, 0); 00789 } 00790 00791 return 0; 00792 } 00793 00794 void KFilePlacesModel::requestTeardown(const QModelIndex &index) 00795 { 00796 Solid::Device device = deviceForIndex(index); 00797 Solid::StorageAccess *access = device.as<Solid::StorageAccess>(); 00798 00799 if (access!=0) { 00800 connect(access, SIGNAL(teardownDone(Solid::ErrorType, QVariant, const QString &)), 00801 this, SLOT(_k_storageTeardownDone(Solid::ErrorType, QVariant))); 00802 00803 access->teardown(); 00804 } 00805 } 00806 00807 void KFilePlacesModel::requestEject(const QModelIndex &index) 00808 { 00809 Solid::Device device = deviceForIndex(index); 00810 00811 Solid::OpticalDrive *drive = device.parent().as<Solid::OpticalDrive>(); 00812 00813 if (drive!=0) { 00814 connect(drive, SIGNAL(ejectDone(Solid::ErrorType, QVariant, const QString &)), 00815 this, SLOT(_k_storageTeardownDone(Solid::ErrorType, QVariant))); 00816 00817 drive->eject(); 00818 } else { 00819 QString label = data(index, Qt::DisplayRole).toString().replace('&',"&&"); 00820 QString message = i18n("The device '%1' is not a disk and cannot be ejected.", label); 00821 emit errorMessage(message); 00822 } 00823 } 00824 00825 void KFilePlacesModel::requestSetup(const QModelIndex &index) 00826 { 00827 Solid::Device device = deviceForIndex(index); 00828 00829 if (device.is<Solid::StorageAccess>() 00830 && !d->setupInProgress.contains(device.as<Solid::StorageAccess>()) 00831 && !device.as<Solid::StorageAccess>()->isAccessible()) { 00832 00833 Solid::StorageAccess *access = device.as<Solid::StorageAccess>(); 00834 00835 d->setupInProgress[access] = index; 00836 00837 connect(access, SIGNAL(setupDone(Solid::ErrorType, QVariant, const QString &)), 00838 this, SLOT(_k_storageSetupDone(Solid::ErrorType, QVariant))); 00839 00840 access->setup(); 00841 } 00842 } 00843 00844 void KFilePlacesModel::Private::_k_storageSetupDone(Solid::ErrorType error, QVariant errorData) 00845 { 00846 QPersistentModelIndex index = setupInProgress.take(q->sender()); 00847 00848 if (!index.isValid()) { 00849 return; 00850 } 00851 00852 if (!error) { 00853 emit q->setupDone(index, true); 00854 } else { 00855 if (errorData.isValid()) { 00856 emit q->errorMessage(i18n("An error occurred while accessing '%1', the system responded: %2", 00857 q->text(index), 00858 errorData.toString())); 00859 } else { 00860 emit q->errorMessage(i18n("An error occurred while accessing '%1'", 00861 q->text(index))); 00862 } 00863 emit q->setupDone(index, false); 00864 } 00865 00866 } 00867 00868 void KFilePlacesModel::Private::_k_storageTeardownDone(Solid::ErrorType error, QVariant errorData) 00869 { 00870 if (error && errorData.isValid()) { 00871 emit q->errorMessage(errorData.toString()); 00872 } 00873 } 00874 00875 #include "kfileplacesmodel.moc"
KDE 4.6 API Reference