Add busy indicator
This commit is contained in:
parent
c9e03b9b4a
commit
8918480892
3 changed files with 112 additions and 15 deletions
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue