]> cloud.milkyroute.net Git - dolphin.git/blobdiff - src/views/dolphinview.cpp
Fix a bunch of Qt6/Kf6 warnings
[dolphin.git] / src / views / dolphinview.cpp
index 35d69e610e69ad4c247660f6b918149c07ae88ae..9a6ef8f7b87c5c777d7f1c2c63ed4029e2101a46 100644 (file)
@@ -78,6 +78,7 @@ DolphinView::DolphinView(const QUrl &url, QWidget *parent)
     , m_assureVisibleCurrentIndex(false)
     , m_isFolderWritable(true)
     , m_dragging(false)
+    , m_selectNextItem(false)
     , m_url(url)
     , m_viewPropertiesContext()
     , m_mode(DolphinView::IconsView)
@@ -209,6 +210,13 @@ DolphinView::DolphinView(const QUrl &url, QWidget *parent)
     connect(m_view, &DolphinItemListView::sortRoleChanged, this, &DolphinView::slotSortRoleChangedByHeader);
     connect(m_view, &DolphinItemListView::visibleRolesChanged, this, &DolphinView::slotVisibleRolesChangedByHeader);
     connect(m_view, &DolphinItemListView::roleEditingCanceled, this, &DolphinView::slotRoleEditingCanceled);
+
+    connect(m_view, &DolphinItemListView::columnHovered, this, [this](int columnIndex) {
+        m_hoveredColumnHeaderIndex = columnIndex;
+    });
+    connect(m_view, &DolphinItemListView::columnUnHovered, this, [this](int /* columnIndex */) {
+        m_hoveredColumnHeaderIndex = std::nullopt;
+    });
     connect(m_view->header(), &KItemListHeader::columnWidthChangeFinished, this, &DolphinView::slotHeaderColumnWidthChangeFinished);
     connect(m_view->header(), &KItemListHeader::sidePaddingChanged, this, &DolphinView::slotSidePaddingWidthChanged);
 
@@ -291,7 +299,9 @@ DolphinView::Mode DolphinView::viewMode() const
 void DolphinView::setSelectionModeEnabled(const bool enabled)
 {
     if (enabled) {
-        m_proxyStyle = std::make_unique<SelectionMode::SingleClickSelectionProxyStyle>();
+        if (!m_proxyStyle) {
+            m_proxyStyle = std::make_unique<SelectionMode::SingleClickSelectionProxyStyle>();
+        }
         setStyle(m_proxyStyle.get());
         m_view->setStyle(m_proxyStyle.get());
         m_view->setEnabledSelectionToggles(DolphinItemListView::SelectionTogglesEnabled::False);
@@ -414,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)
@@ -612,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();
     }
@@ -701,6 +712,7 @@ void DolphinView::invertSelection()
 
 void DolphinView::clearSelection()
 {
+    m_selectJobCreatedItems = false;
     m_selectedUrls.clear();
     m_container->controller()->selectionManager()->clearSelection();
 }
@@ -749,6 +761,7 @@ void DolphinView::trashSelectedItems()
     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;
@@ -770,6 +783,7 @@ void DolphinView::deleteSelectedItems()
     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;
@@ -799,21 +813,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);
 }
 
@@ -928,6 +960,11 @@ bool DolphinView::eventFilter(QObject *watched, QEvent *event)
             }
         }
         break;
+    case QEvent::KeyRelease:
+        if (static_cast<QKeyEvent *>(event)->key() == Qt::Key_Control) {
+            m_controlWheelAccumulatedDelta = 0;
+        }
+        break;
     case QEvent::FocusIn:
         if (watched == m_container) {
             setActive(true);
@@ -953,9 +990,24 @@ bool DolphinView::eventFilter(QObject *watched, QEvent *event)
         }
         break;
 
-    case QEvent::ToolTip:
-        tryShowNameToolTip(static_cast<QHelpEvent *>(event));
+    case QEvent::ToolTip: {
+        const auto helpEvent = static_cast<QHelpEvent *>(event);
+        if (tryShowNameToolTip(helpEvent)) {
+            return true;
 
+        } else if (m_hoveredColumnHeaderIndex) {
+            const auto rolesInfo = KFileItemModel::rolesInformation();
+            const auto visibleRole = m_visibleRoles.value(*m_hoveredColumnHeaderIndex);
+
+            for (const KFileItemModel::RoleInfo &info : rolesInfo) {
+                if (visibleRole == info.role) {
+                    QToolTip::showText(helpEvent->globalPos(), info.tooltip, this);
+                    return true;
+                }
+            }
+        }
+        break;
+    }
     default:
         break;
     }
@@ -966,10 +1018,16 @@ bool DolphinView::eventFilter(QObject *watched, QEvent *event)
 void DolphinView::wheelEvent(QWheelEvent *event)
 {
     if (event->modifiers().testFlag(Qt::ControlModifier)) {
-        const QPoint numDegrees = event->angleDelta() / 8;
-        const QPoint numSteps = numDegrees / 15;
+        m_controlWheelAccumulatedDelta += event->angleDelta().y();
+
+        if (m_controlWheelAccumulatedDelta <= -QWheelEvent::DefaultDeltasPerStep) {
+            slotDecreaseZoom();
+            m_controlWheelAccumulatedDelta += QWheelEvent::DefaultDeltasPerStep;
+        } else if (m_controlWheelAccumulatedDelta >= QWheelEvent::DefaultDeltasPerStep) {
+            slotIncreaseZoom();
+            m_controlWheelAccumulatedDelta -= QWheelEvent::DefaultDeltasPerStep;
+        }
 
-        setZoomLevel(zoomLevel() + numSteps.y());
         event->accept();
     } else {
         event->ignore();
@@ -1153,6 +1211,7 @@ void DolphinView::slotHeaderContextMenuRequested(const QPointF &pos)
         action->setCheckable(true);
         action->setChecked(visibleRolesSet.contains(info.role));
         action->setData(info.role);
+        action->setToolTip(info.tooltip);
 
         const bool enable = (!info.requiresBaloo && !info.requiresIndexer) || (info.requiresBaloo) || (info.requiresIndexer && indexingEnabled);
         action->setEnabled(enable);
@@ -1316,7 +1375,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);
+                });
+            });
         }
     }
 }
@@ -1363,7 +1432,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);
 }
@@ -1374,7 +1443,9 @@ 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::slotJobResult(KJob *job)
@@ -1382,13 +1453,41 @@ 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
+            // TODO KF6 replace with Qt::singleShotConnection
+            QMetaObject::Connection *const connection = new QMetaObject::Connection;
+            *connection = connect(
+                m_model,
+                &KFileItemModel::directoryLoadingCompleted,
+                this,
+                [this, connection]() {
+                    // the model should now contain all the items created by the job
+                    updateSelectionState();
+                    m_selectJobCreatedItems = false;
+                    m_selectedUrls.clear();
+                    QObject::disconnect(*connection);
+                    delete connection;
+                },
+                Qt::UniqueConnection);
+        } else {
+            m_selectJobCreatedItems = false;
+            m_selectedUrls.clear();
+        }
     }
 }
 
 void DolphinView::slotSelectionChanged(const KItemSet &current, const KItemSet &previous)
 {
+    m_selectNextItem = false;
     const int currentCount = current.count();
     const int previousCount = previous.count();
     const bool selectionStateChanged = (currentCount == 0 && previousCount > 0) || (currentCount > 0 && previousCount == 0);
@@ -1644,6 +1743,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()) {
@@ -1678,35 +1811,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)
@@ -1722,6 +1827,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();
@@ -1741,6 +1851,7 @@ void DolphinView::slotTwoClicksRenamingTimerTimeout()
 void DolphinView::slotTrashFileFinished(KJob *job)
 {
     if (job->error() == 0) {
+        selectNextItem(); // Fixes BUG: 419914 via selecting next item
         Q_EMIT operationCompletedMessage(i18nc("@info:status", "Trash operation completed."));
     } else if (job->error() != KIO::ERR_USER_CANCELED) {
         Q_EMIT errorMessage(job->errorString());
@@ -1750,12 +1861,37 @@ void DolphinView::slotTrashFileFinished(KJob *job)
 void DolphinView::slotDeleteFileFinished(KJob *job)
 {
     if (job->error() == 0) {
+        selectNextItem(); // Fixes BUG: 419914 via selecting next item
         Q_EMIT operationCompletedMessage(i18nc("@info:status", "Delete operation completed."));
     } else if (job->error() != KIO::ERR_USER_CANCELED) {
         Q_EMIT errorMessage(job->errorString());
     }
 }
 
+void DolphinView::selectNextItem()
+{
+    if (m_active && m_selectNextItem) {
+        KItemListSelectionManager *selectionManager = m_container->controller()->selectionManager();
+        if (selectedItems().isEmpty()) {
+            Q_ASSERT_X(false, "DolphinView", "Selecting the next item failed.");
+            return;
+        }
+        const auto lastSelectedIndex = m_model->index(selectedItems().last());
+        if (lastSelectedIndex < 0) {
+            Q_ASSERT_X(false, "DolphinView", "Selecting the next item failed.");
+            return;
+        }
+        auto nextItem = lastSelectedIndex + 1;
+        if (nextItem >= itemsCount()) {
+            nextItem = lastSelectedIndex - selectedItemsCount();
+        }
+        if (nextItem >= 0) {
+            selectionManager->setSelected(nextItem, 1);
+        }
+        m_selectNextItem = false;
+    }
+}
+
 void DolphinView::slotRenamingResult(KJob *job)
 {
     if (job->error()) {
@@ -1880,7 +2016,7 @@ void DolphinView::slotRoleEditingFinished(int index, const QByteArray &role, con
             newUrl.setPath(newUrl.path() + KIO::encodeFileName(newName));
 
 #ifndef Q_OS_WIN
-            //Confirm hiding file/directory by renaming inline
+            // Confirm hiding file/directory by renaming inline
             if (!hiddenFilesShown() && newName.startsWith(QLatin1Char('.')) && !oldItem.name().startsWith(QLatin1Char('.'))) {
                 KGuiItem yesGuiItem(i18nc("@action:button", "Rename and Hide"), QStringLiteral("view-hidden"));
 
@@ -2094,6 +2230,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);
 }
@@ -2258,13 +2396,13 @@ void DolphinView::updatePlaceholderLabel()
     m_placeholderLabel->setVisible(true);
 }
 
-void DolphinView::tryShowNameToolTip(QHelpEvent *event)
+bool DolphinView::tryShowNameToolTip(QHelpEvent *event)
 {
     if (!GeneralSettings::showToolTips() && m_mode == DolphinView::IconsView) {
         const std::optional<int> index = m_view->itemAt(event->pos());
 
         if (!index.has_value()) {
-            return;
+            return false;
         }
 
         // Check whether the filename has been elided
@@ -2275,6 +2413,8 @@ void DolphinView::tryShowNameToolTip(QHelpEvent *event)
             const QString text = item.text();
             const QPoint pos = mapToGlobal(event->pos());
             QToolTip::showText(pos, text);
+            return true;
         }
     }
+    return false;
 }