2 * SPDX-FileCopyrightText: 2012 Peter Penz <peter.penz19@gmail.com>
4 * Based on KFilePlacesModel from kdelibs:
5 * SPDX-FileCopyrightText: 2007 Kevin Ottens <ervin@kde.org>
6 * SPDX-FileCopyrightText: 2007 David Faure <faure@kde.org>
8 * SPDX-License-Identifier: GPL-2.0-or-later
11 #include "placesitemmodel.h"
13 #include "dolphin_generalsettings.h"
14 #include "dolphindebug.h"
15 #include "dolphinplacesmodelsingleton.h"
16 #include "placesitem.h"
17 #include "placesitemsignalhandler.h"
18 #include "views/dolphinview.h"
19 #include "views/viewproperties.h"
22 #include <KLocalizedString>
23 #include <KUrlMimeData>
24 #include <Solid/DeviceNotifier>
25 #include <Solid/OpticalDrive>
26 #include <KCoreAddons/KProcessList>
27 #include <KCoreAddons/KListOpenFilesJob>
34 PlacesItemModel::PlacesItemModel(QObject
* parent
) :
35 KStandardItemModel(parent
),
36 m_hiddenItemsShown(false),
37 m_deviceToTearDown(nullptr),
38 m_storageSetupInProgress(),
39 m_sourceModel(DolphinPlacesModelSingleton::instance().placesModel())
43 initializeDefaultViewProperties();
45 connect(m_sourceModel
, &KFilePlacesModel::rowsInserted
, this, &PlacesItemModel::onSourceModelRowsInserted
);
46 connect(m_sourceModel
, &KFilePlacesModel::rowsAboutToBeRemoved
, this, &PlacesItemModel::onSourceModelRowsAboutToBeRemoved
);
47 connect(m_sourceModel
, &KFilePlacesModel::dataChanged
, this, &PlacesItemModel::onSourceModelDataChanged
);
48 connect(m_sourceModel
, &KFilePlacesModel::rowsAboutToBeMoved
, this, &PlacesItemModel::onSourceModelRowsAboutToBeMoved
);
49 connect(m_sourceModel
, &KFilePlacesModel::rowsMoved
, this, &PlacesItemModel::onSourceModelRowsMoved
);
50 connect(m_sourceModel
, &KFilePlacesModel::groupHiddenChanged
, this, &PlacesItemModel::onSourceModelGroupHiddenChanged
);
53 PlacesItemModel::~PlacesItemModel()
57 void PlacesItemModel::createPlacesItem(const QString
&text
, const QUrl
&url
, const QString
&iconName
, const QString
&appName
)
59 createPlacesItem(text
, url
, iconName
, appName
, -1);
62 void PlacesItemModel::createPlacesItem(const QString
&text
, const QUrl
&url
, const QString
&iconName
, const QString
&appName
, int after
)
64 m_sourceModel
->addPlace(text
, url
, iconName
, appName
, mapToSource(after
));
67 PlacesItem
* PlacesItemModel::placesItem(int index
) const
69 return dynamic_cast<PlacesItem
*>(item(index
));
72 int PlacesItemModel::hiddenCount() const
74 return m_sourceModel
->hiddenCount();
77 void PlacesItemModel::setHiddenItemsShown(bool show
)
79 if (m_hiddenItemsShown
== show
) {
83 m_hiddenItemsShown
= show
;
86 for (int r
= 0, rMax
= m_sourceModel
->rowCount(); r
< rMax
; r
++) {
87 const QModelIndex index
= m_sourceModel
->index(r
, 0);
88 if (!m_sourceModel
->isHidden(index
)) {
91 addItemFromSourceModel(index
);
94 for (int r
= 0, rMax
= m_sourceModel
->rowCount(); r
< rMax
; r
++) {
95 const QModelIndex index
= m_sourceModel
->index(r
, 0);
96 if (m_sourceModel
->isHidden(index
)) {
97 removeItemByIndex(index
);
103 bool PlacesItemModel::hiddenItemsShown() const
105 return m_hiddenItemsShown
;
108 int PlacesItemModel::closestItem(const QUrl
& url
) const
110 return mapFromSource(m_sourceModel
->closestItem(url
));
113 // look for the correct position for the item based on source model
114 void PlacesItemModel::insertSortedItem(PlacesItem
* item
)
120 const KBookmark iBookmark
= item
->bookmark();
121 const QString iBookmarkId
= bookmarkId(iBookmark
);
122 QModelIndex sourceIndex
;
125 for(int r
= 0, rMax
= m_sourceModel
->rowCount(); r
< rMax
; r
++) {
126 sourceIndex
= m_sourceModel
->index(r
, 0);
127 const KBookmark sourceBookmark
= m_sourceModel
->bookmarkForIndex(sourceIndex
);
129 if (bookmarkId(sourceBookmark
) == iBookmarkId
) {
133 if (m_hiddenItemsShown
|| !m_sourceModel
->isHidden(sourceIndex
)) {
138 m_indexMap
.insert(pos
, sourceIndex
);
139 insertItem(pos
, item
);
142 void PlacesItemModel::onItemInserted(int index
)
144 KStandardItemModel::onItemInserted(index
);
147 void PlacesItemModel::onItemRemoved(int index
, KStandardItem
* removedItem
)
149 m_indexMap
.removeAt(index
);
151 KStandardItemModel::onItemRemoved(index
, removedItem
);
154 void PlacesItemModel::onItemChanged(int index
, const QSet
<QByteArray
>& changedRoles
)
156 const QModelIndex sourceIndex
= mapToSource(index
);
157 const PlacesItem
*changedItem
= placesItem(mapFromSource(sourceIndex
));
159 if (!changedItem
|| !sourceIndex
.isValid()) {
160 qWarning() << "invalid item changed signal";
163 if (changedRoles
.contains("isHidden")) {
164 if (m_sourceModel
->isHidden(sourceIndex
) != changedItem
->isHidden()) {
165 m_sourceModel
->setPlaceHidden(sourceIndex
, changedItem
->isHidden());
167 m_sourceModel
->refresh();
170 KStandardItemModel::onItemChanged(index
, changedRoles
);
173 QAction
* PlacesItemModel::ejectAction(int index
) const
175 const PlacesItem
* item
= placesItem(index
);
176 if (item
&& item
->device().is
<Solid::OpticalDisc
>()) {
177 return new QAction(QIcon::fromTheme(QStringLiteral("media-eject")), i18nc("@item", "Eject"), nullptr);
183 QAction
* PlacesItemModel::teardownAction(int index
) const
185 const PlacesItem
* item
= placesItem(index
);
190 Solid::Device device
= item
->device();
191 const bool providesTearDown
= device
.is
<Solid::StorageAccess
>() &&
192 device
.as
<Solid::StorageAccess
>()->isAccessible();
193 if (!providesTearDown
) {
197 Solid::StorageDrive
* drive
= device
.as
<Solid::StorageDrive
>();
199 drive
= device
.parent().as
<Solid::StorageDrive
>();
202 bool hotPluggable
= false;
203 bool removable
= false;
205 hotPluggable
= drive
->isHotpluggable();
206 removable
= drive
->isRemovable();
211 if (device
.is
<Solid::OpticalDisc
>()) {
212 text
= i18nc("@item", "Release");
213 } else if (removable
|| hotPluggable
) {
214 text
= i18nc("@item", "Safely Remove");
215 iconName
= QStringLiteral("media-eject");
217 text
= i18nc("@item", "Unmount");
218 iconName
= QStringLiteral("media-eject");
221 if (iconName
.isEmpty()) {
222 return new QAction(text
, nullptr);
225 return new QAction(QIcon::fromTheme(iconName
), text
, nullptr);
228 void PlacesItemModel::requestEject(int index
)
230 const PlacesItem
* item
= placesItem(index
);
232 Solid::OpticalDrive
* drive
= item
->device().parent().as
<Solid::OpticalDrive
>();
234 connect(drive
, &Solid::OpticalDrive::ejectDone
,
235 this, &PlacesItemModel::slotStorageTearDownDone
);
238 const QString label
= item
->text();
239 const QString message
= i18nc("@info", "The device '%1' is not a disk and cannot be ejected.", label
);
240 Q_EMIT
errorMessage(message
);
245 void PlacesItemModel::requestTearDown(int index
)
247 const PlacesItem
* item
= placesItem(index
);
249 Solid::StorageAccess
*tmp
= item
->device().as
<Solid::StorageAccess
>();
251 m_deviceToTearDown
= tmp
;
252 // disconnect the Solid::StorageAccess::teardownRequested
253 // to prevent emitting PlacesItemModel::storageTearDownExternallyRequested
254 // after we have emitted PlacesItemModel::storageTearDownRequested
255 disconnect(tmp
, &Solid::StorageAccess::teardownRequested
,
256 item
->signalHandler(), &PlacesItemSignalHandler::onTearDownRequested
);
257 Q_EMIT
storageTearDownRequested(tmp
->filePath());
262 bool PlacesItemModel::storageSetupNeeded(int index
) const
264 const PlacesItem
* item
= placesItem(index
);
265 return item
? item
->storageSetupNeeded() : false;
268 void PlacesItemModel::requestStorageSetup(int index
)
270 const PlacesItem
* item
= placesItem(index
);
275 Solid::Device device
= item
->device();
276 const bool setup
= device
.is
<Solid::StorageAccess
>()
277 && !m_storageSetupInProgress
.contains(device
.as
<Solid::StorageAccess
>())
278 && !device
.as
<Solid::StorageAccess
>()->isAccessible();
280 Solid::StorageAccess
* access
= device
.as
<Solid::StorageAccess
>();
282 m_storageSetupInProgress
[access
] = index
;
284 connect(access
, &Solid::StorageAccess::setupDone
,
285 this, &PlacesItemModel::slotStorageSetupDone
);
291 QMimeData
* PlacesItemModel::createMimeData(const KItemSet
& indexes
) const
296 QDataStream
stream(&itemData
, QIODevice::WriteOnly
);
298 for (int index
: indexes
) {
299 const QUrl itemUrl
= placesItem(index
)->url();
300 if (itemUrl
.isValid()) {
306 QMimeData
* mimeData
= new QMimeData();
307 if (!urls
.isEmpty()) {
308 mimeData
->setUrls(urls
);
310 // #378954: prevent itemDropEvent() drops if there isn't a source url.
311 mimeData
->setData(blacklistItemDropEventMimeType(), QByteArrayLiteral("true"));
313 mimeData
->setData(internalMimeType(), itemData
);
318 bool PlacesItemModel::supportsDropping(int index
) const
320 return index
>= 0 && index
< count();
323 void PlacesItemModel::dropMimeDataBefore(int index
, const QMimeData
* mimeData
)
325 if (mimeData
->hasFormat(internalMimeType())) {
326 // The item has been moved inside the view
327 QByteArray itemData
= mimeData
->data(internalMimeType());
328 QDataStream
stream(&itemData
, QIODevice::ReadOnly
);
332 QModelIndex sourceIndex
= mapToSource(index
);
333 QModelIndex oldSourceIndex
= mapToSource(oldIndex
);
335 m_sourceModel
->movePlace(oldSourceIndex
.row(), sourceIndex
.row());
336 } else if (mimeData
->hasFormat(QStringLiteral("text/uri-list"))) {
337 // One or more items must be added to the model
338 const QList
<QUrl
> urls
= KUrlMimeData::urlsFromMimeData(mimeData
);
339 for (int i
= urls
.count() - 1; i
>= 0; --i
) {
340 const QUrl
& url
= urls
[i
];
342 QString text
= url
.fileName();
343 if (text
.isEmpty()) {
347 if ((url
.isLocalFile() && !QFileInfo(url
.toLocalFile()).isDir())
348 || url
.scheme() == QLatin1String("trash")) {
349 // Only directories outside the trash are allowed
353 createPlacesItem(text
, url
, KIO::iconNameForUrl(url
), {}, qMax(0, index
- 1));
356 // will save bookmark alteration and fix sort if that is broken by the drag/drop operation
360 void PlacesItemModel::addItemFromSourceModel(const QModelIndex
&index
)
362 if (!m_hiddenItemsShown
&& m_sourceModel
->isHidden(index
)) {
366 const KBookmark bookmark
= m_sourceModel
->bookmarkForIndex(index
);
367 Q_ASSERT(!bookmark
.isNull());
368 PlacesItem
*item
= new PlacesItem(bookmark
);
369 updateItem(item
, index
);
370 insertSortedItem(item
);
372 if (m_sourceModel
->isDevice(index
)) {
373 connect(item
->signalHandler(), &PlacesItemSignalHandler::tearDownExternallyRequested
,
374 this, &PlacesItemModel::storageTearDownExternallyRequested
);
378 void PlacesItemModel::removeItemByIndex(const QModelIndex
&sourceIndex
)
380 QString id
= bookmarkId(m_sourceModel
->bookmarkForIndex(sourceIndex
));
382 for (int i
= 0, iMax
= count(); i
< iMax
; ++i
) {
383 if (bookmarkId(placesItem(i
)->bookmark()) == id
) {
390 QString
PlacesItemModel::bookmarkId(const KBookmark
&bookmark
) const
392 QString id
= bookmark
.metaDataItem(QStringLiteral("UDI"));
394 id
= bookmark
.metaDataItem(QStringLiteral("ID"));
399 void PlacesItemModel::initializeDefaultViewProperties() const
401 for(int i
= 0, iMax
= m_sourceModel
->rowCount(); i
< iMax
; i
++) {
402 const QModelIndex index
= m_sourceModel
->index(i
, 0);
403 const PlacesItem
*item
= placesItem(mapFromSource(index
));
408 // Create default view-properties for all "Search For" and "Recently Saved" bookmarks
409 // in case the user has not already created custom view-properties for a corresponding
411 const bool createDefaultViewProperties
= item
->isSearchOrTimelineUrl() && !GeneralSettings::self()->globalViewProps();
412 if (createDefaultViewProperties
) {
413 const QUrl itemUrl
= item
->url();
414 ViewProperties
props(KFilePlacesModel::convertedUrl(itemUrl
));
415 if (!props
.exist()) {
416 const QString path
= itemUrl
.path();
417 if (path
== QLatin1String("/documents")) {
418 props
.setViewMode(DolphinView::DetailsView
);
419 props
.setPreviewsShown(false);
420 props
.setVisibleRoles({"text", "path"});
421 } else if (path
== QLatin1String("/images")) {
422 props
.setViewMode(DolphinView::IconsView
);
423 props
.setPreviewsShown(true);
424 props
.setVisibleRoles({"text", "height", "width"});
425 } else if (path
== QLatin1String("/audio")) {
426 props
.setViewMode(DolphinView::DetailsView
);
427 props
.setPreviewsShown(false);
428 props
.setVisibleRoles({"text", "artist", "album"});
429 } else if (path
== QLatin1String("/videos")) {
430 props
.setViewMode(DolphinView::IconsView
);
431 props
.setPreviewsShown(true);
432 props
.setVisibleRoles({"text"});
433 } else if (itemUrl
.scheme() == QLatin1String("timeline")) {
434 props
.setViewMode(DolphinView::DetailsView
);
435 props
.setVisibleRoles({"text", "modificationtime"});
443 void PlacesItemModel::updateItem(PlacesItem
*item
, const QModelIndex
&index
)
445 item
->setGroup(index
.data(KFilePlacesModel::GroupRole
).toString());
446 item
->setIcon(index
.data(KFilePlacesModel::IconNameRole
).toString());
447 item
->setGroupHidden(index
.data(KFilePlacesModel::GroupHiddenRole
).toBool());
450 void PlacesItemModel::slotStorageTearDownDone(Solid::ErrorType error
, const QVariant
& errorData
)
452 if (error
&& errorData
.isValid()) {
453 if (error
== Solid::ErrorType::DeviceBusy
) {
454 KListOpenFilesJob
* listOpenFilesJob
= new KListOpenFilesJob(m_deviceToTearDown
->filePath());
455 connect(listOpenFilesJob
, &KIO::Job::result
, this, [this, listOpenFilesJob
](KJob
*) {
456 const KProcessList::KProcessInfoList blockingProcesses
= listOpenFilesJob
->processInfoList();
458 if (blockingProcesses
.isEmpty()) {
459 errorString
= i18n("One or more files on this device are open within an application.");
461 QStringList blockingApps
;
462 for (const auto& process
: blockingProcesses
) {
463 blockingApps
<< process
.name();
465 blockingApps
.removeDuplicates();
466 errorString
= xi18np("One or more files on this device are opened in application <application>\"%2\"</application>.",
467 "One or more files on this device are opened in following applications: <application>%2</application>.",
468 blockingApps
.count(), blockingApps
.join(i18nc("separator in list of apps blocking device unmount", ", ")));
470 Q_EMIT
errorMessage(errorString
);
472 listOpenFilesJob
->start();
474 Q_EMIT
errorMessage(errorData
.toString());
477 // No error; it must have been unmounted successfully
478 Q_EMIT
storageTearDownSuccessful();
480 disconnect(m_deviceToTearDown
, &Solid::StorageAccess::teardownDone
,
481 this, &PlacesItemModel::slotStorageTearDownDone
);
482 m_deviceToTearDown
= nullptr;
485 void PlacesItemModel::slotStorageSetupDone(Solid::ErrorType error
,
486 const QVariant
& errorData
,
491 const int index
= m_storageSetupInProgress
.take(sender());
492 const PlacesItem
* item
= placesItem(index
);
497 if (error
!= Solid::NoError
) {
498 if (errorData
.isValid()) {
499 Q_EMIT
errorMessage(i18nc("@info", "An error occurred while accessing '%1', the system responded: %2",
501 errorData
.toString()));
503 Q_EMIT
errorMessage(i18nc("@info", "An error occurred while accessing '%1'",
506 Q_EMIT
storageSetupDone(index
, false);
508 Q_EMIT
storageSetupDone(index
, true);
512 void PlacesItemModel::onSourceModelRowsInserted(const QModelIndex
&parent
, int first
, int last
)
514 for (int i
= first
; i
<= last
; i
++) {
515 const QModelIndex index
= m_sourceModel
->index(i
, 0, parent
);
516 addItemFromSourceModel(index
);
520 void PlacesItemModel::onSourceModelRowsAboutToBeRemoved(const QModelIndex
&parent
, int first
, int last
)
522 for(int r
= first
; r
<= last
; r
++) {
523 const QModelIndex index
= m_sourceModel
->index(r
, 0, parent
);
524 int oldIndex
= mapFromSource(index
);
525 if (oldIndex
!= -1) {
526 removeItem(oldIndex
);
531 void PlacesItemModel::onSourceModelRowsAboutToBeMoved(const QModelIndex
&parent
, int start
, int end
, const QModelIndex
&destination
, int row
)
533 Q_UNUSED(destination
)
536 for(int r
= start
; r
<= end
; r
++) {
537 const QModelIndex sourceIndex
= m_sourceModel
->index(r
, 0, parent
);
539 removeItem(mapFromSource(sourceIndex
));
543 void PlacesItemModel::onSourceModelRowsMoved(const QModelIndex
&parent
, int start
, int end
, const QModelIndex
&destination
, int row
)
545 Q_UNUSED(destination
)
548 const int blockSize
= (end
- start
) + 1;
550 for (int r
= start
; r
<= end
; r
++) {
551 // insert the moved item in the new position
552 const int targetRow
= row
+ (start
- r
) - (r
< row
? blockSize
: 0);
553 const QModelIndex targetIndex
= m_sourceModel
->index(targetRow
, 0, destination
);
555 addItemFromSourceModel(targetIndex
);
559 void PlacesItemModel::onSourceModelDataChanged(const QModelIndex
&topLeft
, const QModelIndex
&bottomRight
, const QVector
<int> &roles
)
563 for (int r
= topLeft
.row(); r
<= bottomRight
.row(); r
++) {
564 const QModelIndex sourceIndex
= m_sourceModel
->index(r
, 0);
565 const KBookmark bookmark
= m_sourceModel
->bookmarkForIndex(sourceIndex
);
566 PlacesItem
*placeItem
= itemFromBookmark(bookmark
);
568 if (placeItem
&& (!m_hiddenItemsShown
&& m_sourceModel
->isHidden(sourceIndex
))) {
569 //hide item if it became invisible
570 removeItem(index(placeItem
));
574 if (!placeItem
&& (m_hiddenItemsShown
|| !m_sourceModel
->isHidden(sourceIndex
))) {
575 //show item if it became visible
576 addItemFromSourceModel(sourceIndex
);
580 if (placeItem
&& !m_sourceModel
->isDevice(sourceIndex
)) {
581 // must update the bookmark object
582 placeItem
->setBookmark(bookmark
);
587 void PlacesItemModel::onSourceModelGroupHiddenChanged(KFilePlacesModel::GroupType group
, bool hidden
)
589 const auto groupIndexes
= m_sourceModel
->groupIndexes(group
);
590 for (const QModelIndex
&sourceIndex
: groupIndexes
) {
591 PlacesItem
*item
= placesItem(mapFromSource(sourceIndex
));
593 item
->setGroupHidden(hidden
);
598 void PlacesItemModel::cleanupBookmarks()
600 // KIO model now provides support for baloo urls, and because of that we
601 // need to remove old URLs that were visible only in Dolphin to avoid duplication
603 static const QVector
<QUrl
> balooURLs
= {
604 QUrl(QStringLiteral("timeline:/today")),
605 QUrl(QStringLiteral("timeline:/yesterday")),
606 QUrl(QStringLiteral("timeline:/thismonth")),
607 QUrl(QStringLiteral("timeline:/lastmonth")),
608 QUrl(QStringLiteral("search:/documents")),
609 QUrl(QStringLiteral("search:/images")),
610 QUrl(QStringLiteral("search:/audio")),
611 QUrl(QStringLiteral("search:/videos"))
616 const QModelIndex sourceIndex
= m_sourceModel
->index(row
, 0);
617 const KBookmark bookmark
= m_sourceModel
->bookmarkForIndex(sourceIndex
);
618 const QUrl url
= bookmark
.url();
619 const QString appName
= bookmark
.metaDataItem(QStringLiteral("OnlyInApp"));
621 if ((appName
== KAboutData::applicationData().componentName() ||
622 appName
== KAboutData::applicationData().componentName() + DolphinPlacesModelSingleton::applicationNameSuffix()) && balooURLs
.contains(url
)) {
623 qCDebug(DolphinDebug
) << "Removing old baloo url:" << url
;
624 m_sourceModel
->removePlace(sourceIndex
);
628 } while (row
< m_sourceModel
->rowCount());
631 void PlacesItemModel::loadBookmarks()
633 for(int r
= 0, rMax
= m_sourceModel
->rowCount(); r
< rMax
; r
++) {
634 const QModelIndex sourceIndex
= m_sourceModel
->index(r
, 0);
635 if (m_hiddenItemsShown
|| !m_sourceModel
->isHidden(sourceIndex
)) {
636 addItemFromSourceModel(sourceIndex
);
641 void PlacesItemModel::clear() {
642 KStandardItemModel::clear();
645 void PlacesItemModel::proceedWithTearDown()
647 Q_ASSERT(m_deviceToTearDown
);
649 connect(m_deviceToTearDown
, &Solid::StorageAccess::teardownDone
,
650 this, &PlacesItemModel::slotStorageTearDownDone
);
651 m_deviceToTearDown
->teardown();
654 void PlacesItemModel::deleteItem(int index
)
656 QModelIndex sourceIndex
= mapToSource(index
);
657 Q_ASSERT(sourceIndex
.isValid());
658 m_sourceModel
->removePlace(sourceIndex
);
661 void PlacesItemModel::refresh()
663 m_sourceModel
->refresh();
666 void PlacesItemModel::hideItem(int index
)
668 PlacesItem
* shownItem
= placesItem(index
);
673 shownItem
->setHidden(true);
676 QString
PlacesItemModel::internalMimeType() const
678 return "application/x-dolphinplacesmodel-" +
679 QString::number((qptrdiff
)this);
682 int PlacesItemModel::groupedDropIndex(int index
, const PlacesItem
* item
) const
686 int dropIndex
= index
;
687 const QString group
= item
->group();
689 const int itemCount
= count();
691 dropIndex
= itemCount
;
694 // Search nearest previous item with the same group
695 int previousIndex
= -1;
696 for (int i
= dropIndex
- 1; i
>= 0; --i
) {
697 if (placesItem(i
)->group() == group
) {
703 // Search nearest next item with the same group
705 for (int i
= dropIndex
; i
< count(); ++i
) {
706 if (placesItem(i
)->group() == group
) {
712 // Adjust the drop-index to be inserted to the
713 // nearest item with the same group.
714 if (previousIndex
>= 0 && nextIndex
>= 0) {
715 dropIndex
= (dropIndex
- previousIndex
< nextIndex
- dropIndex
) ?
716 previousIndex
+ 1 : nextIndex
;
717 } else if (previousIndex
>= 0) {
718 dropIndex
= previousIndex
+ 1;
719 } else if (nextIndex
>= 0) {
720 dropIndex
= nextIndex
;
726 bool PlacesItemModel::equalBookmarkIdentifiers(const KBookmark
& b1
, const KBookmark
& b2
)
728 const QString udi1
= b1
.metaDataItem(QStringLiteral("UDI"));
729 const QString udi2
= b2
.metaDataItem(QStringLiteral("UDI"));
730 if (!udi1
.isEmpty() && !udi2
.isEmpty()) {
733 return b1
.metaDataItem(QStringLiteral("ID")) == b2
.metaDataItem(QStringLiteral("ID"));
737 int PlacesItemModel::mapFromSource(const QModelIndex
&index
) const
739 if (!index
.isValid()) {
743 return m_indexMap
.indexOf(index
);
746 bool PlacesItemModel::isDir(int index
) const
752 KFilePlacesModel::GroupType
PlacesItemModel::groupType(int row
) const
754 return m_sourceModel
->groupType(mapToSource(row
));
757 bool PlacesItemModel::isGroupHidden(KFilePlacesModel::GroupType type
) const
759 return m_sourceModel
->isGroupHidden(type
);
762 void PlacesItemModel::setGroupHidden(KFilePlacesModel::GroupType type
, bool hidden
)
764 return m_sourceModel
->setGroupHidden(type
, hidden
);
767 QModelIndex
PlacesItemModel::mapToSource(int row
) const
769 return m_indexMap
.value(row
);
772 PlacesItem
*PlacesItemModel::itemFromBookmark(const KBookmark
&bookmark
) const
774 const QString id
= bookmarkId(bookmark
);
775 for (int i
= 0, iMax
= count(); i
< iMax
; i
++) {
776 PlacesItem
*item
= placesItem(i
);
777 const KBookmark itemBookmark
= item
->bookmark();
778 if (bookmarkId(itemBookmark
) == id
) {