]> cloud.milkyroute.net Git - dolphin.git/blobdiff - src/views/dolphinview.cpp
Merge remote-tracking branch 'origin/master' into kf6
[dolphin.git] / src / views / dolphinview.cpp
index 288b3ac5d0e5f05a0626b4718e8e3724423f9e63..e27f423f6b79c2a2f863f79f921696b30b2d6218 100644 (file)
@@ -35,7 +35,7 @@
 #include <KFileItemListProperties>
 #include <KFormat>
 #include <KIO/CopyJob>
-#include <KIO/DeleteJob>
+#include <KIO/DeleteOrTrashJob>
 #include <KIO/DropJob>
 #include <KIO/JobUiDelegate>
 #include <KIO/Paste>
 
 #include <kwidgetsaddons_version.h>
 
-#include <kio_version.h>
-#if KIO_VERSION >= QT_VERSION_CHECK(5, 100, 0)
-#include <KIO/DeleteOrTrashJob>
-#endif
-
 #include <QAbstractItemView>
 #include <QActionGroup>
 #include <QApplication>
@@ -92,6 +87,7 @@ DolphinView::DolphinView(const QUrl &url, QWidget *parent)
     , m_currentItemUrl()
     , m_scrollToCurrentItem(false)
     , m_restoredContentsPosition()
+    , m_controlWheelAccumulatedDelta(0)
     , m_selectedUrls()
     , m_clearSelectionBeforeSelectingNewItems(false)
     , m_markFirstNewlySelectedItemAsCurrent(false)
@@ -280,6 +276,10 @@ bool DolphinView::isActive() const
 void DolphinView::setViewMode(Mode mode)
 {
     if (mode != m_mode) {
+        // Reset scrollbars before changing the view mode.
+        m_container->horizontalScrollBar()->setValue(0);
+        m_container->verticalScrollBar()->setValue(0);
+
         ViewProperties props(viewPropertiesUrl());
         props.setViewMode(mode);
 
@@ -424,6 +424,7 @@ int DolphinView::selectedItemsCount() const
 void DolphinView::markUrlsAsSelected(const QList<QUrl> &urls)
 {
     m_selectedUrls = urls;
+    m_selectJobCreatedItems = false;
 }
 
 void DolphinView::markUrlAsCurrent(const QUrl &url)
@@ -622,7 +623,7 @@ void DolphinView::requestStatusBarText()
             return;
         }
 
-        m_statJobForStatusBarText = KIO::statDetails(m_model->rootItem().url(), KIO::StatJob::SourceSide, KIO::StatRecursiveSize, KIO::HideProgressInfo);
+        m_statJobForStatusBarText = KIO::stat(m_model->rootItem().url(), KIO::StatJob::SourceSide, KIO::StatRecursiveSize, KIO::HideProgressInfo);
         connect(m_statJobForStatusBarText, &KJob::result, this, &DolphinView::slotStatJobResult);
         m_statJobForStatusBarText->start();
     }
@@ -711,6 +712,7 @@ void DolphinView::invertSelection()
 
 void DolphinView::clearSelection()
 {
+    m_selectJobCreatedItems = false;
     m_selectedUrls.clear();
     m_container->controller()->selectionManager()->clearSelection();
 }
