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 <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)
|
||||
: QSortFilterProxyModel(parent)
|
||||
, m_dirWatch(nullptr)
|
||||
|
@ -89,6 +100,7 @@ FolderModel::FolderModel(QObject *parent)
|
|||
, m_selectedItemSize("")
|
||||
, m_actionCollection(this)
|
||||
, m_dragInProgress(false)
|
||||
, m_dropTargetPositionsCleanup(new QTimer(this))
|
||||
, m_viewAdapter(nullptr)
|
||||
, m_mimeAppManager(MimeAppManager::self())
|
||||
, m_sizeJob(nullptr)
|
||||
|
@ -102,11 +114,65 @@ FolderModel::FolderModel(QObject *parent)
|
|||
m_dirLister->setShowingDotFiles(m_showHiddenFiles);
|
||||
// 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->setDirLister(m_dirLister);
|
||||
m_dirModel->setDropsAllowed(KDirModel::DropOnDirectory | KDirModel::DropOnLocalExecutable);
|
||||
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);
|
||||
connect(m_selectionModel, &QItemSelectionModel::selectionChanged, this, &FolderModel::selectionChanged);
|
||||
|
||||
|
@ -1038,24 +1104,38 @@ void FolderModel::drop(QQuickItem *target, QObject *dropEvent, int row)
|
|||
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)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 处理url
|
||||
QList<QUrl> sourceUrls;
|
||||
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);
|
||||
if (!isDropBetweenSharedViews(mimeData->urls(), dropTargetFolderUrl)) {
|
||||
KIO::Job *job = KIO::move(mimeData->urls(), dropTargetUrl, KIO::HideProgressInfo);
|
||||
job->start();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,6 +48,7 @@ class FolderModel : public QSortFilterProxyModel, public QQmlParserStatus
|
|||
Q_INTERFACES(QQmlParserStatus)
|
||||
Q_PROPERTY(QString url READ url WRITE setUrl NOTIFY urlChanged)
|
||||
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(bool sortDirsFirst READ sortDirsFirst WRITE setSortDirsFirst NOTIFY sortDirsFirstChanged)
|
||||
Q_PROPERTY(bool dragging READ dragging NOTIFY draggingChanged)
|
||||
|
@ -225,6 +226,8 @@ public:
|
|||
|
||||
signals:
|
||||
void urlChanged();
|
||||
void listingCompleted() const;
|
||||
void listingCanceled() const;
|
||||
void resolvedUrlChanged();
|
||||
void statusChanged();
|
||||
void sortModeChanged();
|
||||
|
@ -243,6 +246,7 @@ signals:
|
|||
void showHiddenFilesChanged();
|
||||
|
||||
void notification(const QString &message);
|
||||
void move(int x, int y, QList<QUrl> urls);
|
||||
|
||||
private slots:
|
||||
void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
|
||||
|
@ -296,6 +300,9 @@ private:
|
|||
QPoint m_dragHotSpotScrollOffset;
|
||||
bool m_dragInProgress;
|
||||
|
||||
QHash<QString, QPoint> m_dropTargetPositions;
|
||||
QTimer *m_dropTargetPositionsCleanup;
|
||||
|
||||
QPointer<ItemViewAdapter> m_viewAdapter;
|
||||
|
||||
// Save path history
|
||||
|
|
|
@ -144,7 +144,8 @@ Item {
|
|||
text: qsTr("Empty folder")
|
||||
font.pointSize: 15
|
||||
anchors.centerIn: parent
|
||||
visible: false
|
||||
visible: dirModel.status === FM.FolderModel.Ready
|
||||
&& _viewLoader.item.count === 0
|
||||
}
|
||||
|
||||
FM.FolderModel {
|
||||
|
@ -260,6 +261,15 @@ Item {
|
|||
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 {
|
||||
text: dirModel.selectedItemSize
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue