Add busy indicator

This commit is contained in:
reionwong 2021-11-14 08:01:00 +08:00
parent c9e03b9b4a
commit 8918480892
3 changed files with 112 additions and 15 deletions

View file

@ -75,6 +75,17 @@
#include <KFileItemListProperties> #include <KFileItemListProperties>
#include <KDesktopFile> #include <KDesktopFile>
static bool isDropBetweenSharedViews(const QList<QUrl> &urls, const QUrl &folderUrl)
{
for (const auto &url : urls) {
if (folderUrl.adjusted(QUrl::StripTrailingSlash) != url.adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash)) {
return false;
}
}
return true;
}
FolderModel::FolderModel(QObject *parent) FolderModel::FolderModel(QObject *parent)
: QSortFilterProxyModel(parent) : QSortFilterProxyModel(parent)
, m_dirWatch(nullptr) , m_dirWatch(nullptr)
@ -89,6 +100,7 @@ FolderModel::FolderModel(QObject *parent)
, m_selectedItemSize("") , m_selectedItemSize("")
, m_actionCollection(this) , m_actionCollection(this)
, m_dragInProgress(false) , m_dragInProgress(false)
, m_dropTargetPositionsCleanup(new QTimer(this))
, m_viewAdapter(nullptr) , m_viewAdapter(nullptr)
, m_mimeAppManager(MimeAppManager::self()) , m_mimeAppManager(MimeAppManager::self())
, m_sizeJob(nullptr) , m_sizeJob(nullptr)
@ -102,11 +114,65 @@ FolderModel::FolderModel(QObject *parent)
m_dirLister->setShowingDotFiles(m_showHiddenFiles); m_dirLister->setShowingDotFiles(m_showHiddenFiles);
// connect(dirLister, &DirLister::error, this, &FolderModel::notification); // connect(dirLister, &DirLister::error, this, &FolderModel::notification);
connect(m_dirLister, &KCoreDirLister::started, this, std::bind(&FolderModel::setStatus, this, Status::Listing));
void (KCoreDirLister::*myCompletedSignal)() = &KCoreDirLister::completed;
QObject::connect(m_dirLister, myCompletedSignal, this, [this] {
setStatus(Status::Ready);
emit listingCompleted();
});
void (KCoreDirLister::*myCanceledSignal)() = &KCoreDirLister::canceled;
QObject::connect(m_dirLister, myCanceledSignal, this, [this] {
setStatus(Status::Canceled);
emit listingCanceled();
});
m_dirModel = new KDirModel(this); m_dirModel = new KDirModel(this);
m_dirModel->setDirLister(m_dirLister); m_dirModel->setDirLister(m_dirLister);
m_dirModel->setDropsAllowed(KDirModel::DropOnDirectory | KDirModel::DropOnLocalExecutable); m_dirModel->setDropsAllowed(KDirModel::DropOnDirectory | KDirModel::DropOnLocalExecutable);
m_dirModel->moveToThread(qApp->thread()); m_dirModel->moveToThread(qApp->thread());
// If we have dropped items queued for moving, go unsorted now.
connect(this, &QAbstractItemModel::rowsAboutToBeInserted, this, [this]() {
if (!m_dropTargetPositions.isEmpty()) {
setSortMode(-1);
}
});
// Position dropped items at the desired target position.
connect(this, &QAbstractItemModel::rowsInserted, this, [this](const QModelIndex &parent, int first, int last) {
for (int i = first; i <= last; ++i) {
const auto idx = index(i, 0, parent);
const auto url = itemForIndex(idx).url();
auto it = m_dropTargetPositions.find(url.fileName());
if (it != m_dropTargetPositions.end()) {
const auto pos = it.value();
m_dropTargetPositions.erase(it);
Q_EMIT move(pos.x(), pos.y(), {url});
}
}
});
/*
* Dropped files may not actually show up as new files, e.g. when we overwrite
* an existing file. Or files that fail to be listed by the dirLister, or...
* To ensure we don't grow the map indefinitely, clean it up periodically.
* The cleanup timer is (re)started whenever we modify the map. We use a quite
* high interval of 10s. This should ensure, that we don't accidentally wipe
* the mapping when we actually still want to use it. Since the time between
* adding an entry in the map and it showing up in the model should be
* small, this should rarely, if ever happen.
*/
m_dropTargetPositionsCleanup->setInterval(10000);
m_dropTargetPositionsCleanup->setSingleShot(true);
connect(m_dropTargetPositionsCleanup, &QTimer::timeout, this, [this]() {
if (!m_dropTargetPositions.isEmpty()) {
qDebug() << "clearing drop target positions after timeout:" << m_dropTargetPositions;
m_dropTargetPositions.clear();
}
});
m_selectionModel = new QItemSelectionModel(this, this); m_selectionModel = new QItemSelectionModel(this, this);
connect(m_selectionModel, &QItemSelectionModel::selectionChanged, this, &FolderModel::selectionChanged); connect(m_selectionModel, &QItemSelectionModel::selectionChanged, this, &FolderModel::selectionChanged);
@ -1038,24 +1104,38 @@ void FolderModel::drop(QQuickItem *target, QObject *dropEvent, int row)
dropTargetUrl = item.mostLocalUrl(); dropTargetUrl = item.mostLocalUrl();
} }
auto dropTargetFolderUrl = dropTargetUrl;
if (dropTargetFolderUrl.fileName() == QLatin1Char('.')) {
// the target URL for desktop:/ is e.g. 'file://home/user/Desktop/.'
dropTargetFolderUrl = dropTargetFolderUrl.adjusted(QUrl::RemoveFilename);
}
const int x = dropEvent->property("x").toInt();
const int y = dropEvent->property("y").toInt();
const QPoint dropPos = {x, y};
if (m_dragInProgress && row == -1) {
if (mimeData->urls().isEmpty())
return;
setSortMode(-1);
for (const auto &url : mimeData->urls()) {
m_dropTargetPositions.insert(url.fileName(), dropPos);
}
emit move(x, y, mimeData->urls());
return;
}
if (idx.isValid() && !(flags(idx) & Qt::ItemIsDropEnabled)) { if (idx.isValid() && !(flags(idx) & Qt::ItemIsDropEnabled)) {
return; return;
} }
// 处理url if (!isDropBetweenSharedViews(mimeData->urls(), dropTargetFolderUrl)) {
QList<QUrl> sourceUrls; KIO::Job *job = KIO::move(mimeData->urls(), dropTargetUrl, KIO::HideProgressInfo);
for (const QUrl &url : mimeData->urls()) {
QFileInfo info(url.toLocalFile());
QUrl newUrl = QUrl::fromLocalFile(info.dir().path());
// 相同的目录下不加入
if (newUrl != dropTargetUrl) {
sourceUrls.append(url);
}
}
if (!sourceUrls.isEmpty()) {
KIO::Job *job = KIO::move(sourceUrls, dropTargetUrl, KIO::HideProgressInfo);
job->start(); job->start();
} }
} }

View file

@ -48,6 +48,7 @@ class FolderModel : public QSortFilterProxyModel, public QQmlParserStatus
Q_INTERFACES(QQmlParserStatus) Q_INTERFACES(QQmlParserStatus)
Q_PROPERTY(QString url READ url WRITE setUrl NOTIFY urlChanged) Q_PROPERTY(QString url READ url WRITE setUrl NOTIFY urlChanged)
Q_PROPERTY(QUrl resolvedUrl READ resolvedUrl NOTIFY resolvedUrlChanged) Q_PROPERTY(QUrl resolvedUrl READ resolvedUrl NOTIFY resolvedUrlChanged)
Q_PROPERTY(Status status READ status NOTIFY statusChanged)
Q_PROPERTY(int sortMode READ sortMode WRITE setSortMode NOTIFY sortModeChanged) Q_PROPERTY(int sortMode READ sortMode WRITE setSortMode NOTIFY sortModeChanged)
Q_PROPERTY(bool sortDirsFirst READ sortDirsFirst WRITE setSortDirsFirst NOTIFY sortDirsFirstChanged) Q_PROPERTY(bool sortDirsFirst READ sortDirsFirst WRITE setSortDirsFirst NOTIFY sortDirsFirstChanged)
Q_PROPERTY(bool dragging READ dragging NOTIFY draggingChanged) Q_PROPERTY(bool dragging READ dragging NOTIFY draggingChanged)
@ -225,6 +226,8 @@ public:
signals: signals:
void urlChanged(); void urlChanged();
void listingCompleted() const;
void listingCanceled() const;
void resolvedUrlChanged(); void resolvedUrlChanged();
void statusChanged(); void statusChanged();
void sortModeChanged(); void sortModeChanged();
@ -243,6 +246,7 @@ signals:
void showHiddenFilesChanged(); void showHiddenFilesChanged();
void notification(const QString &message); void notification(const QString &message);
void move(int x, int y, QList<QUrl> urls);
private slots: private slots:
void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected); void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
@ -296,6 +300,9 @@ private:
QPoint m_dragHotSpotScrollOffset; QPoint m_dragHotSpotScrollOffset;
bool m_dragInProgress; bool m_dragInProgress;
QHash<QString, QPoint> m_dropTargetPositions;
QTimer *m_dropTargetPositionsCleanup;
QPointer<ItemViewAdapter> m_viewAdapter; QPointer<ItemViewAdapter> m_viewAdapter;
// Save path history // Save path history

View file

@ -144,7 +144,8 @@ Item {
text: qsTr("Empty folder") text: qsTr("Empty folder")
font.pointSize: 15 font.pointSize: 15
anchors.centerIn: parent anchors.centerIn: parent
visible: false visible: dirModel.status === FM.FolderModel.Ready
&& _viewLoader.item.count === 0
} }
FM.FolderModel { FM.FolderModel {
@ -260,6 +261,15 @@ Item {
visible: dirModel.selectionCount >= 1 visible: dirModel.selectionCount >= 1
} }
FishUI.BusyIndicator {
id: _busyIndicator
Layout.alignment: Qt.AlignLeft
Layout.fillHeight: true
width: height
running: visible
visible: dirModel.status === FM.FolderModel.Listing
}
Label { Label {
text: dirModel.selectedItemSize text: dirModel.selectedItemSize
} }