X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/blobdiff_plain/42cd439af882c78e6e3c1f6a58dd8d47ce47ff57..8b4d3624ad1be3de678cc5fcaa5a6baa43767914:/src/views/dolphinview.cpp diff --git a/src/views/dolphinview.cpp b/src/views/dolphinview.cpp index 71c16bf46..9c85303fd 100644 --- a/src/views/dolphinview.cpp +++ b/src/views/dolphinview.cpp @@ -7,7 +7,9 @@ #include "dolphinview.h" +#include "dolphin_compactmodesettings.h" #include "dolphin_detailsmodesettings.h" +#include "dolphin_iconsmodesettings.h" #include "dolphin_generalsettings.h" #include "dolphinitemlistview.h" #include "dolphinnewfilemenuobserver.h" @@ -18,6 +20,7 @@ #include "kitemviews/kitemlistcontroller.h" #include "kitemviews/kitemlistheader.h" #include "kitemviews/kitemlistselectionmanager.h" +#include "kitemviews/private/kitemlistroleeditor.h" #include "versioncontrol/versioncontrolobserver.h" #include "viewproperties.h" #include "views/tooltips/tooltipmanager.h" @@ -45,6 +48,7 @@ #include #include +#include #include #include #include @@ -67,6 +71,7 @@ DolphinView::DolphinView(const QUrl& url, QWidget* parent) : m_assureVisibleCurrentIndex(false), m_isFolderWritable(true), m_dragging(false), + m_loading(false), m_url(url), m_viewPropertiesContext(), m_mode(DolphinView::IconsView), @@ -85,7 +90,8 @@ DolphinView::DolphinView(const QUrl& url, QWidget* parent) : m_markFirstNewlySelectedItemAsCurrent(false), m_versionControlObserver(nullptr), m_twoClicksRenamingTimer(nullptr), - m_placeholderLabel(nullptr) + m_placeholderLabel(nullptr), + m_showLoadingPlaceholderTimer(nullptr) { m_topLayout = new QVBoxLayout(this); m_topLayout->setSpacing(0); @@ -123,6 +129,11 @@ DolphinView::DolphinView(const QUrl& url, QWidget* parent) : connect(m_container->horizontalScrollBar(), &QScrollBar::valueChanged, this, [=] { hideToolTip(); }); connect(m_container->verticalScrollBar(), &QScrollBar::valueChanged, this, [=] { hideToolTip(); }); + m_showLoadingPlaceholderTimer = new QTimer(this); + m_showLoadingPlaceholderTimer->setInterval(500); + m_showLoadingPlaceholderTimer->setSingleShot(true); + connect(m_showLoadingPlaceholderTimer, &QTimer::timeout, this, &DolphinView::showLoadingPlaceholder); + // Show some placeholder text for empty folders // This is made using a heavily-modified QLabel rather than a KTitleWidget // because KTitleWidget can't be told to turn off mouse-selectable text @@ -165,7 +176,7 @@ DolphinView::DolphinView(const QUrl& url, QWidget* parent) : connect(m_model, &KFileItemModel::directoryLoadingStarted, this, &DolphinView::slotDirectoryLoadingStarted); connect(m_model, &KFileItemModel::directoryLoadingCompleted, this, &DolphinView::slotDirectoryLoadingCompleted); - connect(m_model, &KFileItemModel::directoryLoadingCanceled, this, &DolphinView::directoryLoadingCanceled); + connect(m_model, &KFileItemModel::directoryLoadingCanceled, this, &DolphinView::slotDirectoryLoadingCanceled); connect(m_model, &KFileItemModel::directoryLoadingProgress, this, &DolphinView::directoryLoadingProgress); connect(m_model, &KFileItemModel::directorySortingProgress, this, &DolphinView::directorySortingProgress); connect(m_model, &KFileItemModel::itemsChanged, @@ -176,11 +187,10 @@ DolphinView::DolphinView(const QUrl& url, QWidget* parent) : connect(m_model, &KFileItemModel::errorMessage, this, &DolphinView::errorMessage); 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(this, &DolphinView::itemCountChanged, this, &DolphinView::updatePlaceholderLabel); - connect(this, &DolphinView::urlChanged, - this, &DolphinView::updatePlaceholderLabel); m_view->installEventFilter(this); connect(m_view, &DolphinItemListView::sortOrderChanged, @@ -529,17 +539,18 @@ QStringList DolphinView::mimeTypeFilters() const return m_model->mimeTypeFilters(); } -QString DolphinView::statusBarText() const +void DolphinView::requestStatusBarText() { - QString summary; - QString foldersText; - QString filesText; - - int folderCount = 0; - int fileCount = 0; - KIO::filesize_t totalFileSize = 0; + if (m_statJobForStatusBarText) { + // Kill the pending request. + m_statJobForStatusBarText->kill(); + } if (m_container->controller()->selectionManager()->hasSelection()) { + int folderCount = 0; + int fileCount = 0; + KIO::filesize_t totalFileSize = 0; + // Give a summary of the status of the selected files const KFileItemList list = selectedItems(); for (const KFileItem& item : list) { @@ -553,14 +564,37 @@ QString DolphinView::statusBarText() const if (folderCount + fileCount == 1) { // If only one item is selected, show info about it - return list.first().getStatusBarInfo(); + Q_EMIT statusBarTextChanged(list.first().getStatusBarInfo()); } else { // At least 2 items are selected - foldersText = i18ncp("@info:status", "1 Folder selected", "%1 Folders selected", folderCount); - filesText = i18ncp("@info:status", "1 File selected", "%1 Files selected", fileCount); + emitStatusBarText(folderCount, fileCount, totalFileSize, HasSelection); + } + } else { // has no selection + if (!m_model->rootItem().url().isValid()) { + return; } + + m_statJobForStatusBarText = KIO::statDetails(m_model->rootItem().url(), + KIO::StatJob::SourceSide, KIO::StatRecursiveSize, KIO::HideProgressInfo); + connect(m_statJobForStatusBarText, &KJob::result, + this, &DolphinView::slotStatJobResult); + m_statJobForStatusBarText->start(); + } +} + +void DolphinView::emitStatusBarText(const int folderCount, const int fileCount, + KIO::filesize_t totalFileSize, const Selection selection) +{ + QString foldersText; + QString filesText; + QString summary; + + if (selection == HasSelection) { + // At least 2 items are selected because the case of 1 selected item is handled in + // DolphinView::requestStatusBarText(). + foldersText = i18ncp("@info:status", "1 Folder selected", "%1 Folders selected", folderCount); + filesText = i18ncp("@info:status", "1 File selected", "%1 Files selected", fileCount); } else { - calculateItemCount(fileCount, folderCount, totalFileSize); foldersText = i18ncp("@info:status", "1 Folder", "%1 Folders", folderCount); filesText = i18ncp("@info:status", "1 File", "%1 Files", fileCount); } @@ -578,8 +612,7 @@ QString DolphinView::statusBarText() const } else { summary = i18nc("@info:status", "0 Folders, 0 Files"); } - - return summary; + Q_EMIT statusBarTextChanged(summary); } QList DolphinView::versionControlActions(const KFileItemList& items) const @@ -651,12 +684,21 @@ void DolphinView::renameSelectedItems() if (items.count() == 1 && GeneralSettings::renameInline()) { const int index = m_model->index(items.first()); - m_view->editRole(index, "text"); - hideToolTip(); + QMetaObject::Connection * const connection = new QMetaObject::Connection; + *connection = connect(m_view, &KItemListView::scrollingStopped, this, [=](){ + QObject::disconnect(*connection); + delete connection; + + m_view->editRole(index, "text"); + + hideToolTip(); + + connect(m_view, &DolphinItemListView::roleEditingFinished, + this, &DolphinView::slotRoleEditingFinished); + }); + m_view->scrollToItem(index); - connect(m_view, &DolphinItemListView::roleEditingFinished, - this, &DolphinView::slotRoleEditingFinished); } else { KIO::RenameFileDialog* dialog = new KIO::RenameFileDialog(items, this); connect(dialog, &KIO::RenameFileDialog::renamingFinished, @@ -945,7 +987,7 @@ void DolphinView::slotItemsActivated(const KItemSet& indexes) const QUrl& url = openItemAsFolderUrl(item); if (!url.isEmpty()) { // Open folders in new tabs - Q_EMIT tabRequested(url, DolphinTabWidget::AfterLastTab); + Q_EMIT tabRequested(url); } else { items.append(item); } @@ -963,9 +1005,9 @@ void DolphinView::slotItemMiddleClicked(int index) const KFileItem& item = m_model->fileItem(index); const QUrl& url = openItemAsFolderUrl(item); if (!url.isEmpty()) { - Q_EMIT tabRequested(url, DolphinTabWidget::AfterCurrentTab); + Q_EMIT tabRequested(url); } else if (isTabsForFilesEnabled()) { - Q_EMIT tabRequested(item.url(), DolphinTabWidget::AfterCurrentTab); + Q_EMIT tabRequested(item.url()); } } @@ -1272,6 +1314,36 @@ void DolphinView::emitSelectionChangedSignal() Q_EMIT selectionChanged(selectedItems()); } +void DolphinView::slotStatJobResult(KJob *job) +{ + int folderCount = 0; + int fileCount = 0; + KIO::filesize_t totalFileSize = 0; + bool countFileSize = true; + + const auto entry = static_cast(job)->statResult(); + if (entry.contains(KIO::UDSEntry::UDS_RECURSIVE_SIZE)) { + // We have a precomputed value. + totalFileSize = static_cast( + entry.numberValue(KIO::UDSEntry::UDS_RECURSIVE_SIZE)); + countFileSize = false; + } + + const int itemCount = m_model->count(); + for (int i = 0; i < itemCount; ++i) { + const KFileItem item = m_model->fileItem(i); + if (item.isDir()) { + ++folderCount; + } else { + ++fileCount; + if (countFileSize) { + totalFileSize += item.size(); + } + } + } + emitStatusBarText(folderCount, fileCount, totalFileSize, NoSelection); +} + void DolphinView::updateSortRole(const QByteArray& role) { ViewProperties props(viewPropertiesUrl()); @@ -1438,16 +1510,30 @@ QUrl DolphinView::openItemAsFolderUrl(const KFileItem& item, const bool browseTh void DolphinView::resetZoomLevel() { - ViewModeSettings::ViewMode mode; - + // TODO : Switch to using ViewModeSettings after MR #256 is merged + int defaultIconSize = KIconLoader::SizeSmall; switch (m_mode) { - case IconsView: mode = ViewModeSettings::IconsMode; break; - case CompactView: mode = ViewModeSettings::CompactMode; break; - case DetailsView: mode = ViewModeSettings::DetailsMode; break; + case IconsView: + IconsModeSettings::self()->useDefaults(true); + defaultIconSize = IconsModeSettings::iconSize(); + IconsModeSettings::self()->useDefaults(false); + break; + case DetailsView: + DetailsModeSettings::self()->useDefaults(true); + defaultIconSize = DetailsModeSettings::iconSize(); + DetailsModeSettings::self()->useDefaults(false); + break; + case CompactView: + CompactModeSettings::self()->useDefaults(true); + defaultIconSize = CompactModeSettings::iconSize(); + CompactModeSettings::self()->useDefaults(false); + break; + default: + Q_ASSERT(false); + break; } - const ViewModeSettings settings(mode); - const QSize iconSize = QSize(settings.iconSize(), settings.iconSize()); - setZoomLevel(ZoomLevelInfo::zoomLevelForIconSize(iconSize)); + + setZoomLevel(ZoomLevelInfo::zoomLevelForIconSize(QSize(defaultIconSize, defaultIconSize))); } void DolphinView::observeCreatedItem(const QUrl& url) @@ -1538,40 +1624,6 @@ void DolphinView::hideToolTip(const ToolTipManager::HideBehavior behavior) #endif } -void DolphinView::calculateItemCount(int& fileCount, - int& folderCount, - KIO::filesize_t& totalFileSize) const -{ - const int itemCount = m_model->count(); - - bool countFileSize = true; - - if (!m_model->rootItem().url().isValid()) { - return; - } - - // In case we have a precomputed value - const auto job = KIO::statDetails(m_model->rootItem().url(), KIO::StatJob::SourceSide, KIO::StatRecursiveSize, KIO::HideProgressInfo); - job->exec(); - const auto entry = job->statResult(); - if (entry.contains(KIO::UDSEntry::UDS_RECURSIVE_SIZE)) { - totalFileSize = static_cast(entry.numberValue(KIO::UDSEntry::UDS_RECURSIVE_SIZE)); - countFileSize = false; - } - - for (int i = 0; i < itemCount; ++i) { - const KFileItem item = m_model->fileItem(i); - if (item.isDir()) { - ++folderCount; - } else { - ++fileCount; - if (countFileSize) { - totalFileSize += item.size(); - } - } - } -} - void DolphinView::slotTwoClicksRenamingTimerTimeout() { const KItemListSelectionManager* selectionManager = m_container->controller()->selectionManager(); @@ -1624,8 +1676,8 @@ void DolphinView::slotRenamingResult(KJob* job) void DolphinView::slotDirectoryLoadingStarted() { - // We don't want the placeholder label to flicker while the folder is loading - m_placeholderLabel->setVisible(false); + m_loading = true; + updatePlaceholderLabel(); // Disable the writestate temporary until it can be determined in a fast way // in DolphinView::slotDirectoryLoadingCompleted() @@ -1639,6 +1691,8 @@ void DolphinView::slotDirectoryLoadingStarted() void DolphinView::slotDirectoryLoadingCompleted() { + m_loading = false; + // Update the view-state. This has to be done asynchronously // because the view might not be in its final state yet. QTimer::singleShot(0, this, &DolphinView::updateViewState); @@ -1652,6 +1706,15 @@ void DolphinView::slotDirectoryLoadingCompleted() updateWritableState(); } +void DolphinView::slotDirectoryLoadingCanceled() +{ + m_loading = false; + + updatePlaceholderLabel(); + + Q_EMIT directoryLoadingCanceled(); +} + void DolphinView::slotItemsChanged() { m_assureVisibleCurrentIndex = false; @@ -1706,13 +1769,15 @@ void DolphinView::slotRoleEditingFinished(int index, const QByteArray& role, con disconnect(m_view, &DolphinItemListView::roleEditingFinished, this, &DolphinView::slotRoleEditingFinished); - if (index < 0 || index >= m_model->count()) { + const KFileItemList items = selectedItems(); + if (items.count() != 1) { return; } if (role == "text") { - const KFileItem oldItem = m_model->fileItem(index); - const QString newName = value.toString(); + const KFileItem oldItem = items.first(); + const EditResult retVal = value.value(); + const QString newName = retVal.newName; if (!newName.isEmpty() && newName != oldItem.text() && newName != QLatin1Char('.') && newName != QLatin1String("..")) { const QUrl oldUrl = oldItem.url(); @@ -1743,14 +1808,14 @@ void DolphinView::slotRoleEditingFinished(int index, const QByteArray& role, con #endif const bool newNameExistsAlready = (m_model->index(newUrl) >= 0); - if (!newNameExistsAlready) { + if (!newNameExistsAlready && m_model->index(oldUrl) == index) { // Only change the data in the model if no item with the new name // is in the model yet. If there is an item with the new name // already, calling KIO::CopyJob will open a dialog // asking for a new name, and KFileItemModel will update the // data when the dir lister signals that the file name has changed. QHash data; - data.insert(role, value); + data.insert(role, retVal.newName); m_model->setData(index, data); } @@ -1767,6 +1832,13 @@ void DolphinView::slotRoleEditingFinished(int index, const QByteArray& role, con connect(job, &KJob::result, this, &DolphinView::slotRenamingResult); } } + if (retVal.direction != EditDone) { + const short indexShift = retVal.direction == EditNext ? 1 : -1; + m_container->controller()->selectionManager()->setSelected(index, 1, KItemListSelectionManager::Deselect); + m_container->controller()->selectionManager()->setSelected(index + indexShift, 1, + KItemListSelectionManager::Select); + renameSelectedItems(); + } } } @@ -2014,18 +2086,31 @@ void DolphinView::slotSwipeUp() Q_EMIT goUpRequested(); } +void DolphinView::showLoadingPlaceholder() +{ + m_placeholderLabel->setText(i18n("Loading...")); + m_placeholderLabel->setVisible(true); +} + void DolphinView::updatePlaceholderLabel() { + m_showLoadingPlaceholderTimer->stop(); if (itemsCount() > 0) { m_placeholderLabel->setVisible(false); return; } + if (m_loading) { + m_placeholderLabel->setVisible(false); + m_showLoadingPlaceholderTimer->start(); + return; + } + if (!nameFilter().isEmpty()) { m_placeholderLabel->setText(i18n("No items matching the filter")); } else if (m_url.scheme() == QLatin1String("baloosearch") || m_url.scheme() == QLatin1String("filenamesearch")) { m_placeholderLabel->setText(i18n("No items matching the search")); - } else if (m_url.scheme() == QLatin1String("trash")) { + } else if (m_url.scheme() == QLatin1String("trash") && m_url.path() == QLatin1String("/")) { m_placeholderLabel->setText(i18n("Trash is empty")); } else if (m_url.scheme() == QLatin1String("tags")) { m_placeholderLabel->setText(i18n("No tags")); @@ -2035,7 +2120,7 @@ void DolphinView::updatePlaceholderLabel() m_placeholderLabel->setText(i18n("No shared folders found")); } else if (m_url.scheme() == QLatin1String("network")) { m_placeholderLabel->setText(i18n("No relevant network resources found")); - } else if (m_url.scheme() == QLatin1String("mtp")) { + } else if (m_url.scheme() == QLatin1String("mtp") && m_url.path() == QLatin1String("/")) { m_placeholderLabel->setText(i18n("No MTP-compatible devices found")); } else if (m_url.scheme() == QLatin1String("bluetooth")) { m_placeholderLabel->setText(i18n("No Bluetooth devices found"));