#include <KComponentData>
#include <KDebug>
#include <KIcon>
+#include <kprotocolinfo.h>
#include <KLocale>
#include <KStandardDirs>
#include <KUser>
#include <views/viewproperties.h>
#ifdef HAVE_NEPOMUK
- #include <Nepomuk/ResourceManager>
- #include <Nepomuk/Query/ComparisonTerm>
- #include <Nepomuk/Query/LiteralTerm>
- #include <Nepomuk/Query/Query>
- #include <Nepomuk/Query/ResourceTypeTerm>
- #include <Nepomuk/Vocabulary/NFO>
- #include <Nepomuk/Vocabulary/NIE>
+ #include <Nepomuk2/ResourceManager>
+ #include <Nepomuk2/Query/ComparisonTerm>
+ #include <Nepomuk2/Query/LiteralTerm>
+ #include <Nepomuk2/Query/FileQuery>
+ #include <Nepomuk2/Query/ResourceTypeTerm>
+ #include <Nepomuk2/Vocabulary/NFO>
+ #include <Nepomuk2/Vocabulary/NIE>
#endif
namespace {
PlacesItemModel::PlacesItemModel(QObject* parent) :
KStandardItemModel(parent),
- m_nepomukRunning(false),
+ m_fileIndexingEnabled(false),
m_hiddenItemsShown(false),
m_availableDevices(),
m_predicate(),
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());
+ Nepomuk2::ResourceManager* rm = Nepomuk2::ResourceManager::instance();
+ connect(rm, SIGNAL(nepomukSystemStarted()), this, SLOT(slotNepomukStarted()));
+ connect(rm, SIGNAL(nepomukSystemStopped()), this, SLOT(slotNepomukStopped()));
+
+ if (rm->initialized()) {
+ KConfig config("nepomukserverrc");
+ m_fileIndexingEnabled = config.group("Service-nepomukfileindexer").readEntry("autostart", true);
+ }
+
#endif
const QString file = KStandardDirs::locateLocal("data", "kfileplaces/bookmarks.xml");
m_bookmarkManager = KBookmarkManager::managerForFile(file, "kfilePlaces");
}
}
+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<Solid::StorageAccess>()
+ && !m_storageSetupInProgress.contains(device.as<Solid::StorageAccess>())
+ && !device.as<Solid::StorageAccess>()->isAccessible();
+ if (setup) {
+ Solid::StorageAccess* access = device.as<Solid::StorageAccess>();
+
+ 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<int>& indexes) const
{
KUrl::List urls;
return mimeData;
}
-void PlacesItemModel::dropMimeData(int index, const QMimeData* 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
text = url.host();
}
+ if (url.isLocalFile() && !QFileInfo(url.toLocalFile()).isDir()) {
+ // Only directories are allowed
+ continue;
+ }
+
PlacesItem* newItem = createPlacesItem(text, url);
const int dropIndex = groupedDropIndex(index, newItem);
insertItem(dropIndex, newItem);
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)
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)
}
}
+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) {
+ if (errorData.isValid()) {
+ emit errorMessage(i18nc("@info", "An error occurred while accessing '%1', the system responded: %2",
+ item->text(),
+ errorData.toString()));
+ } else {
+ emit errorMessage(i18nc("@info", "An error occurred while accessing '%1'",
+ item->text()));
+ }
+ emit storageSetupDone(index, false);
+ } else {
+ emit storageSetupDone(index, true);
+ }
+}
+
void PlacesItemModel::hideItem()
{
hideItem(m_hiddenItemToRemove);
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) {
}
if (!found) {
- PlacesItem* item = new PlacesItem(newBookmark);
- if (item->isHidden() && !m_hiddenItemsShown) {
- m_bookmarkedItems.append(item);
- } else {
- appendItemToGroup(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);
+ }
}
}
}
QList<PlacesItem*> devicesItems;
while (!bookmark.isNull()) {
- if (acceptBookmark(bookmark)) {
+ if (acceptBookmark(bookmark, devices)) {
PlacesItem* item = new PlacesItem(bookmark);
if (item->groupType() == PlacesItem::DevicesType) {
devices.remove(item->udi());
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);
}
#endif
}
-bool PlacesItemModel::acceptBookmark(const KBookmark& bookmark) const
+bool PlacesItemModel::acceptBookmark(const KBookmark& bookmark,
+ const QSet<QString>& 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;
}
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) {
}
}
+void PlacesItemModel::clear() {
+ m_bookmarkedItems.clear();
+ KStandardItemModel::clear();
+}
+
+void PlacesItemModel::slotNepomukStarted()
+{
+ KConfig config("nepomukserverrc");
+ m_fileIndexingEnabled = config.group("Service-nepomukfileindexer").readEntry("autostart", true);
+ if (m_fileIndexingEnabled) {
+ m_systemBookmarks.clear();
+ m_systemBookmarksIndexes.clear();
+ createSystemBookmarks();
+
+ clear();
+ loadBookmarks();
+ }
+}
+
+void PlacesItemModel::slotNepomukStopped()
+{
+ if (m_fileIndexingEnabled) {
+ m_fileIndexingEnabled = false;
+
+ m_systemBookmarks.clear();
+ m_systemBookmarksIndexes.clear();
+ createSystemBookmarks();
+
+ clear();
+ loadBookmarks();
+ }
+}
+
+
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();
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;
}
#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);
}
}
#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