@@ -755,43 +757,22 @@ void DolphinView::trashSelectedItems()
 {
     const QList<QUrl> list = simplifiedSelectedUrls();
 
-#if KIO_VERSION >= QT_VERSION_CHECK(5, 100, 0)
     using Iface = KIO::AskUserActionInterface;
     auto *trashJob = new KIO::DeleteOrTrashJob(list, Iface::Trash, Iface::DefaultConfirmation, this);
     connect(trashJob, &KJob::result, this, &DolphinView::slotTrashFileFinished);
     m_selectNextItem = true;
     trashJob->start();
-#else
-    KIO::JobUiDelegate uiDelegate;
-    uiDelegate.setWindow(window());
-    if (uiDelegate.askDeleteConfirmation(list, KIO::JobUiDelegate::Trash, KIO::JobUiDelegate::DefaultConfirmation)) {
-        KIO::Job *job = KIO::trash(list);
-        KIO::FileUndoManager::self()->recordJob(KIO::FileUndoManager::Trash, list, QUrl(QStringLiteral("trash:/")), job);
-        KJobWidgets::setWindow(job, this);
-        connect(job, &KIO::Job::result, this, &DolphinView::slotTrashFileFinished);
-    }
-#endif
 }
 
 void DolphinView::deleteSelectedItems()
 {
     const QList<QUrl> list = simplifiedSelectedUrls();
 
-#if KIO_VERSION >= QT_VERSION_CHECK(5, 100, 0)
     using Iface = KIO::AskUserActionInterface;
     auto *trashJob = new KIO::DeleteOrTrashJob(list, Iface::Delete, Iface::DefaultConfirmation, this);
     connect(trashJob, &KJob::result, this, &DolphinView::slotTrashFileFinished);
     m_selectNextItem = true;
     trashJob->start();
-#else
-    KIO::JobUiDelegate uiDelegate;
-    uiDelegate.setWindow(window());
-    if (uiDelegate.askDeleteConfirmation(list, KIO::JobUiDelegate::Delete, KIO::JobUiDelegate::DefaultConfirmation)) {
-        KIO::Job *job = KIO::del(list);
-        KJobWidgets::setWindow(job, this);
-        connect(job, &KIO::Job::result, this, &DolphinView::slotDeleteFileFinished);
-    }
-#endif
 }
 
 void DolphinView::cutSelectedItemsToClipboard()
@@ -811,21 +792,39 @@ void DolphinView::copySelectedItemsToClipboard()
 
 void DolphinView::copySelectedItems(const KFileItemList &selection, const QUrl &destinationUrl)
 {
+    if (selection.isEmpty() || !destinationUrl.isValid()) {
+        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::copyingDone, this, &DolphinView::slotCopyingDone);
+    connect(job, &KIO::CopyJob::copying, this, &DolphinView::slotItemCreatedFromJob);
+    connect(job, &KIO::CopyJob::copyingDone, this, &DolphinView::slotItemCreatedFromJob);
     KIO::FileUndoManager::self()->recordCopyJob(job);
 }
 
 void DolphinView::moveSelectedItems(const KFileItemList &selection, const QUrl &destinationUrl)
 {
+    if (selection.isEmpty() || !destinationUrl.isValid()) {
+        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::copyingDone, this, &DolphinView::slotCopyingDone);
+    connect(job, &KIO::CopyJob::moving, this, &DolphinView::slotItemCreatedFromJob);
+    connect(job, &KIO::CopyJob::copyingDone, this, &DolphinView::slotItemCreatedFromJob);
     KIO::FileUndoManager::self()->recordCopyJob(job);
 }
 
@@ -1060,24 +1059,14 @@ void DolphinView::slotItemsActivated(const KItemSet &indexes)
 
     if (indexes.count() > 5) {
         QString question = i18np("Are you sure you want to open 1 item?", "Are you sure you want to open %1 items?", indexes.count());
-#if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 100, 0)
-        const int answer = KMessageBox::warningTwoActions(
+        const int answer = KMessageBox::warningContinueCancel(
             this,
             question,
             {},
-#else
-        const int answer =
-            KMessageBox::warningYesNo(this,
-                                      question,
-                                      {},
-#endif
             KGuiItem(i18ncp("@action:button", "Open %1 Item", "Open %1 Items", indexes.count()), QStringLiteral("document-open")),
-            KStandardGuiItem::cancel());
-#if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 100, 0)
-        if (answer != KMessageBox::PrimaryAction) {
-#else
-        if (answer != KMessageBox::Yes) {
-#endif
+            KStandardGuiItem::cancel(),
+            QStringLiteral("ConfirmOpenManyFolders"));
+        if (answer != KMessageBox::PrimaryAction && answer != KMessageBox::Continue) {
             return;
         }
     }
@@ -1115,6 +1104,7 @@ void DolphinView::slotItemMiddleClicked(int index)
     const KFileItem &item = m_model->fileItem(index);
     const QUrl &url = openItemAsFolderUrl(item);
     const auto modifiers = QGuiApplication::keyboardModifiers();
+    const QString &archiveProtocol = KProtocolManager::protocolForArchiveMimetype(item.mimetype());
     if (!url.isEmpty()) {
         // keep in sync with KUrlNavigator::slotNavigatorButtonClicked
         if (modifiers & Qt::ShiftModifier) {
@@ -1122,13 +1112,15 @@ void DolphinView::slotItemMiddleClicked(int index)
         } else {
             Q_EMIT tabRequested(url);
         }
-    } else if (isTabsForFilesEnabled()) {
+    } else if (!archiveProtocol.isEmpty() && isTabsForFilesEnabled()) {
         // keep in sync with KUrlNavigator::slotNavigatorButtonClicked
         if (modifiers & Qt::ShiftModifier) {
             Q_EMIT activeTabRequested(item.url());
         } else {
             Q_EMIT tabRequested(item.url());
         }
+    } else {
+        Q_EMIT fileMiddleClickActivated(item);
     }
 }
 
@@ -1355,7 +1347,17 @@ void DolphinView::dropUrls(const QUrl &destUrl, QDropEvent *dropEvent, QWidget *
             // 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);
+                });
+            });
         }
     }
 }
