File 2003-better-selection.patch of Package dolphin
diff --git a/src/views/dolphinview.cpp b/src/views/dolphinview.cpp
index a2d3548193e3846fcb528d97649410916d9be2f8..f38987c2a08b2342063bd251c1625f3b9d27fea7 100644
--- a/src/views/dolphinview.cpp
+++ b/src/views/dolphinview.cpp
@@ -84,14 +84,8 @@ DolphinView::DolphinView(const QUrl &url, const QList<KeyPressHandler *> keyPres
, m_container(nullptr)
, m_toolTipManager(nullptr)
, m_selectionChangedTimer(nullptr)
- , m_currentItemUrl()
- , m_scrollToCurrentItem(false)
, m_restoredContentsPosition()
, m_controlWheelAccumulatedDelta(0)
- , m_selectedUrls()
- , m_clearSelectionBeforeSelectingNewItems(false)
- , m_markFirstNewlySelectedItemAsCurrent(false)
- , m_selectJobCreatedItems(false)
, m_ignoreSelectionChanges(false)
, m_versionControlObserver(nullptr)
, m_twoClicksRenamingTimer(nullptr)
@@ -202,6 +196,7 @@ DolphinView::DolphinView(const QUrl &url, const QList<KeyPressHandler *> keyPres
connect(m_model, &KFileItemModel::directoryRedirection, this, &DolphinView::slotDirectoryRedirection);
connect(m_model, &KFileItemModel::urlIsFileError, this, &DolphinView::urlIsFileError);
connect(m_model, &KFileItemModel::fileItemsChanged, this, &DolphinView::fileItemsChanged);
+ connect(m_model, &KFileItemModel::itemsRemoved, this, &DolphinView::slotItemsRemoved);
// #473377: Use a QueuedConnection to avoid modifying KCoreDirLister before KCoreDirListerCache::deleteDir() returns.
connect(m_model, &KFileItemModel::currentDirectoryRemoved, this, &DolphinView::currentDirectoryRemoved, Qt::QueuedConnection);
@@ -224,7 +219,9 @@ DolphinView::DolphinView(const QUrl &url, const QList<KeyPressHandler *> keyPres
KItemListSelectionManager *selectionManager = controller->selectionManager();
connect(selectionManager, &KItemListSelectionManager::selectionChanged, this, &DolphinView::slotSelectionChanged);
- connect(selectionManager, &KItemListSelectionManager::currentChanged, m_view, &DolphinItemListView::scrollToItem);
+ connect(selectionManager, &KItemListSelectionManager::currentChanged, m_view, [this](int current) {
+ m_view->scrollToItem(current);
+ });
#if HAVE_BALOO
m_toolTipManager = new ToolTipManager(this);
@@ -356,10 +353,6 @@ void DolphinView::setHiddenFilesShown(bool show)
return;
}
- const KFileItemList itemList = selectedItems();
- m_selectedUrls.clear();
- m_selectedUrls = itemList.urlList();
-
ViewProperties props(viewPropertiesUrl());
props.setHiddenFilesShown(show);
@@ -431,14 +424,14 @@ int DolphinView::selectedItemsCount() const
void DolphinView::markUrlsAsSelected(const QList<QUrl> &urls)
{
- m_selectedUrls = urls;
- m_selectJobCreatedItems = false;
+ m_jobInfo.jobs.clear();
+ m_jobInfo.urlsToSelect = urls;
}
void DolphinView::markUrlAsCurrent(const QUrl &url)
{
- m_currentItemUrl = url;
- m_scrollToCurrentItem = true;
+ m_jobInfo.jobs.clear();
+ m_jobInfo.urlToMakeCurrent = url;
}
void DolphinView::selectItems(const QRegularExpression ®exp, bool enabled)
@@ -731,8 +724,7 @@ void DolphinView::invertSelection()
void DolphinView::clearSelection()
{
- m_selectJobCreatedItems = false;
- m_selectedUrls.clear();
+ m_jobInfo.reset();
m_container->controller()->selectionManager()->clearSelection();
}
@@ -814,16 +806,15 @@ void DolphinView::copySelectedItems(const KFileItemList &selection, const QUrl &
return;
}
- m_clearSelectionBeforeSelectingNewItems = true;
- m_markFirstNewlySelectedItemAsCurrent = true;
- m_selectJobCreatedItems = true;
-
KIO::CopyJob *job = KIO::copy(selection.urlList(), destinationUrl, KIO::DefaultFlags);
KJobWidgets::setWindow(job, this);
- connect(job, &KIO::DropJob::result, this, &DolphinView::slotJobResult);
- connect(job, &KIO::CopyJob::copying, this, &DolphinView::slotItemCreatedFromJob);
+ m_jobInfo.jobs << job;
+
+ connect(job, &KIO::CopyJob::finished, this, &DolphinView::slotJobFinished);
+ connect(job, &KIO::CopyJob::result, this, &DolphinView::slotJobResult);
connect(job, &KIO::CopyJob::copyingDone, this, &DolphinView::slotItemCreatedFromJob);
+ connect(job, &KIO::CopyJob::copyingLinkDone, this, &DolphinView::slotItemLinkCreatedFromJob);
KIO::FileUndoManager::self()->recordCopyJob(job);
}
@@ -833,16 +824,15 @@ void DolphinView::moveSelectedItems(const KFileItemList &selection, const QUrl &
return;
}
- m_clearSelectionBeforeSelectingNewItems = true;
- m_markFirstNewlySelectedItemAsCurrent = true;
- m_selectJobCreatedItems = true;
-
KIO::CopyJob *job = KIO::move(selection.urlList(), destinationUrl, KIO::DefaultFlags);
KJobWidgets::setWindow(job, this);
- connect(job, &KIO::DropJob::result, this, &DolphinView::slotJobResult);
- connect(job, &KIO::CopyJob::moving, this, &DolphinView::slotItemCreatedFromJob);
+ m_jobInfo.jobs << job;
+
+ connect(job, &KIO::CopyJob::finished, this, &DolphinView::slotJobFinished);
+ connect(job, &KIO::CopyJob::result, this, &DolphinView::slotJobResult);
connect(job, &KIO::CopyJob::copyingDone, this, &DolphinView::slotItemCreatedFromJob);
+ connect(job, &KIO::CopyJob::copyingLinkDone, this, &DolphinView::slotItemLinkCreatedFromJob);
KIO::FileUndoManager::self()->recordCopyJob(job);
}
@@ -868,10 +858,6 @@ void DolphinView::duplicateSelectedItems()
const QMimeDatabase db;
- m_clearSelectionBeforeSelectingNewItems = true;
- m_markFirstNewlySelectedItemAsCurrent = true;
- m_selectJobCreatedItems = true;
-
// Duplicate all selected items and append "copy" to the end of the file name
// but before the filename extension, if present
for (const auto &item : itemList) {
@@ -901,6 +887,9 @@ void DolphinView::duplicateSelectedItems()
job->setAutoRename(true);
KJobWidgets::setWindow(job, this);
+ m_jobInfo.jobs << job;
+
+ connect(job, &KIO::CopyJob::finished, this, &DolphinView::slotJobFinished);
connect(job, &KIO::CopyJob::result, this, &DolphinView::slotJobResult);
connect(job, &KIO::CopyJob::copyingDone, this, &DolphinView::slotItemCreatedFromJob);
connect(job, &KIO::CopyJob::copyingLinkDone, this, &DolphinView::slotItemLinkCreatedFromJob);
@@ -1368,24 +1357,16 @@ void DolphinView::slotItemDropEvent(int index, QGraphicsSceneDragDropEvent *even
void DolphinView::dropUrls(const QUrl &destUrl, QDropEvent *dropEvent, QWidget *dropWidget)
{
KIO::DropJob *job = DragAndDropHelper::dropUrls(destUrl, dropEvent, dropWidget);
-
if (job) {
+ KJobWidgets::setWindow(job, this);
connect(job, &KIO::DropJob::result, this, &DolphinView::slotJobResult);
if (destUrl == url()) {
- // Mark the dropped urls as selected.
- m_clearSelectionBeforeSelectingNewItems = true;
- m_markFirstNewlySelectedItemAsCurrent = true;
- m_selectJobCreatedItems = true;
- connect(job, &KIO::DropJob::itemCreated, this, &DolphinView::slotItemCreated);
- connect(job, &KIO::DropJob::copyJobStarted, this, [this](const KIO::CopyJob *copyJob) {
- connect(copyJob, &KIO::CopyJob::copying, this, &DolphinView::slotItemCreatedFromJob);
- connect(copyJob, &KIO::CopyJob::moving, this, &DolphinView::slotItemCreatedFromJob);
- connect(copyJob, &KIO::CopyJob::linking, this, [this](KIO::Job *job, const QString &src, const QUrl &dest) {
- Q_UNUSED(job)
- Q_UNUSED(src)
- slotItemCreated(dest);
- });
+ m_jobInfo.jobs << job;
+ connect(job, &KIO::DropJob::finished, this, &DolphinView::slotJobFinished);
+ connect(job, &KIO::DropJob::copyJobStarted, this, [this](KIO::CopyJob *copyJob) {
+ connect(copyJob, &KIO::CopyJob::copyingDone, this, &DolphinView::slotItemCreatedFromJob);
+ connect(copyJob, &KIO::CopyJob::copyingLinkDone, this, &DolphinView::slotItemLinkCreatedFromJob);
});
}
}
@@ -1433,35 +1414,41 @@ void DolphinView::slotSelectedItemTextPressed(int index)
}
}
-void DolphinView::slotItemCreatedFromJob(KIO::Job *, const QUrl &, const QUrl &to)
+void DolphinView::slotItemCreatedFromJob(KIO::Job *job, const QUrl &from, const QUrl &to)
{
- slotItemCreated(to);
+ Q_UNUSED(from);
+
+ slotItemCreated(to, job);
}
-void DolphinView::slotItemLinkCreatedFromJob(KIO::Job *, const QUrl &, const QString &, const QUrl &to)
+void DolphinView::slotItemLinkCreatedFromJob(KIO::Job *job, const QUrl &from, const QString &target, const QUrl &to)
{
- slotItemCreated(to);
+ Q_UNUSED(from);
+ Q_UNUSED(target);
+
+ slotItemCreated(to, job);
}
-void DolphinView::slotItemCreated(const QUrl &url)
+void DolphinView::slotItemCreated(const QUrl &url, KIO::Job *job)
{
- if (m_markFirstNewlySelectedItemAsCurrent) {
- markUrlAsCurrent(url);
- m_markFirstNewlySelectedItemAsCurrent = false;
+ if (!m_jobInfo.jobs.contains(job) && !m_jobInfo.jobs.contains(job->parentJob())) {
+ return;
+ }
+ // skip an item that is already in the list or not in the current folder
+ for (const QUrl &jobUrl : std::as_const(m_jobInfo.urlsToSelect)) {
+ if (jobUrl == url || jobUrl.isParentOf(url)) {
+ return;
+ }
}
- if (m_selectJobCreatedItems && !m_selectedUrls.contains(url)) {
- m_selectedUrls << url;
+ if (m_jobInfo.urlsToSelect.isEmpty()) {
+ m_jobInfo.urlToMakeCurrent = url;
}
+ m_jobInfo.urlsToSelect << url;
}
-void DolphinView::onDirectoryLoadingCompletedAfterJob()
+void DolphinView::slotJobFinished(KJob *job)
{
- // the model should now contain all the items created by the job
- m_selectJobCreatedItems = true; // to make sure we overwrite selection
- // update the view: scroll into View and selection
- updateViewState();
- m_selectJobCreatedItems = false;
- m_selectedUrls.clear();
+ m_jobInfo.jobs.remove(job);
}
void DolphinView::slotJobResult(KJob *job)
@@ -1469,32 +1456,14 @@ void DolphinView::slotJobResult(KJob *job)
if (job->error() && job->error() != KIO::ERR_USER_CANCELED) {
Q_EMIT errorMessage(job->errorString(), job->error());
}
- if (!m_selectJobCreatedItems) {
- m_selectedUrls.clear();
- return;
- }
- if (!m_selectedUrls.isEmpty()) {
- m_selectedUrls = KDirModel::simplifiedUrlList(m_selectedUrls);
-
- updateViewState();
- if (!m_currentItemUrl.isEmpty() || !m_selectedUrls.isEmpty()) {
- // not all urls were found, the model may not be up to date
- connect(m_model, &KFileItemModel::directoryLoadingCompleted, this, &DolphinView::onDirectoryLoadingCompletedAfterJob, Qt::SingleShotConnection);
- } else {
- m_selectJobCreatedItems = false;
- m_currentItemUrl.clear();
- m_selectedUrls.clear();
- }
- }
}
void DolphinView::slotSelectionChanged(const KItemSet ¤t, const KItemSet &previous)
{
m_selectNextItem = false;
- if (!m_ignoreSelectionChanges) {
- m_selectJobCreatedItems = false;
- m_selectedUrls.clear();
+ if (!m_ignoreSelectionChanges && current.count() != previous.count()) {
+ m_jobInfo.reset();
}
const int currentCount = current.count();
@@ -1607,10 +1576,10 @@ void DolphinView::restoreState(QDataStream &stream)
}
// Restore the current item that had the keyboard focus
- stream >> m_currentItemUrl;
+ stream >> m_jobInfo.urlToMakeCurrent;
// Restore the previously selected items
- stream >> m_selectedUrls;
+ stream >> m_jobInfo.urlsToSelect;
// Restore the view position
stream >> m_restoredContentsPosition;
@@ -1735,28 +1704,19 @@ void DolphinView::updateViewState()
{
IgnoreSelectionChangesScopeGuard guard(this, true);
- if (!m_currentItemUrl.isEmpty()) {
+ if (!m_jobInfo.urlToMakeCurrent.isEmpty()) {
KItemListSelectionManager *selectionManager = m_container->controller()->selectionManager();
- // if there is a selection already, leave it that way
- // unless some drop/paste job are in the process of creating items
- if (!selectionManager->hasSelection() || m_selectJobCreatedItems) {
- const int currentIndex = m_model->index(m_currentItemUrl);
- if (currentIndex != -1) {
- selectionManager->setCurrentItem(currentIndex);
-
- // scroll to current item and reset the state
- if (m_scrollToCurrentItem) {
- m_view->scrollToItem(currentIndex, KItemListView::ViewItemPosition::Middle);
- m_scrollToCurrentItem = false;
- }
- m_currentItemUrl.clear();
- } else {
- selectionManager->setCurrentItem(0);
- }
+ const int currentIndex = m_model->index(m_jobInfo.urlToMakeCurrent);
+ selectionManager->endAnchoredSelection();
+ if (currentIndex != -1) {
+ selectionManager->setCurrentItem(currentIndex);
+ m_view->scrollToItem(currentIndex, KItemListView::ViewItemPosition::Middle);
} else {
- m_currentItemUrl.clear();
+ selectionManager->setCurrentItem(0);
}
+
+ m_jobInfo.urlToMakeCurrent.clear();
}
if (!m_restoredContentsPosition.isNull()) {
@@ -1768,39 +1728,24 @@ void DolphinView::updateViewState()
m_container->verticalScrollBar()->setValue(y);
}
- if (!m_selectedUrls.isEmpty()) {
- KItemListSelectionManager *selectionManager = m_container->controller()->selectionManager();
-
- const bool shouldScrollToCurrentItem = m_clearSelectionBeforeSelectingNewItems;
- // if there is a selection already, leave it that way
- // unless some drop/paste job are in the process of creating items
- if (!selectionManager->hasSelection() || m_selectJobCreatedItems) {
- if (m_clearSelectionBeforeSelectingNewItems) {
- selectionManager->clearSelection();
- m_clearSelectionBeforeSelectingNewItems = false;
+ if (!m_jobInfo.urlsToSelect.isEmpty()) {
+ KItemSet itemsToSelect;
+ for (const QUrl &url : std::as_const(m_jobInfo.urlsToSelect)) {
+ const int index = m_model->index(url);
+ if (index != -1) {
+ itemsToSelect << index;
}
+ }
- KItemSet selectedItems = selectionManager->selectedItems();
-
- QList<QUrl>::iterator it = m_selectedUrls.begin();
- while (it != m_selectedUrls.end()) {
- const int index = m_model->index(*it);
- if (index >= 0) {
- selectedItems.insert(index);
- it = m_selectedUrls.erase(it);
- } else {
- ++it;
- }
- }
+ if (!itemsToSelect.isEmpty()) {
+ KItemListSelectionManager *selectionManager = m_container->controller()->selectionManager();
+ selectionManager->endAnchoredSelection();
+ selectionManager->setSelectedItems(itemsToSelect);
+ selectionManager->beginAnchoredSelection(selectionManager->currentItem());
+ }
- if (!selectedItems.isEmpty()) {
- selectionManager->beginAnchoredSelection(selectionManager->currentItem());
- selectionManager->setSelectedItems(selectedItems);
- selectionManager->endAnchoredSelection();
- if (shouldScrollToCurrentItem) {
- m_view->scrollToItem(selectedItems.first());
- }
- }
+ if (m_jobInfo.jobs.isEmpty() && m_jobInfo.urlsToSelect.count() == itemsToSelect.count()) {
+ m_jobInfo.urlsToSelect.clear();
}
}
}
@@ -2204,24 +2149,23 @@ void DolphinView::applyModeToView()
}
}
-void DolphinView::pasteToUrl(const QUrl &url)
+void DolphinView::pasteToUrl(const QUrl &destUrl)
{
- KIO::PasteJob *job = KIO::paste(QApplication::clipboard()->mimeData(), url);
+ KIO::PasteJob *job = KIO::paste(QApplication::clipboard()->mimeData(), destUrl);
KJobWidgets::setWindow(job, this);
- m_clearSelectionBeforeSelectingNewItems = true;
- m_markFirstNewlySelectedItemAsCurrent = true;
- m_selectJobCreatedItems = true;
- connect(job, &KIO::PasteJob::itemCreated, this, &DolphinView::slotItemCreated);
- connect(job, &KIO::PasteJob::copyJobStarted, this, [this](const KIO::CopyJob *copyJob) {
- connect(copyJob, &KIO::CopyJob::copying, this, &DolphinView::slotItemCreatedFromJob);
- connect(copyJob, &KIO::CopyJob::moving, this, &DolphinView::slotItemCreatedFromJob);
- connect(copyJob, &KIO::CopyJob::linking, this, [this](KIO::Job *job, const QString &src, const QUrl &dest) {
- Q_UNUSED(job)
- Q_UNUSED(src)
- slotItemCreated(dest);
- });
- });
connect(job, &KIO::PasteJob::result, this, &DolphinView::slotJobResult);
+
+ if (destUrl == url()) {
+ m_jobInfo.jobs << job;
+ connect(job, &KIO::DropJob::finished, this, &DolphinView::slotJobFinished);
+ connect(job, &KIO::PasteJob::itemCreated, this, [this, job](const QUrl &url) {
+ slotItemCreated(url, job);
+ });
+ connect(job, &KIO::PasteJob::copyJobStarted, this, [this](KIO::CopyJob *copyJob) {
+ connect(copyJob, &KIO::CopyJob::copyingDone, this, &DolphinView::slotItemCreatedFromJob);
+ connect(copyJob, &KIO::CopyJob::copyingLinkDone, this, &DolphinView::slotItemLinkCreatedFromJob);
+ });
+ }
}
QList<QUrl> DolphinView::simplifiedSelectedUrls() const
@@ -2291,7 +2235,6 @@ QUrl DolphinView::viewPropertiesUrl() const
void DolphinView::forceUrlsSelection(const QUrl ¤t, const QList<QUrl> &selected)
{
clearSelection();
- m_clearSelectionBeforeSelectingNewItems = true;
markUrlAsCurrent(current);
markUrlsAsSelected(selected);
}
@@ -2329,6 +2272,17 @@ void DolphinView::slotSwipeUp()
Q_EMIT goUpRequested();
}
+void DolphinView::slotItemsRemoved(const KItemRangeList &itemRanges)
+{
+ if (!m_jobInfo.urlsToSelect.isEmpty()) {
+ for (const KItemRange &range : itemRanges) {
+ for (int i = range.index, n = i + range.count; i< n; ++i) {
+ m_jobInfo.urlsToSelect.removeAll(m_model->fileItem(i).url());
+ }
+ }
+ }
+}
+
void DolphinView::showLoadingPlaceholder()
{
m_placeholderLabel->setText(i18n("Loading…"));
diff --git a/src/views/dolphinview.h b/src/views/dolphinview.h
index 75c5b05397bf159cb02d34d6eb5039a096e91ec2..65e23567124a0a258dc92cce5c9ab39d7031a7a6 100644
--- a/src/views/dolphinview.h
+++ b/src/views/dolphinview.h
@@ -20,6 +20,7 @@
#include <QMimeData>
#include <QPointer>
+#include <QSet>
#include <QUrl>
#include <QWidget>
@@ -31,6 +32,7 @@ class DolphinItemListView;
class KFileItemModel;
class KItemListContainer;
class KItemModelBase;
+class KItemRangeList;
class KItemSet;
class ToolTipManager;
class VersionControlObserver;
@@ -713,16 +715,23 @@ private Q_SLOTS:
void slotModelChanged(KItemModelBase *current, KItemModelBase *previous);
void slotMouseButtonPressed(int itemIndex, Qt::MouseButtons buttons);
void slotSelectedItemTextPressed(int index);
- void slotItemCreatedFromJob(KIO::Job *, const QUrl &, const QUrl &to);
- void slotItemLinkCreatedFromJob(KIO::Job *, const QUrl &, const QString &, const QUrl &to);
+ void slotItemCreatedFromJob(KIO::Job *job, const QUrl &from, const QUrl &to);
+ void slotItemLinkCreatedFromJob(KIO::Job *job, const QUrl &from, const QString &target, const QUrl &to);
void slotIncreaseZoom();
void slotDecreaseZoom();
void slotSwipeUp();
+ void slotItemsRemoved(const KItemRangeList &itemRanges);
/*
* Is called when new items get pasted or dropped.
*/
- void slotItemCreated(const QUrl &url);
+ void slotItemCreated(const QUrl &url, KIO::Job *job);
+
+ /*
+ * Is called when the job is finished, in any case.
+ */
+ void slotJobFinished(KJob *job);
+
/*
* Is called after all pasted or dropped items have been copied to destination.
*/
@@ -845,8 +854,6 @@ private Q_SLOTS:
void slotTwoClicksRenamingTimerTimeout();
- void onDirectoryLoadingCompletedAfterJob();
-
private:
void loadDirectory(const QUrl &url, bool reload = false);
@@ -884,7 +891,7 @@ private:
* Helper method for DolphinView::paste() and DolphinView::pasteIntoFolder().
* Pastes the clipboard data into the URL \a url.
*/
- void pasteToUrl(const QUrl &url);
+ void pasteToUrl(const QUrl &destUrl);
/**
* Returns a list of URLs for all selected items. The list is
@@ -958,20 +965,12 @@ private:
QTimer *m_selectionChangedTimer;
- QUrl m_currentItemUrl; // Used for making the view to remember the current URL after F5
- bool m_scrollToCurrentItem; // Used for marking we need to scroll to current item or not
QPoint m_restoredContentsPosition;
// Used for tracking the accumulated scroll amount (for zooming with high
// resolution scroll wheels)
int m_controlWheelAccumulatedDelta;
- QList<QUrl> m_selectedUrls; // Used for making the view to remember selections after F5 and file operations
- bool m_clearSelectionBeforeSelectingNewItems;
- bool m_markFirstNewlySelectedItemAsCurrent;
- /// Decides whether items created by jobs should automatically be selected.
- bool m_selectJobCreatedItems;
-
/// If true, then the selection was changed inside updateViewState()
bool m_ignoreSelectionChanges;
@@ -993,6 +992,19 @@ private:
const bool m_prevValue;
};
+ struct {
+ QList<QUrl> urlsToSelect;
+ QUrl urlToMakeCurrent;
+ QSet<KJob*> jobs;
+
+ void reset()
+ {
+ urlsToSelect.clear();
+ urlToMakeCurrent.clear();
+ jobs.clear();
+ }
+ } m_jobInfo;
+
VersionControlObserver *m_versionControlObserver;
QTimer *m_twoClicksRenamingTimer;