X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/blobdiff_plain/894232ebda5b2cf155a4f4e5bf1287eb700faa18..1353c92cce7ebc805b51d90f0bbb0c95dca0f2cb:/src/panels/places/placesitemmodel.cpp diff --git a/src/panels/places/placesitemmodel.cpp b/src/panels/places/placesitemmodel.cpp index 2a3dfa441..a37c17fd8 100644 --- a/src/panels/places/placesitemmodel.cpp +++ b/src/panels/places/placesitemmodel.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -51,13 +52,13 @@ #include #ifdef HAVE_NEPOMUK - #include - #include - #include - #include - #include - #include - #include + #include + #include + #include + #include + #include + #include + #include #endif namespace { @@ -73,7 +74,7 @@ namespace { PlacesItemModel::PlacesItemModel(QObject* parent) : KStandardItemModel(parent), - m_nepomukRunning(false), + m_fileIndexingEnabled(false), m_hiddenItemsShown(false), m_availableDevices(), m_predicate(), @@ -83,10 +84,15 @@ PlacesItemModel::PlacesItemModel(QObject* parent) : m_bookmarkedItems(), m_hiddenItemToRemove(-1), m_saveBookmarksTimer(0), - m_updateBookmarksTimer(0) + m_updateBookmarksTimer(0), + m_storageSetupInProgress() { #ifdef HAVE_NEPOMUK - m_nepomukRunning = (Nepomuk::ResourceManager::instance()->initialized()); + if (Nepomuk2::ResourceManager::instance()->initialized()) { + KConfig config("nepomukserverrc"); + m_fileIndexingEnabled = config.group("Service-nepomukfileindexer").readEntry("autostart", false); + } + #endif const QString file = KStandardDirs::locateLocal("data", "kfileplaces/bookmarks.xml"); m_bookmarkManager = KBookmarkManager::managerForFile(file, "kfilePlaces"); @@ -95,7 +101,7 @@ PlacesItemModel::PlacesItemModel(QObject* parent) : initializeAvailableDevices(); loadBookmarks(); - const int syncBookmarksTimeout = 1000; + const int syncBookmarksTimeout = 100; m_saveBookmarksTimer = new QTimer(this); m_saveBookmarksTimer->setInterval(syncBookmarksTimeout); @@ -226,6 +232,32 @@ int PlacesItemModel::closestItem(const KUrl& url) const return foundIndex; } +void PlacesItemModel::appendItemToGroup(PlacesItem* item) +{ + if (!item) { + return; + } + + int i = 0; + while (i < count() && placesItem(i)->group() != item->group()) { + ++i; + } + + bool inserted = false; + while (!inserted && i < count()) { + if (placesItem(i)->group() != item->group()) { + insertItem(i, item); + inserted = true; + } + ++i; + } + + if (!inserted) { + appendItem(item); + } +} + + QAction* PlacesItemModel::ejectAction(int index) const { const PlacesItem* item = placesItem(index); @@ -312,6 +344,35 @@ void PlacesItemModel::requestTeardown(int index) } } +bool PlacesItemModel::storageSetupNeeded(int index) const +{ + const PlacesItem* item = placesItem(index); + return item ? item->storageSetupNeeded() : false; +} + +void PlacesItemModel::requestStorageSetup(int index) +{ + const PlacesItem* item = placesItem(index); + if (!item) { + return; + } + + Solid::Device device = item->device(); + const bool setup = device.is() + && !m_storageSetupInProgress.contains(device.as()) + && !device.as()->isAccessible(); + if (setup) { + Solid::StorageAccess* access = device.as(); + + m_storageSetupInProgress[access] = index; + + connect(access, SIGNAL(setupDone(Solid::ErrorType,QVariant,QString)), + this, SLOT(slotStorageSetupDone(Solid::ErrorType,QVariant,QString))); + + access->setup(); + } +} + QMimeData* PlacesItemModel::createMimeData(const QSet& indexes) const { KUrl::List urls; @@ -331,14 +392,61 @@ QMimeData* PlacesItemModel::createMimeData(const QSet& indexes) const if (!urls.isEmpty()) { urls.populateMimeData(mimeData); } - - const QString internalMimeType = "application/x-dolphinplacesmodel-" + - QString::number((qptrdiff)this); - mimeData->setData(internalMimeType, itemData); + mimeData->setData(internalMimeType(), itemData); return mimeData; } +bool PlacesItemModel::supportsDropping(int index) const +{ + return index >= 0 && index < count(); +} + +void PlacesItemModel::dropMimeDataBefore(int index, const QMimeData* mimeData) +{ + if (mimeData->hasFormat(internalMimeType())) { + // The item has been moved inside the view + QByteArray itemData = mimeData->data(internalMimeType()); + QDataStream stream(&itemData, QIODevice::ReadOnly); + int oldIndex; + stream >> oldIndex; + if (oldIndex == index || oldIndex == index - 1) { + // No moving has been done + return; + } + + PlacesItem* oldItem = placesItem(oldIndex); + if (!oldItem) { + return; + } + + PlacesItem* newItem = new PlacesItem(oldItem->bookmark()); + removeItem(oldIndex); + + if (oldIndex < index) { + --index; + } + + const int dropIndex = groupedDropIndex(index, newItem); + insertItem(dropIndex, newItem); + } else if (mimeData->hasFormat("text/uri-list")) { + // One or more items must be added to the model + const KUrl::List urls = KUrl::List::fromMimeData(mimeData); + for (int i = urls.count() - 1; i >= 0; --i) { + const KUrl& url = urls[i]; + + QString text = url.fileName(); + if (text.isEmpty()) { + text = url.host(); + } + + PlacesItem* newItem = createPlacesItem(text, url); + const int dropIndex = groupedDropIndex(index, newItem); + insertItem(dropIndex, newItem); + } + } +} + KUrl PlacesItemModel::convertedUrl(const KUrl& url) { KUrl newUrl = url; @@ -447,11 +555,14 @@ void PlacesItemModel::onItemChanged(int index, const QSet& changedRo void PlacesItemModel::slotDeviceAdded(const QString& udi) { const Solid::Device device(udi); - if (m_predicate.matches(device)) { - m_availableDevices << udi; - const KBookmark bookmark = PlacesItem::createDeviceBookmark(m_bookmarkManager, udi); - appendItem(new PlacesItem(bookmark)); + + if (!m_predicate.matches(device)) { + return; } + + m_availableDevices << udi; + const KBookmark bookmark = PlacesItem::createDeviceBookmark(m_bookmarkManager, udi); + appendItem(new PlacesItem(bookmark)); } void PlacesItemModel::slotDeviceRemoved(const QString& udi) @@ -467,14 +578,14 @@ void PlacesItemModel::slotDeviceRemoved(const QString& udi) delete item; return; } - } + } - for (int i = 0; i < count(); ++i) { - if (placesItem(i)->udi() == udi) { - removeItem(i); - return; - } - } + for (int i = 0; i < count(); ++i) { + if (placesItem(i)->udi() == udi) { + removeItem(i); + return; + } + } } void PlacesItemModel::slotStorageTeardownDone(Solid::ErrorType error, const QVariant& errorData) @@ -484,6 +595,37 @@ void PlacesItemModel::slotStorageTeardownDone(Solid::ErrorType error, const QVar } } +void PlacesItemModel::slotStorageSetupDone(Solid::ErrorType error, + const QVariant& errorData, + const QString& udi) +{ + Q_UNUSED(udi); + + const int index = m_storageSetupInProgress.take(sender()); + const PlacesItem* item = placesItem(index); + if (!item) { + return; + } + + if (error) { + // TODO: Request message-freeze exception + if (errorData.isValid()) { + // emit errorMessage(i18nc("@info", "An error occurred while accessing '%1', the system responded: %2", + // item->text(), + // errorData.toString())); + emit errorMessage(QString("An error occurred while accessing '%1', the system responded: %2") + .arg(item->text()).arg(errorData.toString())); + } else { + // emit errorMessage(i18nc("@info", "An error occurred while accessing '%1'", + // item->text())); + emit errorMessage(QString("An error occurred while accessing '%1'").arg(item->text())); + } + emit storageSetupDone(index, false); + } else { + emit storageSetupDone(index, true); + } +} + void PlacesItemModel::hideItem() { hideItem(m_hiddenItemToRemove); @@ -497,7 +639,7 @@ void PlacesItemModel::updateBookmarks() KBookmarkGroup root = m_bookmarkManager->root(); KBookmark newBookmark = root.first(); while (!newBookmark.isNull()) { - if (acceptBookmark(newBookmark)) { + if (acceptBookmark(newBookmark, m_availableDevices)) { bool found = false; int modelIndex = 0; for (int i = 0; i < m_bookmarkedItems.count(); ++i) { @@ -521,11 +663,22 @@ void PlacesItemModel::updateBookmarks() } if (!found) { - PlacesItem* item = new PlacesItem(newBookmark); - if (item->isHidden() && !m_hiddenItemsShown) { - m_bookmarkedItems.append(item); - } else { - appendItem(item); + const QString udi = newBookmark.metaDataItem("UDI"); + + /* + * See Bug 304878 + * Only add a new places item, if the item text is not empty + * and if the device is available. Fixes the strange behaviour - + * add a places item without text in the Places section - when you + * remove a device (e.g. a usb stick) without unmounting. + */ + if (udi.isEmpty() || Solid::Device(udi).isValid()) { + PlacesItem* item = new PlacesItem(newBookmark); + if (item->isHidden() && !m_hiddenItemsShown) { + m_bookmarkedItems.append(item); + } else { + appendItemToGroup(item); + } } } } @@ -595,20 +748,22 @@ void PlacesItemModel::loadBookmarks() QList devicesItems; while (!bookmark.isNull()) { - const bool deviceAvailable = devices.remove(bookmark.metaDataItem("UDI")); - if (acceptBookmark(bookmark)) { + if (acceptBookmark(bookmark, devices)) { PlacesItem* item = new PlacesItem(bookmark); - if (deviceAvailable) { + if (item->groupType() == PlacesItem::DevicesType) { + devices.remove(item->udi()); devicesItems.append(item); } else { const KUrl url = bookmark.url(); if (missingSystemBookmarks.contains(url)) { missingSystemBookmarks.remove(url); - // Apply the translated text to the system bookmarks, otherwise an outdated - // translation might be shown. - const int index = m_systemBookmarksIndexes.value(url); - item->setText(m_systemBookmarks[index].text); + // Try to retranslate the text of system bookmarks to have translated + // items when changing the language. In case if the user has applied a custom + // text, the retranslation will fail and the users custom text is still used. + // It is important to use "KFile System Bookmarks" as context (see + // createSystemBookmarks()). + item->setText(i18nc("KFile System Bookmarks", bookmark.text().toUtf8().data())); item->setSystemItem(true); } @@ -668,18 +823,19 @@ void PlacesItemModel::loadBookmarks() #endif } -bool PlacesItemModel::acceptBookmark(const KBookmark& bookmark) const +bool PlacesItemModel::acceptBookmark(const KBookmark& bookmark, + const QSet& availableDevices) const { const QString udi = bookmark.metaDataItem("UDI"); const KUrl url = bookmark.url(); const QString appName = bookmark.metaDataItem("OnlyInApp"); - const bool deviceAvailable = m_availableDevices.contains(udi); + const bool deviceAvailable = availableDevices.contains(udi); const bool allowedHere = (appName.isEmpty() || appName == KGlobal::mainComponent().componentName() || appName == KGlobal::mainComponent().componentName() + AppNamePrefix) - && (m_nepomukRunning || (url.protocol() != QLatin1String("timeline") && - url.protocol() != QLatin1String("search"))); + && (m_fileIndexingEnabled || (url.protocol() != QLatin1String("timeline") && + url.protocol() != QLatin1String("search"))); return (udi.isEmpty() && allowedHere) || deviceAvailable; } @@ -744,47 +900,48 @@ void PlacesItemModel::createSystemBookmarks() Q_ASSERT(m_systemBookmarks.isEmpty()); Q_ASSERT(m_systemBookmarksIndexes.isEmpty()); - const QString timeLineIcon = "package_utility_time"; // TODO: Ask the Oxygen team to create - // a custom icon for the timeline-protocol - + // Note: The context of the I18N_NOOP2 must be "KFile System Bookmarks". The real + // i18nc call is done after reading the bookmark. The reason why the i18nc call is not + // done here is because otherwise switching the language would not result in retranslating the + // bookmarks. m_systemBookmarks.append(SystemBookmarkData(KUrl(KUser().homeDir()), "user-home", - i18nc("@item", "Home"))); + I18N_NOOP2("KFile System Bookmarks", "Home"))); m_systemBookmarks.append(SystemBookmarkData(KUrl("remote:/"), "network-workgroup", - i18nc("@item", "Network"))); + I18N_NOOP2("KFile System Bookmarks", "Network"))); m_systemBookmarks.append(SystemBookmarkData(KUrl("/"), "folder-red", - i18nc("@item", "Root"))); + I18N_NOOP2("KFile System Bookmarks", "Root"))); m_systemBookmarks.append(SystemBookmarkData(KUrl("trash:/"), "user-trash", - i18nc("@item", "Trash"))); + I18N_NOOP2("KFile System Bookmarks", "Trash"))); - if (m_nepomukRunning) { + if (m_fileIndexingEnabled) { m_systemBookmarks.append(SystemBookmarkData(KUrl("timeline:/today"), - timeLineIcon, - i18nc("@item Recently Accessed", "Today"))); + "go-jump-today", + I18N_NOOP2("KFile System Bookmarks", "Today"))); m_systemBookmarks.append(SystemBookmarkData(KUrl("timeline:/yesterday"), - timeLineIcon, - i18nc("@item Recently Accessed", "Yesterday"))); + "view-calendar-day", + I18N_NOOP2("KFile System Bookmarks", "Yesterday"))); m_systemBookmarks.append(SystemBookmarkData(KUrl("timeline:/thismonth"), - timeLineIcon, - i18nc("@item Recently Accessed", "This Month"))); + "view-calendar-month", + I18N_NOOP2("KFile System Bookmarks", "This Month"))); m_systemBookmarks.append(SystemBookmarkData(KUrl("timeline:/lastmonth"), - timeLineIcon, - i18nc("@item Recently Accessed", "Last Month"))); + "view-calendar-month", + I18N_NOOP2("KFile System Bookmarks", "Last Month"))); m_systemBookmarks.append(SystemBookmarkData(KUrl("search:/documents"), "folder-txt", - i18nc("@item Commonly Accessed", "Documents"))); + I18N_NOOP2("KFile System Bookmarks", "Documents"))); m_systemBookmarks.append(SystemBookmarkData(KUrl("search:/images"), "folder-image", - i18nc("@item Commonly Accessed", "Images"))); + I18N_NOOP2("KFile System Bookmarks", "Images"))); m_systemBookmarks.append(SystemBookmarkData(KUrl("search:/audio"), "folder-sound", - i18nc("@item Commonly Accessed", "Audio Files"))); + I18N_NOOP2("KFile System Bookmarks", "Audio Files"))); m_systemBookmarks.append(SystemBookmarkData(KUrl("search:/videos"), "folder-video", - i18nc("@item Commonly Accessed", "Videos"))); + I18N_NOOP2("KFile System Bookmarks", "Videos"))); } for (int i = 0; i < m_systemBookmarks.count(); ++i) { @@ -794,14 +951,21 @@ void PlacesItemModel::createSystemBookmarks() void PlacesItemModel::initializeAvailableDevices() { - m_predicate = Solid::Predicate::fromString( - "[[[[ StorageVolume.ignored == false AND [ StorageVolume.usage == 'FileSystem' OR StorageVolume.usage == 'Encrypted' ]]" + QString predicate("[[[[ StorageVolume.ignored == false AND [ StorageVolume.usage == 'FileSystem' OR StorageVolume.usage == 'Encrypted' ]]" " OR " "[ IS StorageAccess AND StorageDrive.driveType == 'Floppy' ]]" " OR " "OpticalDisc.availableContent & 'Audio' ]" " OR " "StorageAccess.ignored == false ]"); + + + if (KProtocolInfo::isKnownProtocol("mtp")) { + predicate.prepend("["); + predicate.append(" OR PortableMediaPlayer.supportedProtocols == 'mtp']"); + } + + m_predicate = Solid::Predicate::fromString(predicate); Q_ASSERT(m_predicate.isValid()); Solid::DeviceNotifier* notifier = Solid::DeviceNotifier::instance(); @@ -809,7 +973,7 @@ void PlacesItemModel::initializeAvailableDevices() connect(notifier, SIGNAL(deviceRemoved(QString)), this, SLOT(slotDeviceRemoved(QString))); const QList& deviceList = Solid::Device::listFromQuery(m_predicate); - foreach(const Solid::Device& device, deviceList) { + foreach (const Solid::Device& device, deviceList) { m_availableDevices << device.udi(); } } @@ -879,6 +1043,56 @@ void PlacesItemModel::triggerBookmarksSaving() } } +QString PlacesItemModel::internalMimeType() const +{ + return "application/x-dolphinplacesmodel-" + + QString::number((qptrdiff)this); +} + +int PlacesItemModel::groupedDropIndex(int index, const PlacesItem* item) const +{ + Q_ASSERT(item); + + int dropIndex = index; + const PlacesItem::GroupType type = item->groupType(); + + const int itemCount = count(); + if (index < 0) { + dropIndex = itemCount; + } + + // Search nearest previous item with the same group + int previousIndex = -1; + for (int i = dropIndex - 1; i >= 0; --i) { + if (placesItem(i)->groupType() == type) { + previousIndex = i; + break; + } + } + + // Search nearest next item with the same group + int nextIndex = -1; + for (int i = dropIndex; i < count(); ++i) { + if (placesItem(i)->groupType() == type) { + nextIndex = i; + break; + } + } + + // Adjust the drop-index to be inserted to the + // nearest item with the same group. + if (previousIndex >= 0 && nextIndex >= 0) { + dropIndex = (dropIndex - previousIndex < nextIndex - dropIndex) ? + previousIndex + 1 : nextIndex; + } else if (previousIndex >= 0) { + dropIndex = previousIndex + 1; + } else if (nextIndex >= 0) { + dropIndex = nextIndex; + } + + return dropIndex; +} + bool PlacesItemModel::equalBookmarkIdentifiers(const KBookmark& b1, const KBookmark& b2) { const QString udi1 = b1.metaDataItem("UDI"); @@ -898,21 +1112,21 @@ KUrl PlacesItemModel::createTimelineUrl(const KUrl& url) KUrl timelineUrl; const QString path = url.pathOrUrl(); - if (path.endsWith("yesterday")) { + if (path.endsWith(QLatin1String("yesterday"))) { const QDate date = QDate::currentDate().addDays(-1); const int year = date.year(); const int month = date.month(); const int day = date.day(); timelineUrl = "timeline:/" + timelineDateString(year, month) + '/' + timelineDateString(year, month, day); - } else if (path.endsWith("thismonth")) { + } else if (path.endsWith(QLatin1String("thismonth"))) { const QDate date = QDate::currentDate(); timelineUrl = "timeline:/" + timelineDateString(date.year(), date.month()); - } else if (path.endsWith("lastmonth")) { + } else if (path.endsWith(QLatin1String("lastmonth"))) { const QDate date = QDate::currentDate().addMonths(-1); timelineUrl = "timeline:/" + timelineDateString(date.year(), date.month()); } else { - Q_ASSERT(path.endsWith("today")); + Q_ASSERT(path.endsWith(QLatin1String("today"))); timelineUrl= url; } @@ -944,16 +1158,16 @@ KUrl PlacesItemModel::createSearchUrl(const KUrl& url) #ifdef HAVE_NEPOMUK const QString path = url.pathOrUrl(); - if (path.endsWith("documents")) { - searchUrl = searchUrlForTerm(Nepomuk::Query::ResourceTypeTerm(Nepomuk::Vocabulary::NFO::Document())); - } else if (path.endsWith("images")) { - searchUrl = searchUrlForTerm(Nepomuk::Query::ResourceTypeTerm(Nepomuk::Vocabulary::NFO::Image())); - } else if (path.endsWith("audio")) { - searchUrl = searchUrlForTerm(Nepomuk::Query::ComparisonTerm(Nepomuk::Vocabulary::NIE::mimeType(), - Nepomuk::Query::LiteralTerm("audio"))); - } else if (path.endsWith("videos")) { - searchUrl = searchUrlForTerm(Nepomuk::Query::ComparisonTerm(Nepomuk::Vocabulary::NIE::mimeType(), - Nepomuk::Query::LiteralTerm("video"))); + if (path.endsWith(QLatin1String("documents"))) { + searchUrl = searchUrlForTerm(Nepomuk2::Query::ResourceTypeTerm(Nepomuk2::Vocabulary::NFO::Document())); + } else if (path.endsWith(QLatin1String("images"))) { + searchUrl = searchUrlForTerm(Nepomuk2::Query::ResourceTypeTerm(Nepomuk2::Vocabulary::NFO::Image())); + } else if (path.endsWith(QLatin1String("audio"))) { + searchUrl = searchUrlForTerm(Nepomuk2::Query::ComparisonTerm(Nepomuk2::Vocabulary::NIE::mimeType(), + Nepomuk2::Query::LiteralTerm("audio"))); + } else if (path.endsWith(QLatin1String("videos"))) { + searchUrl = searchUrlForTerm(Nepomuk2::Query::ComparisonTerm(Nepomuk2::Vocabulary::NIE::mimeType(), + Nepomuk2::Query::LiteralTerm("video"))); } else { Q_ASSERT(false); } @@ -965,9 +1179,9 @@ KUrl PlacesItemModel::createSearchUrl(const KUrl& url) } #ifdef HAVE_NEPOMUK -KUrl PlacesItemModel::searchUrlForTerm(const Nepomuk::Query::Term& term) +KUrl PlacesItemModel::searchUrlForTerm(const Nepomuk2::Query::Term& term) { - const Nepomuk::Query::Query query(term); + const Nepomuk2::Query::FileQuery query(term); return query.toSearchUrl(); } #endif