#include "kfileitemmodel.h"
#include <KGlobalSettings>
-#include <KLocale>
+#include <KLocalizedString>
#include <KStringHandler>
#include <KDebug>
+#include <kstringhandler_deprecated.h> //TODO: port to QCollator
#include "private/kfileitemmodelsortalgorithm.h"
#include "private/kfileitemmodeldirlister.h"
-#include <QApplication>
#include <QMimeData>
#include <QTimer>
#include <QWidget>
m_dirLister->setMainWindow(parentWidget->window());
}
- connect(m_dirLister, SIGNAL(started(KUrl)), this, SIGNAL(directoryLoadingStarted()));
- connect(m_dirLister, SIGNAL(canceled()), this, SLOT(slotCanceled()));
- connect(m_dirLister, SIGNAL(completed(KUrl)), this, SLOT(slotCompleted()));
- connect(m_dirLister, SIGNAL(itemsAdded(KUrl,KFileItemList)), this, SLOT(slotItemsAdded(KUrl,KFileItemList)));
- connect(m_dirLister, SIGNAL(itemsDeleted(KFileItemList)), this, SLOT(slotItemsDeleted(KFileItemList)));
- connect(m_dirLister, SIGNAL(refreshItems(QList<QPair<KFileItem,KFileItem> >)), this, SLOT(slotRefreshItems(QList<QPair<KFileItem,KFileItem> >)));
- connect(m_dirLister, SIGNAL(clear()), this, SLOT(slotClear()));
- connect(m_dirLister, SIGNAL(clear(KUrl)), this, SLOT(slotClear(KUrl)));
- connect(m_dirLister, SIGNAL(infoMessage(QString)), this, SIGNAL(infoMessage(QString)));
- connect(m_dirLister, SIGNAL(errorMessage(QString)), this, SIGNAL(errorMessage(QString)));
- connect(m_dirLister, SIGNAL(redirection(KUrl,KUrl)), this, SIGNAL(directoryRedirection(KUrl,KUrl)));
- connect(m_dirLister, SIGNAL(urlIsFileError(KUrl)), this, SIGNAL(urlIsFileError(KUrl)));
+ connect(m_dirLister, &KFileItemModelDirLister::started, this, &KFileItemModel::directoryLoadingStarted);
+ connect(m_dirLister, static_cast<void(KFileItemModelDirLister::*)()>(&KFileItemModelDirLister::canceled), this, &KFileItemModel::slotCanceled);
+ connect(m_dirLister, static_cast<void(KFileItemModelDirLister::*)(const QUrl&)>(&KFileItemModelDirLister::completed), this, &KFileItemModel::slotCompleted);
+ connect(m_dirLister, &KFileItemModelDirLister::itemsAdded, this, &KFileItemModel::slotItemsAdded);
+ connect(m_dirLister, &KFileItemModelDirLister::itemsDeleted, this, &KFileItemModel::slotItemsDeleted);
+ connect(m_dirLister, &KFileItemModelDirLister::refreshItems, this, &KFileItemModel::slotRefreshItems);
+ connect(m_dirLister, static_cast<void(KFileItemModelDirLister::*)()>(&KFileItemModelDirLister::clear), this, &KFileItemModel::slotClear);
+ connect(m_dirLister, &KFileItemModelDirLister::infoMessage, this, &KFileItemModel::infoMessage);
+ connect(m_dirLister, &KFileItemModelDirLister::errorMessage, this, &KFileItemModel::errorMessage);
+ connect(m_dirLister, static_cast<void(KFileItemModelDirLister::*)(const QUrl&, const QUrl&)>(&KFileItemModelDirLister::redirection), this, &KFileItemModel::directoryRedirection);
+ connect(m_dirLister, &KFileItemModelDirLister::urlIsFileError, this, &KFileItemModel::urlIsFileError);
// Apply default roles that should be determined
resetRoles();
m_maximumUpdateIntervalTimer = new QTimer(this);
m_maximumUpdateIntervalTimer->setInterval(2000);
m_maximumUpdateIntervalTimer->setSingleShot(true);
- connect(m_maximumUpdateIntervalTimer, SIGNAL(timeout()), this, SLOT(dispatchPendingItemsToInsert()));
+ connect(m_maximumUpdateIntervalTimer, &QTimer::timeout, this, &KFileItemModel::dispatchPendingItemsToInsert);
// When changing the value of an item which represents the sort-role a resorting must be
// triggered. Especially in combination with KFileItemModelRolesUpdater this might be done
m_resortAllItemsTimer = new QTimer(this);
m_resortAllItemsTimer->setInterval(500);
m_resortAllItemsTimer->setSingleShot(true);
- connect(m_resortAllItemsTimer, SIGNAL(timeout()), this, SLOT(resortAllItems()));
+ connect(m_resortAllItemsTimer, &QTimer::timeout, this, &KFileItemModel::resortAllItems);
- connect(KGlobalSettings::self(), SIGNAL(naturalSortingChanged()), this, SLOT(slotNaturalSortingChanged()));
+ connect(KGlobalSettings::self(), &KGlobalSettings::naturalSortingChanged,
+ this, &KFileItemModel::slotNaturalSortingChanged);
}
KFileItemModel::~KFileItemModel()
qDeleteAll(m_pendingItemsToInsert);
}
-void KFileItemModel::loadDirectory(const KUrl& url)
+void KFileItemModel::loadDirectory(const QUrl &url)
{
m_dirLister->openUrl(url);
}
-void KFileItemModel::refreshDirectory(const KUrl& url)
+void KFileItemModel::refreshDirectory(const QUrl &url)
{
// Refresh all expanded directories first (Bug 295300)
- QHashIterator<KUrl, KUrl> expandedDirs(m_expandedDirs);
+ QHashIterator<QUrl, QUrl> expandedDirs(m_expandedDirs);
while (expandedDirs.hasNext()) {
expandedDirs.next();
m_dirLister->openUrl(expandedDirs.value(), KDirLister::Reload);
m_dirLister->openUrl(url, KDirLister::Reload);
}
-KUrl KFileItemModel::directory() const
+QUrl KFileItemModel::directory() const
{
return m_dirLister->url();
}
m_itemData[index]->values = currentValues;
if (changedRoles.contains("text")) {
- KUrl url = m_itemData[index]->item.url();
- url.setFileName(currentValues["text"].toString());
+ QUrl url = m_itemData[index]->item.url();
+ url = url.adjusted(QUrl::RemoveFilename);
+ url.setPath(url.path() + currentValues["text"].toString());
m_itemData[index]->item.setUrl(url);
}
m_dirLister->setShowingDotFiles(show);
m_dirLister->emitChanges();
if (show) {
- slotCompleted();
+ dispatchPendingItemsToInsert();
}
}
// The following code has been taken from KDirModel::mimeData()
// (kdelibs/kio/kio/kdirmodel.cpp)
// Copyright (C) 2006 David Faure <faure@kde.org>
- KUrl::List urls;
- KUrl::List mostLocalUrls;
+ QList<QUrl> urls;
+ QList<QUrl> mostLocalUrls;
bool canUseMostLocalUrls = true;
const ItemData* lastAddedItem = 0;
const bool different = canUseMostLocalUrls && mostLocalUrls != urls;
if (different) {
- urls.populateMimeData(mostLocalUrls, data);
+ data->setUrls(mostLocalUrls);
} else {
- urls.populateMimeData(data);
+ data->setUrls(urls);
}
return data;
return KFileItem();
}
-KFileItem KFileItemModel::fileItem(const KUrl& url) const
+KFileItem KFileItemModel::fileItem(const QUrl &url) const
{
const int indexForUrl = index(url);
if (indexForUrl >= 0) {
return index(item.url());
}
-int KFileItemModel::index(const KUrl& url) const
+int KFileItemModel::index(const QUrl& url) const
{
- KUrl urlToFind = url;
- urlToFind.adjustPath(KUrl::RemoveTrailingSlash);
+ const QUrl urlToFind = url.adjusted(QUrl::StripTrailingSlash);
const int itemCount = m_itemData.count();
int itemsInHash = m_items.count();
const int blockSize = 1000;
const int currentBlockEnd = qMin(itemsInHash + blockSize, itemCount);
for (int i = itemsInHash; i < currentBlockEnd; ++i) {
- const KUrl nextUrl = m_itemData.at(i)->item.url();
+ const QUrl nextUrl = m_itemData.at(i)->item.url();
m_items.insert(nextUrl, i);
}
index = m_items.value(urlToFind, -1);
}
- Q_ASSERT(index >= 0 || m_items.count() == m_itemData.count());
+ if (index < 0) {
+ // The item could not be found, even though all items from m_itemData
+ // should be in m_items now. We print some diagnostic information which
+ // might help to find the cause of the problem, but only once. This
+ // prevents that obtaining and printing the debugging information
+ // wastes CPU cycles and floods the shell or .xsession-errors.
+ static bool printDebugInfo = true;
+
+ if (m_items.count() != m_itemData.count() && printDebugInfo) {
+ printDebugInfo = false;
+
+ kWarning() << "The model is in an inconsistent state.";
+ kWarning() << "m_items.count() ==" << m_items.count();
+ kWarning() << "m_itemData.count() ==" << m_itemData.count();
+
+ // Check if there are multiple items with the same URL.
+ QMultiHash<QUrl, int> indexesForUrl;
+ for (int i = 0; i < m_itemData.count(); ++i) {
+ indexesForUrl.insert(m_itemData.at(i)->item.url(), i);
+ }
+
+ foreach (const QUrl& url, indexesForUrl.uniqueKeys()) {
+ if (indexesForUrl.count(url) > 1) {
+ kWarning() << "Multiple items found with the URL" << url;
+ foreach (int index, indexesForUrl.values(url)) {
+ const ItemData* data = m_itemData.at(index);
+ kWarning() << "index" << index << ":" << data->item;
+ if (data->parent) {
+ kWarning() << "parent" << data->parent->item;
+ }
+ }
+ }
+ }
+ }
+ }
return index;
}
if (m_roles == roles) {
return;
}
+
+ const QSet<QByteArray> changedRoles = (roles - m_roles) + (m_roles - roles);
m_roles = roles;
if (count() > 0) {
m_itemData[i]->values = retrieveData(m_itemData.at(i)->item, m_itemData.at(i)->parent);
}
- kWarning() << "TODO: Emitting itemsChanged() with no information what has changed!";
- emit itemsChanged(KItemRangeList() << KItemRange(0, count()), QSet<QByteArray>());
+ emit itemsChanged(KItemRangeList() << KItemRange(0, count()), changedRoles);
}
// Clear the 'values' of all filtered items. They will be re-populated with the
}
const KFileItem item = m_itemData.at(index)->item;
- const KUrl url = item.url();
- const KUrl targetUrl = item.targetUrl();
+ const QUrl url = item.url();
+ const QUrl targetUrl = item.targetUrl();
if (expanded) {
m_expandedDirs.insert(targetUrl, url);
m_dirLister->openUrl(url, KDirLister::Keep);
- const KUrl::List previouslyExpandedChildren = m_itemData.at(index)->values.value("previouslyExpandedChildren").value<KUrl::List>();
- foreach (const KUrl& url, previouslyExpandedChildren) {
- m_urlsToExpand.insert(url);
+ const QVariantList previouslyExpandedChildren = m_itemData.at(index)->values.value("previouslyExpandedChildren").value<QVariantList>();
+ foreach (const QVariant& var, previouslyExpandedChildren) {
+ m_urlsToExpand.insert(var.toUrl());
}
} else {
+ // Note that there might be (indirect) children of the folder which is to be collapsed in
+ // m_pendingItemsToInsert. To prevent that they will be inserted into the model later,
+ // possibly without a parent, which might result in a crash, we insert all pending items
+ // right now. All new items which would be without a parent will then be removed.
+ dispatchPendingItemsToInsert();
+
+ // Check if the index of the collapsed folder has changed. If that is the case, then items
+ // were inserted before the collapsed folder, and its index needs to be updated.
+ if (m_itemData.at(index)->item != item) {
+ index = this->index(item);
+ }
+
m_expandedDirs.remove(targetUrl);
m_dirLister->stop(url);
const int itemCount = m_itemData.count();
const int firstChildIndex = index + 1;
- KUrl::List expandedChildren;
+ QVariantList expandedChildren;
int childIndex = firstChildIndex;
while (childIndex < itemCount && expandedParentsCount(childIndex) > parentLevel) {
ItemData* itemData = m_itemData.at(childIndex);
if (itemData->values.value("isExpanded").toBool()) {
- const KUrl targetUrl = itemData->item.targetUrl();
+ const QUrl targetUrl = itemData->item.targetUrl();
+ const QUrl url = itemData->item.url();
m_expandedDirs.remove(targetUrl);
+ m_dirLister->stop(url); // TODO: try to unit-test this, see https://bugs.kde.org/show_bug.cgi?id=332102#c11
expandedChildren.append(targetUrl);
}
++childIndex;
return 0;
}
-QSet<KUrl> KFileItemModel::expandedDirectories() const
+QSet<QUrl> KFileItemModel::expandedDirectories() const
{
return m_expandedDirs.values().toSet();
}
-void KFileItemModel::restoreExpandedDirectories(const QSet<KUrl>& urls)
+void KFileItemModel::restoreExpandedDirectories(const QSet<QUrl> &urls)
{
m_urlsToExpand = urls;
}
-void KFileItemModel::expandParentDirectories(const KUrl& url)
+void KFileItemModel::expandParentDirectories(const QUrl &url)
{
const int pos = m_dirLister->url().path().length();
// expanded is added to m_urlsToExpand. KDirLister
// does not care whether the parent-URL has already been
// expanded.
- KUrl urlToExpand = m_dirLister->url();
+ QUrl urlToExpand = m_dirLister->url();
const QStringList subDirs = url.path().mid(pos).split(QDir::separator());
for (int i = 0; i < subDirs.count() - 1; ++i) {
- urlToExpand.addPath(subDirs.at(i));
+ urlToExpand.setPath(urlToExpand.path() + '/' + subDirs.at(i));
m_urlsToExpand.insert(urlToExpand);
}
// KDirLister::open() must called at least once to trigger an initial
// loading. The pending URLs that must be restored are handled
// in slotCompleted().
- QSetIterator<KUrl> it2(m_urlsToExpand);
+ QSetIterator<QUrl> it2(m_urlsToExpand);
while (it2.hasNext()) {
const int idx = index(it2.next());
if (idx >= 0 && !isExpanded(idx)) {
// Remember the order of the current URLs so
// that it can be determined which indexes have
// been moved because of the resorting.
- QList<KUrl> oldUrls;
+ QList<QUrl> oldUrls;
oldUrls.reserve(itemCount);
foreach (const ItemData* itemData, m_itemData) {
oldUrls.append(itemData->item.url());
// Note that the parent folder must be expanded before any of its subfolders become visible.
// Therefore, some URLs in m_restoredExpandedUrls might not be visible yet
// -> we expand the first visible URL we find in m_restoredExpandedUrls.
- foreach (const KUrl& url, m_urlsToExpand) {
+ foreach (const QUrl& url, m_urlsToExpand) {
const int indexForUrl = index(url);
if (indexForUrl >= 0) {
m_urlsToExpand.remove(url);
emit directoryLoadingCanceled();
}
-void KFileItemModel::slotItemsAdded(const KUrl& directoryUrl, const KFileItemList& items)
+void KFileItemModel::slotItemsAdded(const QUrl &directoryUrl, const KFileItemList& items)
{
Q_ASSERT(!items.isEmpty());
- KUrl parentUrl;
+ QUrl parentUrl;
if (m_expandedDirs.contains(directoryUrl)) {
parentUrl = m_expandedDirs.value(directoryUrl);
} else {
- parentUrl = directoryUrl;
- parentUrl.adjustPath(KUrl::RemoveTrailingSlash);
+ parentUrl = directoryUrl.adjusted(QUrl::StripTrailingSlash);
}
if (m_requestRole[ExpandedParentsCountRole]) {
m_expandedDirs.clear();
}
-void KFileItemModel::slotClear(const KUrl& url)
-{
- Q_UNUSED(url);
-}
-
void KFileItemModel::slotNaturalSortingChanged()
{
m_naturalSorting = KGlobalSettings::naturalSorting();
}
// The indexes in m_items are not correct anymore. Therefore, we clear m_items.
- // It will be re-populated with the updated indices if index(const KUrl&) is called.
+ // It will be re-populated with the updated indices if index(const QUrl&) is called.
m_items.clear();
emit itemsInserted(itemRanges);
m_itemData.erase(m_itemData.end() - removedItemsCount, m_itemData.end());
// The indexes in m_items are not correct anymore. Therefore, we clear m_items.
- // It will be re-populated with the updated indices if index(const KUrl&) is called.
+ // It will be re-populated with the updated indices if index(const QUrl&) is called.
m_items.clear();
emit itemsRemoved(itemRanges);
}
-QList<KFileItemModel::ItemData*> KFileItemModel::createItemDataList(const KUrl& parentUrl, const KFileItemList& items) const
+QList<KFileItemModel::ItemData*> KFileItemModel::createItemDataList(const QUrl& parentUrl, const KFileItemList& items) const
{
if (m_sortRole == TypeRole) {
// Try to resolve the MIME-types synchronously to prevent a reordering of
// Don't use KFileItem::timeString() as this is too expensive when
// having several thousands of items. Instead the formatting of the
// date-time will be done on-demand by the view when the date will be shown.
- const KDateTime dateTime = item.time(KFileItem::ModificationTime);
- data.insert(sharedValue("date"), dateTime.dateTime());
+ const QDateTime dateTime = item.time(KFileItem::ModificationTime);
+ data.insert(sharedValue("date"), dateTime);
}
if (m_requestRole[PermissionsRole]) {
if (m_requestRole[PathRole]) {
QString path;
- if (item.url().protocol() == QLatin1String("trash")) {
+ if (item.url().scheme() == QLatin1String("trash")) {
path = item.entry().stringValue(KIO::UDSEntry::UDS_EXTRA);
} else {
// For performance reasons cache the home-path in a static QString
}
case DateRole: {
- const KDateTime dateTimeA = itemA.time(KFileItem::ModificationTime);
- const KDateTime dateTimeB = itemB.time(KFileItem::ModificationTime);
+ const QDateTime dateTimeA = itemA.time(KFileItem::ModificationTime);
+ const QDateTime dateTimeB = itemB.time(KFileItem::ModificationTime);
if (dateTimeA < dateTimeB) {
result = -1;
} else if (dateTimeA > dateTimeB) {
const int maxIndex = count() - 1;
QList<QPair<int, QVariant> > groups;
- const QDate currentDate = KDateTime::currentLocalDateTime().date();
+ const QDate currentDate = QDate::currentDate();
QDate previousModifiedDate;
QString groupValue;
continue;
}
- const KDateTime modifiedTime = m_itemData.at(i)->item.time(KFileItem::ModificationTime);
+ const QDateTime modifiedTime = m_itemData.at(i)->item.time(KFileItem::ModificationTime);
const QDate modifiedDate = modifiedTime.date();
if (modifiedDate == previousModifiedDate) {
// The current item is in the same group as the previous item
}
permissionsString = newPermissionsString;
- const QFileInfo info(itemData->item.url().pathOrUrl());
+ const QFileInfo info(itemData->item.url().toLocalFile());
// Set user string
QString user;
bool KFileItemModel::isConsistent() const
{
// m_items may contain less items than m_itemData because m_items
- // is populated lazily, see KFileItemModel::index(const KUrl& url).
+ // is populated lazily, see KFileItemModel::index(const QUrl& url).
if (m_items.count() > m_itemData.count()) {
return false;
}
return true;
}
-#include "kfileitemmodel.moc"