1
0
mirror of https://invent.kde.org/system/dolphin synced 2024-07-04 17:30:55 +00:00

Use Kio::KPlacesModel as source model for PlacesItemModel

Summary:
Use Kio::KPlacesModel as source model for PlacesItemModel avoiding
duplicated code.

Depends on D8862
Depends on D8332
Depends on D8434
Depends on D8348
Depends on D8630

Test Plan: Unit test created

Reviewers: elvisangelaccio, emmanuelp, mlaurent, mwolff

Reviewed By: elvisangelaccio, mlaurent, mwolff

Subscribers: mwolff, mlaurent, anthonyfieroni, nicolasfella, ngraham, #dolphin

Differential Revision: https://phabricator.kde.org/D8855
This commit is contained in:
Renato Araujo Oliveira Filho 2017-11-16 12:32:49 -03:00
parent 8cea647ce1
commit da6f8fe086
10 changed files with 684 additions and 1066 deletions

View File

@ -8,7 +8,7 @@ set (KDE_APPLICATIONS_VERSION "${KDE_APPLICATIONS_VERSION_MAJOR}.${KDE_APPLICATI
project(Dolphin VERSION ${KDE_APPLICATIONS_VERSION})
set(QT_MIN_VERSION "5.5.0")
set(KF5_MIN_VERSION "5.40.0")
set(KF5_MIN_VERSION "5.41.0")
set(ECM_MIN_VERSION "1.6.0")
# ECM setup

View File

@ -306,9 +306,7 @@ void DolphinContextMenu::openItemContextMenu()
if (selectedUrl.isValid()) {
PlacesItemModel model;
const QString text = selectedUrl.fileName();
PlacesItem* item = model.createPlacesItem(text, selectedUrl, KIO::iconNameForUrl(selectedUrl));
model.appendItemToGroup(item);
model.saveBookmarks();
model.createPlacesItem(text, selectedUrl, KIO::iconNameForUrl(selectedUrl));
}
} else if (activatedAction == openParentAction) {
m_command = OpenParentFolder;
@ -378,9 +376,7 @@ void DolphinContextMenu::openViewportContextMenu()
} else {
icon = KIO::iconNameForUrl(url);
}
PlacesItem* item = model.createPlacesItem(container->placesText(), url, icon);
model.appendItemToGroup(item);
model.saveBookmarks();
model.createPlacesItem(container->placesText(), url, icon);
}
}
}

View File

@ -2373,7 +2373,7 @@ bool KFileItemModel::isConsistent() const
return false;
}
for (int i = 0; i < count(); ++i) {
for (int i = 0, iMax = count(); i < iMax; ++i) {
// Check if m_items and m_itemData are consistent.
const KFileItem item = fileItem(i);
if (item.isNull()) {

View File

@ -130,35 +130,16 @@ void PlacesItem::setBookmark(const KBookmark& bookmark)
delete m_disc;
delete m_mtp;
const QString udi = bookmark.metaDataItem(QStringLiteral("UDI"));
if (udi.isEmpty()) {
setIcon(bookmark.icon());
setText(i18nc("KFile System Bookmarks", bookmark.text().toUtf8().constData()));
setUrl(bookmark.url());
setSystemItem(bookmark.metaDataItem(QStringLiteral("isSystemItem")) == QLatin1String("true"));
} else {
initializeDevice(udi);
}
const GroupType type = groupType();
if (icon().isEmpty()) {
switch (type) {
case RecentlySavedType: setIcon(QStringLiteral("chronometer")); break;
case SearchForType: setIcon(QStringLiteral("system-search")); break;
case PlacesType:
default: setIcon(QStringLiteral("folder"));
}
}
switch (type) {
case PlacesType: setGroup(i18nc("@item", "Places")); break;
case RecentlySavedType: setGroup(i18nc("@item", "Recently Saved")); break;
case SearchForType: setGroup(i18nc("@item", "Search For")); break;
case DevicesType: setGroup(i18nc("@item", "Devices")); break;
default: Q_ASSERT(false); break;
}
setHidden(bookmark.metaDataItem(QStringLiteral("IsHidden")) == QLatin1String("true"));
}
@ -167,62 +148,15 @@ KBookmark PlacesItem::bookmark() const
return m_bookmark;
}
PlacesItem::GroupType PlacesItem::groupType() const
{
if (udi().isEmpty()) {
const QString protocol = url().scheme();
if (protocol == QLatin1String("timeline")) {
return RecentlySavedType;
}
if (protocol.contains(QLatin1String("search"))) {
return SearchForType;
}
if (protocol == QLatin1String("bluetooth") || protocol == QLatin1String("obexftp") || protocol == QLatin1String("kdeconnect")) {
return DevicesType;
}
return PlacesType;
}
return DevicesType;
}
bool PlacesItem::storageSetupNeeded() const
{
return m_access ? !m_access->isAccessible() : false;
}
KBookmark PlacesItem::createBookmark(KBookmarkManager* manager,
const QString& text,
const QUrl& url,
const QString& iconName)
bool PlacesItem::isSearchOrTimelineUrl() const
{
KBookmarkGroup root = manager->root();
if (root.isNull()) {
return KBookmark();
}
KBookmark bookmark = root.addBookmark(text, url, iconName);
bookmark.setFullText(text);
bookmark.setMetaDataItem(QStringLiteral("ID"), generateNewId());
return bookmark;
}
KBookmark PlacesItem::createDeviceBookmark(KBookmarkManager* manager,
const QString& udi)
{
KBookmarkGroup root = manager->root();
if (root.isNull()) {
return KBookmark();
}
KBookmark bookmark = root.createNewSeparator();
bookmark.setMetaDataItem(QStringLiteral("UDI"), udi);
bookmark.setMetaDataItem(QStringLiteral("isSystemItem"), QStringLiteral("true"));
return bookmark;
const QString urlScheme = url().scheme();
return (urlScheme.contains("search") || urlScheme.contains("timeline"));
}
void PlacesItem::onDataValueChanged(const QByteArray& role,

View File

@ -40,14 +40,6 @@ class PlacesItem : public KStandardItem
{
public:
enum GroupType
{
PlacesType,
SearchForType,
RecentlySavedType,
DevicesType
};
explicit PlacesItem(const KBookmark& bookmark, PlacesItem* parent = nullptr);
~PlacesItem() override;
@ -68,16 +60,9 @@ public:
void setBookmark(const KBookmark& bookmark);
KBookmark bookmark() const;
GroupType groupType() const;
bool storageSetupNeeded() const;
static KBookmark createBookmark(KBookmarkManager* manager,
const QString& text,
const QUrl& url,
const QString& iconName);
static KBookmark createDeviceBookmark(KBookmarkManager* manager,
const QString& udi);
bool isSearchOrTimelineUrl() const;
PlacesItemSignalHandler* signalHandler() const;

File diff suppressed because it is too large Load Diff

View File

@ -20,8 +20,6 @@
#ifndef PLACESITEMMODEL_H
#define PLACESITEMMODEL_H
#include <config-baloo.h>
#include <kitemviews/kstandarditemmodel.h>
#include <QUrl>
@ -33,9 +31,9 @@
class KBookmark;
class KBookmarkManager;
class KFilePlacesModel;
class PlacesItem;
class QAction;
class QTimer;
// #define PLACESITEMMODEL_DEBUG
@ -54,15 +52,22 @@ public:
~PlacesItemModel() override;
/**
* @return A new instance of a places item with the given
* attributes.
* @brief Create a new place entry in the bookmark file
* and add it to the model
*/
PlacesItem* createPlacesItem(const QString& text,
const QUrl& url,
const QString& iconName = QString());
void createPlacesItem(const QString& text,
const QUrl& url,
const QString& iconName = QString(),
int after = -1);
PlacesItem* placesItem(int index) const;
/**
* @brief Mark an item as hiden
* @param index of the item to be hidden
*/
void hideItem(int index);
/**
* If set to true, all items that are marked as hidden
* will be shown in the view. The items will
@ -89,15 +94,6 @@ public:
*/
int closestItem(const QUrl& url) const;
/**
* Appends the item \a item as last element of the group
* the item belongs to. If no item with the same group is
* present, the item gets appended as last element of the
* model. PlacesItemModel takes the ownership
* of the item.
*/
void appendItemToGroup(PlacesItem* item);
QAction* ejectAction(int index) const;
QAction* teardownAction(int index) const;
@ -126,11 +122,19 @@ public:
void proceedWithTearDown();
/**
* Saves the bookmarks and indicates to other applications that the
* state of the bookmarks has been changed. Is only called by the
* timeout of m_saveBookmarksTimer to prevent unnecessary savings.
* @brief Remove item from bookmark
*
* This function remove the index from bookmark file permanently
*
* @param index - the item to be removed
*/
void saveBookmarks();
void deleteItem(int index);
/**
* Force a sync on the bookmarks and indicates to other applications that the
* state of the bookmarks has been changed.
*/
void refresh();
bool isDir(int index) const override;
signals:
@ -145,22 +149,17 @@ protected:
void onItemChanged(int index, const QSet<QByteArray>& changedRoles) override;
private slots:
void slotDeviceAdded(const QString& udi);
void slotDeviceRemoved(const QString& udi);
void slotStorageTearDownDone(Solid::ErrorType error, const QVariant& errorData);
void slotStorageSetupDone(Solid::ErrorType error, const QVariant& errorData, const QString& udi);
void hideItem();
/**
* Updates the bookmarks from the model corresponding to the changed
* bookmarks stored by the bookmark-manager. Is called whenever the bookmarks
* have been changed by another application.
*/
void updateBookmarks();
// source model control
void onSourceModelRowsInserted(const QModelIndex &parent, int first, int last);
void onSourceModelRowsAboutToBeRemoved(const QModelIndex &parent, int first, int last);
void onSourceModelRowsAboutToBeMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destination, int row);
void onSourceModelRowsMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destination, int row);
void onSourceModelDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles);
private:
struct SystemBookmarkData;
/**
* Loads the bookmarks from the bookmark-manager and creates items for
* the model or moves hidden items to m_bookmarkedItems.
@ -172,37 +171,7 @@ private:
* current application (e.g. bookmarks from other applications
* will be ignored).
*/
bool acceptBookmark(const KBookmark& bookmark,
const QSet<QString>& availableDevices) const;
/**
* Creates a PlacesItem for a system-bookmark:
* - PlacesItem::isSystemItem() will return true
* - Default view-properties will be created for "Search For" items
* The item is not inserted to the model yet.
*/
PlacesItem* createSystemPlacesItem(const SystemBookmarkData& data);
/**
* Creates system bookmarks that are shown per default and can
* only be hidden but not removed. The result will be stored
* in m_systemBookmarks.
*/
void createSystemBookmarks();
void initializeAvailableDevices();
/**
* @param index Item index related to the model.
* @return Corresponding index related to m_bookmarkedItems.
*/
int bookmarkIndex(int index) const;
/**
* Marks the item with the index \a index as hidden and
* removes it from the model so that it gets invisible.
*/
void hideItem(int index);
bool acceptBookmark(const KBookmark& bookmark) const;
QString internalMimeType() const;
@ -220,77 +189,41 @@ private:
static bool equalBookmarkIdentifiers(const KBookmark& b1, const KBookmark& b2);
/**
* @return URL using the timeline-protocol for searching (see convertedUrl()).
* Appends the item \a item as last element of the group
* the item belongs to. If no item with the same group is
* present, the item gets appended as last element of the
* model. PlacesItemModel takes the ownership
* of the item.
*/
static QUrl createTimelineUrl(const QUrl& url);
/**
* Helper method for createTimelineUrl().
* @return String that represents a date-path in the format that
* the timeline-protocol expects.
*/
static QString timelineDateString(int year, int month, int day = 0);
/**
* @return URL that can be listed by KIO and results in searching
* for a given term. The URL \a url represents a places-internal
* URL like e.g. "search:/documents" (see convertedUrl()).
*/
static QUrl createSearchUrl(const QUrl& url);
#ifdef HAVE_BALOO
/**
* Helper method for createSearchUrl()
* @return URL that can be listed by KIO and results in searching
* for the given type
*/
static QUrl searchUrlForType(const QString& type);
#endif
void insertSortedItem(PlacesItem* item);
#ifdef PLACESITEMMODEL_DEBUG
void showModelState();
#endif
PlacesItem *itemFromBookmark(const KBookmark &bookmark) const;
void addItemFromSourceModel(const QModelIndex &index);
void removeItemByIndex(const QModelIndex &mapToSource);
QString bookmarkId(const KBookmark &bookmark) const;
void initializeDefaultViewProperties() const;
int mapFromSource(const QModelIndex &index) const;
QModelIndex mapToSource(int row) const;
static void updateItem(PlacesItem *item, const QModelIndex &index);
private:
bool m_fileIndexingEnabled;
bool m_hiddenItemsShown;
QSet<QString> m_availableDevices;
Solid::Predicate m_predicate;
KBookmarkManager* m_bookmarkManager;
struct SystemBookmarkData
{
SystemBookmarkData(const QUrl& url,
const QString& icon,
const QString& text) :
url(url), icon(icon), text(text) {}
QUrl url;
QString icon;
QString text;
};
QList<SystemBookmarkData> m_systemBookmarks;
QHash<QUrl, int> m_systemBookmarksIndexes;
// Contains hidden and unhidden items that are stored as
// bookmark (the model itself only contains items that
// are shown in the view). If an entry is 0, then the
// places-item is part of the model. If an entry is not
// 0, the item is hidden and not part of the model.
QList<PlacesItem*> m_bookmarkedItems;
// Index of the hidden item that should be removed in
// removeHiddenItem(). The removing must be done
// asynchronously as in the scope of onItemChanged()
// removing an item is not allowed.
int m_hiddenItemToRemove;
Solid::StorageAccess *m_deviceToTearDown;
QTimer* m_updateBookmarksTimer;
QHash<QObject*, int> m_storageSetupInProgress;
QScopedPointer<KFilePlacesModel> m_sourceModel;
QVector<QPersistentModelIndex> m_indexMap;
};
#endif

View File

@ -34,6 +34,7 @@
#include <KIO/DropJob>
#include <KIO/EmptyTrashJob>
#include <KIO/JobUiDelegate>
#include <KFilePlacesModel>
#include <KJobWidgets>
#include <KLocalizedString>
#include <KIconLoader>
@ -239,13 +240,11 @@ void PlacesPanel::slotItemContextMenuRequested(int index, const QPointF& pos)
if (action == editAction) {
editEntry(index);
} else if (action == removeAction) {
m_model->removeItem(index);
m_model->saveBookmarks();
m_model->deleteItem(index);
} else if (action == hideAction) {
item->setHidden(hideAction->isChecked());
m_model->saveBookmarks();
} else if (action == openInNewWindowAction) {
Dolphin::openNewWindow({PlacesItemModel::convertedUrl(m_model->data(index).value("url").toUrl())}, this);
Dolphin::openNewWindow({KFilePlacesModel::convertedUrl(m_model->data(index).value("url").toUrl())}, this);
} else if (action == openInNewTabAction) {
// TriggerItem does set up the storage first and then it will
// emit the slotItemMiddleClicked signal, because of Qt::MiddleButton.
@ -334,8 +333,8 @@ void PlacesPanel::slotItemDropEvent(int index, QGraphicsSceneDragDropEvent* even
}
const PlacesItem* destItem = m_model->placesItem(index);
const PlacesItem::GroupType group = destItem->groupType();
if (group == PlacesItem::SearchForType || group == PlacesItem::RecentlySavedType) {
if (destItem->isSearchOrTimelineUrl()) {
return;
}
@ -396,7 +395,6 @@ void PlacesPanel::slotItemDropEventStorageSetupDone(int index, bool success)
void PlacesPanel::slotAboveItemDropEvent(int index, QGraphicsSceneDragDropEvent* event)
{
m_model->dropMimeDataBefore(index, event->mimeData());
m_model->saveBookmarks();
}
void PlacesPanel::slotUrlsDropped(const QUrl& dest, QDropEvent* event, QWidget* parent)
@ -456,9 +454,7 @@ void PlacesPanel::addEntry()
dialog->setAllowGlobal(true);
dialog->setUrl(url);
if (dialog->exec() == QDialog::Accepted) {
PlacesItem* item = m_model->createPlacesItem(dialog->text(), dialog->url(), dialog->icon());
m_model->appendItemToGroup(item);
m_model->saveBookmarks();
m_model->createPlacesItem(dialog->text(), dialog->url(), dialog->icon());
}
delete dialog;
@ -480,7 +476,7 @@ void PlacesPanel::editEntry(int index)
oldItem->setText(dialog->text());
oldItem->setUrl(dialog->url());
oldItem->setIcon(dialog->icon());
m_model->saveBookmarks();
m_model->refresh();
}
}
@ -517,9 +513,9 @@ void PlacesPanel::triggerItem(int index, Qt::MouseButton button)
const QUrl url = m_model->data(index).value("url").toUrl();
if (!url.isEmpty()) {
if (button == Qt::MiddleButton) {
emit placeMiddleClicked(PlacesItemModel::convertedUrl(url));
emit placeMiddleClicked(KFilePlacesModel::convertedUrl(url));
} else {
emit placeActivated(PlacesItemModel::convertedUrl(url));
emit placeActivated(KFilePlacesModel::convertedUrl(url));
}
}
}