@@ -1402,7 +1404,7 @@ void DolphinView::slotSelectedItemTextPressed(int index)
     }
 }
 
-void DolphinView::slotCopyingDone(KIO::Job *, const QUrl &, const QUrl &to)
+void DolphinView::slotItemCreatedFromJob(KIO::Job *, const QUrl &, const QUrl &to)
 {
     slotItemCreated(to);
 }
@@ -1413,7 +1415,17 @@ void DolphinView::slotItemCreated(const QUrl &url)
         markUrlAsCurrent(url);
         m_markFirstNewlySelectedItemAsCurrent = false;
     }
-    m_selectedUrls << url;
+    if (m_selectJobCreatedItems && !m_selectedUrls.contains(url)) {
+        m_selectedUrls << url;
+    }
+}
+
+void DolphinView::onDirectoryLoadingCompleted()
+{
+    // the model should now contain all the items created by the job
+    updateSelectionState();
+    m_selectJobCreatedItems = false;
+    m_selectedUrls.clear();
 }
 
 void DolphinView::slotJobResult(KJob *job)
@@ -1421,8 +1433,21 @@ void DolphinView::slotJobResult(KJob *job)
     if (job->error() && job->error() != KIO::ERR_USER_CANCELED) {
         Q_EMIT errorMessage(job->errorString());
     }
+    if (!m_selectJobCreatedItems) {
+        m_selectedUrls.clear();
+        return;
+    }
     if (!m_selectedUrls.isEmpty()) {
         m_selectedUrls = KDirModel::simplifiedUrlList(m_selectedUrls);
+
+        updateSelectionState();
+        if (!m_selectedUrls.isEmpty()) {
+            // not all urls were found, the model may not be up to date
+            connect(m_model, &KFileItemModel::directoryLoadingCompleted, this, &DolphinView::onDirectoryLoadingCompleted, Qt::UniqueConnection);
+        } else {
+            m_selectJobCreatedItems = false;
+            m_selectedUrls.clear();
+        }
     }
 }
 
@@ -1684,6 +1709,40 @@ void DolphinView::slotDirectoryRedirection(const QUrl &oldUrl, const QUrl &newUr
     }
 }
 
+void DolphinView::updateSelectionState()
+{
+    if (!m_selectedUrls.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) {
+            if (m_clearSelectionBeforeSelectingNewItems) {
+                selectionManager->clearSelection();
+                m_clearSelectionBeforeSelectingNewItems = false;
+            }
+
+            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 (!selectedItems.isEmpty()) {
+                selectionManager->beginAnchoredSelection(selectionManager->currentItem());
+                selectionManager->setSelectedItems(selectedItems);
+            }
+        }
+    }
+}
+
 void DolphinView::updateViewState()
 {
     if (m_currentItemUrl != QUrl()) {
@@ -1718,35 +1777,7 @@ void DolphinView::updateViewState()
         m_container->verticalScrollBar()->setValue(y);
     }
 
-    if (!m_selectedUrls.isEmpty()) {
-        KItemListSelectionManager *selectionManager = m_container->controller()->selectionManager();
-
-        // if there is a selection already, leave it that way
-        if (!selectionManager->hasSelection()) {
-            if (m_clearSelectionBeforeSelectingNewItems) {
-                selectionManager->clearSelection();
-                m_clearSelectionBeforeSelectingNewItems = false;
-            }
-
-            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 (!selectedItems.isEmpty()) {
-                selectionManager->beginAnchoredSelection(selectionManager->currentItem());
-                selectionManager->setSelectedItems(selectedItems);
-            }
-        }
-    }
+    updateSelectionState();
 }
 
 void DolphinView::hideToolTip(const ToolTipManager::HideBehavior behavior)
@@ -1762,6 +1793,11 @@ void DolphinView::hideToolTip(const ToolTipManager::HideBehavior behavior)
     }
 }
 
+bool DolphinView::handleSpaceAsNormalKey() const
+{
+    return !m_container->hasFocus() || m_container->controller()->isSearchAsYouTypeActive();
+}
+
 void DolphinView::slotTwoClicksRenamingTimerTimeout()
 {
     const KItemListSelectionManager *selectionManager = m_container->controller()->selectionManager();
@@ -1950,13 +1986,8 @@ void DolphinView::slotRoleEditingFinished(int index, const QByteArray &role, con
             if (!hiddenFilesShown() && newName.startsWith(QLatin1Char('.')) && !oldItem.name().startsWith(QLatin1Char('.'))) {
                 KGuiItem yesGuiItem(i18nc("@action:button", "Rename and Hide"), QStringLiteral("view-hidden"));
 
-#if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 100, 0)
                 const auto code =
                     KMessageBox::questionTwoActions(this,
-#else
-                const auto code =
-                    KMessageBox::questionYesNo(this,
-#endif
                                                     oldItem.isFile() ? i18n("Adding a dot to the beginning of this file's name will hide it from view.\n"
                                                                             "Do you still want to rename it?")
                                                                      : i18n("Adding a dot to the beginning of this folder's name will hide it from view.\n"
@@ -1966,11 +1997,7 @@ void DolphinView::slotRoleEditingFinished(int index, const QByteArray &role, con
                                                     KStandardGuiItem::cancel(),
                                                     QStringLiteral("ConfirmHide"));
 
-#if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 100, 0)
                 if (code == KMessageBox::SecondaryAction) {
-#else
-                if (code == KMessageBox::No) {
-#endif
                     return;
                 }
             }
@@ -1993,9 +2020,9 @@ void DolphinView::slotRoleEditingFinished(int index, const QByteArray &role, con
             KIO::FileUndoManager::self()->recordJob(KIO::FileUndoManager::Rename, {oldUrl}, newUrl, job);
             job->uiDelegate()->setAutoErrorHandlingEnabled(true);
 
-            forceUrlsSelection(newUrl, {newUrl});
-
             if (!newNameExistsAlready) {
+                forceUrlsSelection(newUrl, {newUrl});
+
                 // Only connect the result signal if there is no item with the new name
                 // in the model yet, see bug 328262.
                 connect(job, &KJob::result, this, &DolphinView::slotRenamingResult);
@@ -2160,6 +2187,8 @@ void DolphinView::pasteToUrl(const QUrl &url)
     KJobWidgets::setWindow(job, this);
     m_clearSelectionBeforeSelectingNewItems = true;
     m_markFirstNewlySelectedItemAsCurrent = true;
+    m_selectJobCreatedItems = true;
+    // TODO KF6 use KIO::PasteJob::copyJobStarted to hook to earlier events copying/moving
     connect(job, &KIO::PasteJob::itemCreated, this, &DolphinView::slotItemCreated);
     connect(job, &KIO::PasteJob::result, this, &DolphinView::slotJobResult);
 }
@@ -2251,7 +2280,7 @@ void DolphinView::copyPathToClipboard()
     if (clipboard == nullptr) {
         return;
     }
-    clipboard->setText(path);
+    clipboard->setText(QDir::toNativeSeparators(path));
 }
 
 void DolphinView::slotIncreaseZoom()
@@ -2271,7 +2300,7 @@ void DolphinView::slotSwipeUp()
 
 void DolphinView::showLoadingPlaceholder()
 {
-    m_placeholderLabel->setText(i18n("Loading..."));
+    m_placeholderLabel->setText(i18n("Loading"));
     m_placeholderLabel->setVisible(true);
 }
 
@@ -2346,3 +2375,5 @@ bool DolphinView::tryShowNameToolTip(QHelpEvent *event)
     }
     return false;
 }
+
+#include "moc_dolphinview.cpp"