View File

@ -310,11 +310,9 @@ void DolphinSearchBox::slotSearchSaved()
if (searchURL.isValid()) {
PlacesItemModel model;
const QString label = i18n("Search for %1 in %2", text(), searchPath().fileName());
PlacesItem* item = model.createPlacesItem(label,
searchURL,
QStringLiteral("folder-saved-search-symbolic"));
model.appendItemToGroup(item);
model.saveBookmarks();
model.createPlacesItem(label,
searchURL,
QStringLiteral("folder-saved-search-symbolic"));
}
}

View File

@ -25,11 +25,13 @@
#include <QStandardPaths>
#include <QAction>
#include <QDBusInterface>
#include <QUrlQuery>
#include <KBookmarkManager>
#include <KConfig>
#include <KConfigGroup>
#include <KAboutData>
#include <KFilePlacesModel>
#include "panels/places/placesitemmodel.h"
#include "panels/places/placesitem.h"
@ -37,7 +39,7 @@
#include "kitemviews/kitemrange.h"
Q_DECLARE_METATYPE(KItemRangeList)
Q_DECLARE_METATYPE(PlacesItem::GroupType)
Q_DECLARE_METATYPE(KItemRange)
#ifdef Q_OS_WIN
//c:\ as root for windows
@ -63,8 +65,8 @@ private slots:
void cleanupTestCase();
void testModelSort();
void testModelMove();
void testGroups();
void testDeletePlace();
void testPlaceItem_data();
void testPlaceItem();
void testTearDownDevice();
@ -76,30 +78,37 @@ private slots:
void testEditBookmark();
void testEditAfterCreation();
void testEditMetadata();
void testRefresh();
void testIcons_data();
void testIcons();
void testDragAndDrop();
private:
PlacesItemModel* m_model;
QSet<int> m_tobeRemoved;
QMap<QString, QDBusInterface *> m_interfacesMap;
void setBalooEnabled(bool enabled);
int indexOf(const QUrl &url);
QDBusInterface *fakeManager();
QDBusInterface *fakeDevice(const QString &udi);
QStringList placesUrls() const;
QStringList placesUrls(PlacesItemModel *model = nullptr) const;
QStringList initialUrls() const;
void createPlaceItem(const QString &text, const QUrl &url, const QString &icon);
void removePlaceAfter(int index);
void cancelPlaceRemoval(int index);
void removeTestUserData();
QMimeData *createMimeData(const QList<int> &indexes) const;
};
#define CHECK_PLACES_URLS(urls) \
QStringList tmp(urls); \
QStringList places = placesUrls(); \
while(!places.isEmpty()) { \
tmp.removeOne(places.takeFirst()); \
} \
if (!tmp.isEmpty()) { \
qWarning() << "Expected:" << urls; \
qWarning() << "Got:" << places; \
QCOMPARE(places, urls); \
#define CHECK_PLACES_URLS(urls) \
{ \
QStringList places = placesUrls(); \
if (places != urls) { \
qWarning() << "Expected:" << urls; \
qWarning() << "Got:" << places; \
QCOMPARE(places, urls); \
} \
}
void PlacesItemModelTest::setBalooEnabled(bool enabled)
@ -137,23 +146,78 @@ QDBusInterface *PlacesItemModelTest::fakeDevice(const QString &udi)
return iface;
}
QStringList PlacesItemModelTest::placesUrls() const
QStringList PlacesItemModelTest::placesUrls(PlacesItemModel *model) const
{
QStringList urls;
for (int row = 0; row < m_model->count(); ++row) {
urls << m_model->placesItem(row)->url().toDisplayString(QUrl::PreferLocalFile);
if (!model) {
model = m_model;
}
for (int row = 0; row < model->count(); ++row) {
urls << model->placesItem(row)->url().toDisplayString(QUrl::PreferLocalFile);
}
return urls;
}
QStringList PlacesItemModelTest::initialUrls() const
{
static QStringList urls;
if (urls.isEmpty()) {
urls << QDir::homePath() << QStringLiteral(KDE_ROOT_PATH) << QStringLiteral("trash:/")
<< QStringLiteral("remote:/")
<< QStringLiteral("timeline:/today") << QStringLiteral("timeline:/yesterday") << QStringLiteral("timeline:/thismonth") << QStringLiteral("timeline:/lastmonth")
<< QStringLiteral("search:/documents") << QStringLiteral("search:/images") << QStringLiteral("search:/audio") << QStringLiteral("search:/videos")
<< QStringLiteral("/media/nfs") << QStringLiteral("/foreign")
<< QStringLiteral("/media/floppy0") << QStringLiteral("/media/XO-Y4") << QStringLiteral("/media/cdrom");
}
return urls;
}
void PlacesItemModelTest::createPlaceItem(const QString &text, const QUrl &url, const QString &icon)
{
PlacesItem *item = m_model->createPlacesItem(text,
url,
icon);
QSignalSpy itemsInsertedSpy(m_model, &PlacesItemModel::itemsInserted);
m_model->appendItemToGroup(item);
QTRY_COMPARE(itemsInsertedSpy.count(), 1);
m_model->createPlacesItem(text, url, icon);
}
void PlacesItemModelTest::removePlaceAfter(int index)
{
m_tobeRemoved.insert(index);
}
void PlacesItemModelTest::cancelPlaceRemoval(int index)
{
m_tobeRemoved.remove(index);
}
void PlacesItemModelTest::removeTestUserData()
{
// user hardcoded path to avoid removal of any user personal data
QDir dir(QStringLiteral("/home/renato/.qttest/share/placesitemmodeltest"));
if (dir.exists()) {
QVERIFY(dir.removeRecursively());
}
}
QMimeData *PlacesItemModelTest::createMimeData(const QList<int> &indexes) const
{
QByteArray itemData;
QDataStream stream(&itemData, QIODevice::WriteOnly);
QList<QUrl> urls;
for (int index : indexes) {
const QUrl itemUrl = m_model->placesItem(index)->url();
if (itemUrl.isValid()) {
urls << itemUrl;
}
stream << index;
}
QMimeData* mimeData = new QMimeData();
mimeData->setUrls(urls);
// copied from PlacesItemModel::internalMimeType()
const QString internalMimeType = "application/x-dolphinplacesmodel-" +
QString::number((qptrdiff)m_model);
mimeData->setData(internalMimeType, itemData);
return mimeData;
}
void PlacesItemModelTest::init()
@ -166,13 +230,22 @@ void PlacesItemModelTest::init()
void PlacesItemModelTest::cleanup()
{
for (int i : m_tobeRemoved) {
int before = m_model->count();
m_model->deleteItem(i);
QTRY_COMPARE(m_model->count(), before - 1);
}
m_tobeRemoved.clear();
delete m_model;
m_model = nullptr;
removeTestUserData();
}
void PlacesItemModelTest::initTestCase()
{
QStandardPaths::setTestModeEnabled(true);
// remove test user data
removeTestUserData();
const QString fakeHw = QFINDTESTDATA("data/fakecomputer.xml");
QVERIFY(!fakeHw.isEmpty());
@ -186,24 +259,16 @@ void PlacesItemModelTest::initTestCase()
}
qRegisterMetaType<KItemRangeList>();
qRegisterMetaType<KItemRange>();
}
void PlacesItemModelTest::cleanupTestCase()
{
qDeleteAll(m_interfacesMap);
QFile::remove(bookmarksFile());
}
QStringList PlacesItemModelTest::initialUrls() const
{
QStringList urls;
urls << QDir::homePath() << QStringLiteral("remote:/") << QStringLiteral(KDE_ROOT_PATH) << QStringLiteral("trash:/")
<< QStringLiteral("timeline:/today") << QStringLiteral("timeline:/yesterday") << QStringLiteral("timeline:/thismonth") << QStringLiteral("timeline:/lastmonth")
<< QStringLiteral("search:/documents") << QStringLiteral("search:/images") << QStringLiteral("search:/audio") << QStringLiteral("search:/videos")
<< QStringLiteral("/media/cdrom") << QStringLiteral("/foreign") << QStringLiteral("/media/XO-Y4") << QStringLiteral("/media/nfs") << QStringLiteral("/media/floppy0");
return urls;
// Remove any previous properties file
removeTestUserData();
}
void PlacesItemModelTest::testModelSort()
@ -211,36 +276,29 @@ void PlacesItemModelTest::testModelSort()
CHECK_PLACES_URLS(initialUrls());
}
void PlacesItemModelTest::testModelMove()
{
QStringList urls = initialUrls();
KBookmarkManager *bookmarkManager = KBookmarkManager::managerForFile(bookmarksFile(), QStringLiteral("kfilePlaces"));
KBookmarkGroup root = bookmarkManager->root();
KBookmark systemRoot = m_model->placesItem(1)->bookmark();
KBookmark last = m_model->placesItem(m_model->count() - 1)->bookmark();
// try to move the "root" path to the end of the list
root.moveBookmark(systemRoot, last);
bookmarkManager->emitChanged(root);
// make sure that the items still grouped and the "root" item was moved to the end of places group instead
urls.move(1, 2);
CHECK_PLACES_URLS(urls);
}
void PlacesItemModelTest::testGroups()
{
const auto groups = m_model->groups();
QCOMPARE(groups.size(), 4);
QCOMPARE(groups.size(), 6);
QCOMPARE(groups.at(0).first, 0);
QCOMPARE(groups.at(0).second.toString(), QStringLiteral("Places"));
QCOMPARE(groups.at(1).first, 4);
QCOMPARE(groups.at(1).second.toString(), QStringLiteral("Recently Saved"));
QCOMPARE(groups.at(2).first, 8);
QCOMPARE(groups.at(2).second.toString(), QStringLiteral("Search For"));
QCOMPARE(groups.at(3).first, 12);
QCOMPARE(groups.at(3).second.toString(), QStringLiteral("Devices"));
QCOMPARE(groups.at(1).first, 3);
QCOMPARE(groups.at(1).second.toString(), QStringLiteral("Remote"));
QCOMPARE(groups.at(2).first, 4);
QCOMPARE(groups.at(2).second.toString(), QStringLiteral("Recently Saved"));
QCOMPARE(groups.at(3).first, 8);
QCOMPARE(groups.at(3).second.toString(), QStringLiteral("Search For"));
QCOMPARE(groups.at(4).first, 12);
QCOMPARE(groups.at(4).second.toString(), QStringLiteral("Devices"));
QCOMPARE(groups.at(5).first, 14);
QCOMPARE(groups.at(5).second.toString(), QStringLiteral("Removable Devices"));
}
void PlacesItemModelTest::testPlaceItem_data()
@ -248,20 +306,20 @@ void PlacesItemModelTest::testPlaceItem_data()
QTest::addColumn<QUrl>("url");
QTest::addColumn<bool>("expectedIsHidden");
QTest::addColumn<bool>("expectedIsSystemItem");
QTest::addColumn<PlacesItem::GroupType>("expectedGroupType");
QTest::addColumn<QString>("expectedGroup");
QTest::addColumn<bool>("expectedStorageSetupNeeded");
// places
QTest::newRow("Places - Home") << QUrl::fromLocalFile(QDir::homePath()) << false << true << PlacesItem::PlacesType << false;
QTest::newRow("Places - Home") << QUrl::fromLocalFile(QDir::homePath()) << false << true << QStringLiteral("Places") << false;
// baloo -search
QTest::newRow("Baloo - Documents") << QUrl("search:/documents") << false << true << PlacesItem::SearchForType << false;
QTest::newRow("Baloo - Documents") << QUrl("search:/documents") << false << true << QStringLiteral("Search For") << false;
// baloo - timeline
QTest::newRow("Baloo - Last Month") << QUrl("timeline:/lastmonth") << false << true << PlacesItem::RecentlySavedType << false;
QTest::newRow("Baloo - Last Month") << QUrl("timeline:/lastmonth") << false << true << QStringLiteral("Recently Saved") << false;
// devices
QTest::newRow("Devices - Floppy") << QUrl("file:///media/floppy0") << false << false << PlacesItem::DevicesType << false;
QTest::newRow("Devices - Floppy") << QUrl("file:///media/floppy0") << false << false << QStringLiteral("Removable Devices") << false;
}
void PlacesItemModelTest::testPlaceItem()
@ -269,7 +327,7 @@ void PlacesItemModelTest::testPlaceItem()
QFETCH(QUrl, url);
QFETCH(bool, expectedIsHidden);
QFETCH(bool, expectedIsSystemItem);
QFETCH(PlacesItem::GroupType, expectedGroupType);
QFETCH(QString, expectedGroup);
QFETCH(bool, expectedStorageSetupNeeded);
const int index = indexOf(url);
@ -277,10 +335,38 @@ void PlacesItemModelTest::testPlaceItem()
QCOMPARE(item->url(), url);
QCOMPARE(item->isHidden(), expectedIsHidden);
QCOMPARE(item->isSystemItem(), expectedIsSystemItem);
QCOMPARE(item->groupType(), expectedGroupType);
QCOMPARE(item->group(), expectedGroup);
QCOMPARE(item->storageSetupNeeded(), expectedStorageSetupNeeded);
}
void PlacesItemModelTest::testDeletePlace()
{
const QUrl tempUrl = QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::TempLocation));
QStringList urls = initialUrls();
QSignalSpy itemsInsertedSpy(m_model, &PlacesItemModel::itemsInserted);
QSignalSpy itemsRemovedSpy(m_model, &PlacesItemModel::itemsRemoved);
PlacesItemModel *model = new PlacesItemModel();
// create a new place
createPlaceItem(QStringLiteral("Temporary Dir"), tempUrl, QString());
urls.insert(3, tempUrl.toLocalFile());
// check if the new entry was created
QTRY_COMPARE(itemsInsertedSpy.count(), 1);
CHECK_PLACES_URLS(urls);
QTRY_COMPARE(model->count(), m_model->count());
// delete item
m_model->deleteItem(3);
// make sure that the new item is removed
QTRY_COMPARE(itemsRemovedSpy.count(), 1);
QTRY_COMPARE(m_model->count(), 17);
CHECK_PLACES_URLS(initialUrls());
QTRY_COMPARE(model->count(), m_model->count());
}
void PlacesItemModelTest::testTearDownDevice()
{
const QUrl mediaUrl = QUrl::fromLocalFile(QStringLiteral("/media/XO-Y4"));
@ -351,7 +437,7 @@ void PlacesItemModelTest::testDefaultViewProperties()
QFETCH(bool, expectedPreviewShow);
QFETCH(QList<QByteArray>, expectedVisibleRole);
ViewProperties properties(m_model->convertedUrl(url));
ViewProperties properties(KFilePlacesModel::convertedUrl(url));
QCOMPARE(properties.viewMode(), expectedViewMode);
QCOMPARE(properties.previewsShown(), expectedPreviewShow);
QCOMPARE(properties.visibleRoles(), expectedVisibleRole);
@ -363,6 +449,8 @@ void PlacesItemModelTest::testClear()
m_model->clear();
QCOMPARE(m_model->count(), 0);
QCOMPARE(m_model->hiddenCount(), 0);
m_model->refresh();
QTRY_COMPARE(m_model->count(), 17);
}
void PlacesItemModelTest::testHideItem()
@ -420,115 +508,254 @@ void PlacesItemModelTest::testSystemItems()
QCOMPARE(m_model->placesItem(r)->isSystemItem(), !m_model->placesItem(r)->device().isValid());
}
// create a new entry (non system item)
PlacesItem *item = m_model->createPlacesItem(QStringLiteral("Temporary Dir"),
QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::TempLocation)),
QString());
QSignalSpy itemsInsertedSpy(m_model, &PlacesItemModel::itemsInserted);
m_model->appendItemToGroup(item);
// create a new entry (non system item)
createPlaceItem(QStringLiteral("Temporary Dir"), QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::TempLocation)), QString());
// check if the new entry was created
QTRY_COMPARE(itemsInsertedSpy.count(), 1);
// make sure the new place get removed
removePlaceAfter(3);
QList<QVariant> args = itemsInsertedSpy.takeFirst();
KItemRangeList range = args.at(0).value<KItemRangeList>();
QCOMPARE(range.first().index, 4);
QCOMPARE(range.first().index, 3);
QCOMPARE(range.first().count, 1);
QVERIFY(!m_model->placesItem(4)->isSystemItem());
QVERIFY(!m_model->placesItem(3)->isSystemItem());
QCOMPARE(m_model->count(), 18);
// remove new entry
QTest::qWait(300);
// check if the removal signal is correct
QSignalSpy itemsRemovedSpy(m_model, &PlacesItemModel::itemsRemoved);
m_model->removeItem(4);
m_model->saveBookmarks();
m_model->deleteItem(3);
QTRY_COMPARE(itemsRemovedSpy.count(), 1);
args = itemsRemovedSpy.takeFirst();
range = args.at(0).value<KItemRangeList>();
QCOMPARE(range.first().index, 4);
QCOMPARE(range.first().index, 3);
QCOMPARE(range.first().count, 1);
QTRY_COMPARE(m_model->count(), 17);
//cancel removal (it was removed above)
cancelPlaceRemoval(3);
}
void PlacesItemModelTest::testEditBookmark()
{
const QUrl tempUrl = QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::TempLocation));
QScopedPointer<PlacesItemModel> other(new PlacesItemModel());
createPlaceItem(QStringLiteral("Temporary Dir"), QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::TempLocation)), QString());
// make sure that the new item will be removed later
removePlaceAfter(3);
QSignalSpy itemsChangedSply(m_model, &PlacesItemModel::itemsChanged);
m_model->item(4)->setText(QStringLiteral("Renamed place"));
m_model->saveBookmarks();
// modify place text
m_model->item(3)->setText(QStringLiteral("Renamed place"));
m_model->refresh();
// check if the correct signal was fired
QTRY_COMPARE(itemsChangedSply.count(), 1);
QList<QVariant> args = itemsChangedSply.takeFirst();
KItemRangeList range = args.at(0).value<KItemRangeList>();
QCOMPARE(range.first().index, 4);
QCOMPARE(range.first().index, 3);
QCOMPARE(range.first().count, 1);
QSet<QByteArray> roles = args.at(1).value<QSet<QByteArray> >();
QCOMPARE(roles.size(), 1);
QCOMPARE(*roles.begin(), QByteArrayLiteral("text"));
QCOMPARE(m_model->item(4)->text(), QStringLiteral("Renamed place"));
QCOMPARE(m_model->item(3)->text(), QStringLiteral("Renamed place"));
// check if the item was updated in the other model
QTRY_COMPARE(other->item(4)->text(), QStringLiteral("Renamed place"));
// remove new entry
QSignalSpy itemsRemovedSpy(m_model, &PlacesItemModel::itemsRemoved);
m_model->removeItem(4);
m_model->saveBookmarks();
QTRY_COMPARE(itemsRemovedSpy.count(), 1);
args = itemsRemovedSpy.takeFirst();
range = args.at(0).value<KItemRangeList>();
QCOMPARE(range.first().index, 4);
QCOMPARE(range.first().count, 1);
QTRY_COMPARE(m_model->count(), 17);
QTRY_COMPARE(other->item(3)->text(), QStringLiteral("Renamed place"));
}
void PlacesItemModelTest::testEditAfterCreation()
{
createPlaceItem(QStringLiteral("Temporary Dir"), QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::TempLocation)), QString());
const QUrl tempUrl = QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::TempLocation));
QSignalSpy itemsInsertedSpy(m_model, &PlacesItemModel::itemsInserted);
// create a new place
createPlaceItem(QStringLiteral("Temporary Dir"), tempUrl, QString());
QTRY_COMPARE(itemsInsertedSpy.count(), 1);
PlacesItemModel *model = new PlacesItemModel();
QTRY_COMPARE(model->count(), m_model->count());
PlacesItem *item = m_model->placesItem(4);
// make sure that the new item will be removed later
removePlaceAfter(3);
// modify place text
PlacesItem *item = m_model->placesItem(3);
item->setText(QStringLiteral("Renamed place"));
m_model->saveBookmarks();
m_model->refresh();
// check if the second model got the changes
QTRY_COMPARE(model->count(), m_model->count());
QTRY_COMPARE(model->placesItem(4)->text(), m_model->placesItem(4)->text());
QTRY_COMPARE(model->placesItem(4)->bookmark().metaDataItem(QStringLiteral("OnlyInApp")),
m_model->placesItem(4)->bookmark().metaDataItem(QStringLiteral("OnlyInApp")));
QTRY_COMPARE(model->placesItem(4)->icon(), m_model->placesItem(4)->icon());
QTRY_COMPARE(model->placesItem(4)->url(), m_model->placesItem(4)->url());
m_model->removeItem(4);
m_model->saveBookmarks();
QTRY_COMPARE(model->count(), m_model->count());
QTRY_COMPARE(model->placesItem(3)->text(), m_model->placesItem(3)->text());
QTRY_COMPARE(model->placesItem(3)->bookmark().metaDataItem(QStringLiteral("OnlyInApp")),
m_model->placesItem(3)->bookmark().metaDataItem(QStringLiteral("OnlyInApp")));
QTRY_COMPARE(model->placesItem(3)->icon(), m_model->placesItem(3)->icon());
QTRY_COMPARE(model->placesItem(3)->url(), m_model->placesItem(3)->url());
}
void PlacesItemModelTest::testEditMetadata()
{
createPlaceItem(QStringLiteral("Temporary Dir"), QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::TempLocation)), QString());
const QUrl tempUrl = QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::TempLocation));
QSignalSpy itemsInsertedSpy(m_model, &PlacesItemModel::itemsInserted);
// create a new place
createPlaceItem(QStringLiteral("Temporary Dir"), tempUrl, QString());
QTRY_COMPARE(itemsInsertedSpy.count(), 1);
// check if the new entry was created
PlacesItemModel *model = new PlacesItemModel();
QTRY_COMPARE(model->count(), m_model->count());
// make sure that the new item will be removed later
removePlaceAfter(3);
// modify place metadata
PlacesItem *item = m_model->placesItem(3);
item->bookmark().setMetaDataItem(QStringLiteral("OnlyInApp"), KAboutData::applicationData().componentName());
m_model->refresh();
// check if the place was modified in both models
QTRY_COMPARE(model->placesItem(3)->bookmark().metaDataItem(QStringLiteral("OnlyInApp")),
KAboutData::applicationData().componentName());
QTRY_COMPARE(model->placesItem(3)->text(), m_model->placesItem(3)->text());
QTRY_COMPARE(model->placesItem(3)->bookmark().metaDataItem(QStringLiteral("OnlyInApp")),
m_model->placesItem(3)->bookmark().metaDataItem(QStringLiteral("OnlyInApp")));
QTRY_COMPARE(model->placesItem(3)->icon(), m_model->placesItem(3)->icon());
QTRY_COMPARE(model->placesItem(3)->url(), m_model->placesItem(3)->url());
}
void PlacesItemModelTest::testRefresh()
{
const QUrl tempUrl = QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::TempLocation));
QSignalSpy itemsInsertedSpy(m_model, &PlacesItemModel::itemsInserted);
// create a new place
createPlaceItem(QStringLiteral("Temporary Dir"), tempUrl, QString());
QTRY_COMPARE(itemsInsertedSpy.count(), 1);
PlacesItemModel *model = new PlacesItemModel();
QTRY_COMPARE(model->count(), m_model->count());
PlacesItem *item = m_model->placesItem(4);
item->bookmark().setMetaDataItem(QStringLiteral("OnlyInApp"), KAboutData::applicationData().componentName());
m_model->saveBookmarks();
// make sure that the new item will be removed later
removePlaceAfter(3);
QTRY_COMPARE(model->count(), m_model->count());
QTRY_COMPARE(model->placesItem(4)->bookmark().metaDataItem(QStringLiteral("OnlyInApp")),
KAboutData::applicationData().componentName());
QTRY_COMPARE(model->placesItem(4)->text(), m_model->placesItem(4)->text());
QTRY_COMPARE(model->placesItem(4)->bookmark().metaDataItem(QStringLiteral("OnlyInApp")),
m_model->placesItem(4)->bookmark().metaDataItem(QStringLiteral("OnlyInApp")));
QTRY_COMPARE(model->placesItem(4)->icon(), m_model->placesItem(4)->icon());
QTRY_COMPARE(model->placesItem(4)->url(), m_model->placesItem(4)->url());
PlacesItem *item = m_model->placesItem(3);
PlacesItem *sameItem = model->placesItem(3);
QCOMPARE(item->text(), sameItem->text());
m_model->removeItem(4);
m_model->saveBookmarks();
QTRY_COMPARE(model->count(), m_model->count());
// modify place text
item->setText(QStringLiteral("Renamed place"));
// item from another model is not affected at the moment
QVERIFY(item->text() != sameItem->text());
// propagate change
m_model->refresh();
// item must be equal
QTRY_COMPARE(item->text(), sameItem->text());
}
void PlacesItemModelTest::testIcons_data()
{
QTest::addColumn<QUrl>("url");
QTest::addColumn<QString>("expectedIconName");
// places
QTest::newRow("Places - Home") << QUrl::fromLocalFile(QDir::homePath()) << QStringLiteral("user-home");
// baloo -search
QTest::newRow("Baloo - Documents") << QUrl("search:/documents") << QStringLiteral("folder-text");
// baloo - timeline
QTest::newRow("Baloo - Last Month") << QUrl("timeline:/lastmonth") << QStringLiteral("view-calendar-month");
// devices
QTest::newRow("Devices - Floppy") << QUrl("file:///media/floppy0") << QStringLiteral("blockdevice");
}
void PlacesItemModelTest::testIcons()
{
QFETCH(QUrl, url);
QFETCH(QString, expectedIconName);
PlacesItem *item = m_model->placesItem(indexOf(url));
QCOMPARE(item->icon(), expectedIconName);
for (int r = 0; r < m_model->count(); r++) {
QVERIFY(!m_model->placesItem(r)->icon().isEmpty());
}
}
void PlacesItemModelTest::testDragAndDrop()
{
QList<QVariant> args;
KItemRangeList range;
QStringList urls = initialUrls();
QSignalSpy itemsInsertedSpy(m_model, &PlacesItemModel::itemsInserted);
QSignalSpy itemsRemovedSpy(m_model, &PlacesItemModel::itemsRemoved);
CHECK_PLACES_URLS(initialUrls());
// Move the KDE_ROOT_PATH at the end of the places list will case it to be moved to the end of the places group
QMimeData *dropData = createMimeData(QList<int>() << 1);
m_model->dropMimeDataBefore(m_model->count() - 1, dropData);
urls.move(1, 2);
delete dropData;
QTRY_COMPARE(itemsInsertedSpy.count(), 1);
QTRY_COMPARE(itemsRemovedSpy.count(), 1);
// remove item from actual position
args = itemsRemovedSpy.takeFirst();
range = args.at(0).value<KItemRangeList>();
QCOMPARE(range.size(), 1);
QCOMPARE(range.at(0).count, 1);
QCOMPARE(range.at(0).index, 1);
// insert intem in his group
args = itemsInsertedSpy.takeFirst();
range = args.at(0).value<KItemRangeList>();
QCOMPARE(range.size(), 1);
QCOMPARE(range.at(0).count, 1);
QCOMPARE(range.at(0).index, 2);
CHECK_PLACES_URLS(urls);
itemsInsertedSpy.clear();
itemsRemovedSpy.clear();
// Move the KDE_ROOT_PATH to his original position
dropData = createMimeData(QList<int>() << 2);
m_model->dropMimeDataBefore(1, dropData);
urls.move(2, 1);
delete dropData;
QTRY_COMPARE(itemsInsertedSpy.count(), 1);
QTRY_COMPARE(itemsRemovedSpy.count(), 1);
// remove item from actual position
args = itemsRemovedSpy.takeFirst();
range = args.at(0).value<KItemRangeList>();
QCOMPARE(range.size(), 1);
QCOMPARE(range.at(0).count, 1);
QCOMPARE(range.at(0).index, 2);
// insert intem in the requested position
args = itemsInsertedSpy.takeFirst();
range = args.at(0).value<KItemRangeList>();
QCOMPARE(range.size(), 1);
QCOMPARE(range.at(0).count, 1);
QCOMPARE(range.at(0).index, 1);
CHECK_PLACES_URLS(urls);
}
QTEST_MAIN(PlacesItemModelTest)