-/***************************************************************************
- * Copyright (C) 2006-2009 by Peter Penz <peter.penz19@gmail.com> *
- * Copyright (C) 2006 by Gregor Kališnik <gregor@podnapisi.net> *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the *
- * Free Software Foundation, Inc., *
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
- ***************************************************************************/
+/*
+ * SPDX-FileCopyrightText: 2006-2009 Peter Penz <peter.penz19@gmail.com>
+ * SPDX-FileCopyrightText: 2006 Gregor Kališnik <gregor@podnapisi.net>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
#include "dolphinview.h"
#include "kitemviews/kitemlistcontroller.h"
#include "kitemviews/kitemlistheader.h"
#include "kitemviews/kitemlistselectionmanager.h"
-#include "renamedialog.h"
#include "versioncontrol/versioncontrolobserver.h"
#include "viewproperties.h"
#include "views/tooltips/tooltipmanager.h"
#include <KIO/Paste>
#include <KIO/PasteJob>
#include <KIO/PreviewJob>
+#include <KIO/RenameFileDialog>
#include <KJobWidgets>
#include <KLocalizedString>
#include <KMessageBox>
#include <KProtocolManager>
#include <QAbstractItemView>
+#include <QActionGroup>
#include <QApplication>
#include <QClipboard>
#include <QDropEvent>
+#include <QGraphicsOpacityEffect>
#include <QGraphicsSceneDragDropEvent>
+#include <QLabel>
#include <QMenu>
+#include <QMimeDatabase>
#include <QPixmapCache>
#include <QPointer>
#include <QScrollBar>
+#include <QSize>
#include <QTimer>
#include <QVBoxLayout>
m_assureVisibleCurrentIndex(false),
m_isFolderWritable(true),
m_dragging(false),
+ m_loading(false),
m_url(url),
m_viewPropertiesContext(),
m_mode(DolphinView::IconsView),
m_clearSelectionBeforeSelectingNewItems(false),
m_markFirstNewlySelectedItemAsCurrent(false),
m_versionControlObserver(nullptr),
- m_twoClicksRenamingTimer(nullptr)
+ m_twoClicksRenamingTimer(nullptr),
+ m_placeholderLabel(nullptr)
{
m_topLayout = new QVBoxLayout(this);
m_topLayout->setSpacing(0);
- m_topLayout->setMargin(0);
+ m_topLayout->setContentsMargins(0, 0, 0, 0);
// When a new item has been created by the "Create New..." menu, the item should
// get selected and it must be assured that the item will get visible. As the
m_container = new KItemListContainer(controller, this);
m_container->installEventFilter(this);
setFocusProxy(m_container);
- connect(m_container->horizontalScrollBar(), &QScrollBar::valueChanged, this, &DolphinView::hideToolTip);
- connect(m_container->verticalScrollBar(), &QScrollBar::valueChanged, this, &DolphinView::hideToolTip);
+ connect(m_container->horizontalScrollBar(), &QScrollBar::valueChanged, this, [=] { hideToolTip(); });
+ connect(m_container->verticalScrollBar(), &QScrollBar::valueChanged, this, [=] { hideToolTip(); });
+
+ // 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
+ m_placeholderLabel = new QLabel(this);
+ QFont placeholderLabelFont;
+ // To match the size of a level 2 Heading/KTitleWidget
+ placeholderLabelFont.setPointSize(qRound(placeholderLabelFont.pointSize() * 1.3));
+ m_placeholderLabel->setFont(placeholderLabelFont);
+ m_placeholderLabel->setTextInteractionFlags(Qt::NoTextInteraction);
+ m_placeholderLabel->setWordWrap(true);
+ m_placeholderLabel->setAlignment(Qt::AlignCenter);
+ // Match opacity of QML placeholder label component
+ auto *effect = new QGraphicsOpacityEffect(m_placeholderLabel);
+ effect->setOpacity(0.5);
+ m_placeholderLabel->setGraphicsEffect(effect);
+ // Set initial text and visibility
+ updatePlaceholderLabel();
+
+ auto *centeringLayout = new QVBoxLayout(m_container);
+ centeringLayout->addWidget(m_placeholderLabel);
+ centeringLayout->setAlignment(m_placeholderLabel, Qt::AlignCenter);
controller->setSelectionBehavior(KItemListController::MultiSelection);
connect(controller, &KItemListController::itemActivated, this, &DolphinView::slotItemActivated);
connect(controller, &KItemListController::escapePressed, this, &DolphinView::stopLoading);
connect(controller, &KItemListController::modelChanged, this, &DolphinView::slotModelChanged);
connect(controller, &KItemListController::selectedItemTextPressed, this, &DolphinView::slotSelectedItemTextPressed);
+ connect(controller, &KItemListController::increaseZoom, this, &DolphinView::slotIncreaseZoom);
+ connect(controller, &KItemListController::decreaseZoom, this, &DolphinView::slotDecreaseZoom);
+ connect(controller, &KItemListController::swipeUp, this, &DolphinView::slotSwipeUp);
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,
connect(m_model, &KFileItemModel::directoryRedirection, this, &DolphinView::slotDirectoryRedirection);
connect(m_model, &KFileItemModel::urlIsFileError, this, &DolphinView::urlIsFileError);
+ connect(this, &DolphinView::itemCountChanged,
+ this, &DolphinView::updatePlaceholderLabel);
+
m_view->installEventFilter(this);
connect(m_view, &DolphinItemListView::sortOrderChanged,
this, &DolphinView::slotSortOrderChangedByHeader);
#endif
m_versionControlObserver = new VersionControlObserver(this);
+ m_versionControlObserver->setView(this);
m_versionControlObserver->setModel(m_model);
connect(m_versionControlObserver, &VersionControlObserver::infoMessage, this, &DolphinView::infoMessage);
connect(m_versionControlObserver, &VersionControlObserver::errorMessage, this, &DolphinView::errorMessage);
if (active) {
m_container->setFocus();
- emit activated();
- emit writeStateChanged(m_isFolderWritable);
+ Q_EMIT activated();
+ Q_EMIT writeStateChanged(m_isFolderWritable);
}
}
const int oldZoomLevel = m_view->zoomLevel();
m_view->setPreviewsShown(show);
- emit previewsShownChanged(show);
+ Q_EMIT previewsShownChanged(show);
const int newZoomLevel = m_view->zoomLevel();
if (newZoomLevel != oldZoomLevel) {
- emit zoomLevelChanged(newZoomLevel, oldZoomLevel);
+ Q_EMIT zoomLevelChanged(newZoomLevel, oldZoomLevel);
}
}
props.setHiddenFilesShown(show);
m_model->setShowHiddenFiles(show);
- emit hiddenFilesShownChanged(show);
+ Q_EMIT hiddenFilesShownChanged(show);
}
bool DolphinView::hiddenFilesShown() const
m_container->controller()->model()->setGroupedSorting(grouped);
- emit groupedSortingChanged(grouped);
+ Q_EMIT groupedSortingChanged(grouped);
}
bool DolphinView::groupedSorting() const
m_scrollToCurrentItem = true;
}
-void DolphinView::selectItems(const QRegExp& pattern, bool enabled)
+void DolphinView::selectItems(const QRegularExpression ®exp, bool enabled)
{
const KItemListSelectionManager::SelectionMode mode = enabled
? KItemListSelectionManager::Select
for (int index = 0; index < m_model->count(); index++) {
const KFileItem item = m_model->fileItem(index);
- if (pattern.exactMatch(item.text())) {
+ if (regexp.match(item.text()).hasMatch()) {
// An alternative approach would be to store the matching items in a KItemSet and
// select them in one go after the loop, but we'd need a new function
// KItemListSelectionManager::setSelected(KItemSet, SelectionMode mode)
m_view->setZoomLevel(level);
if (zoomLevel() != oldZoomLevel) {
hideToolTip();
- emit zoomLevelChanged(zoomLevel(), oldZoomLevel);
+ Q_EMIT zoomLevelChanged(zoomLevel(), oldZoomLevel);
}
}
m_visibleRoles = roles;
m_view->setVisibleRoles(roles);
- emit visibleRolesChanged(m_visibleRoles, previousRoles);
+ Q_EMIT visibleRolesChanged(m_visibleRoles, previousRoles);
}
QList<QByteArray> DolphinView::visibleRoles() const
const int newZoomLevel = m_view->zoomLevel();
if (newZoomLevel != oldZoomLevel) {
- emit zoomLevelChanged(newZoomLevel, oldZoomLevel);
+ Q_EMIT zoomLevelChanged(newZoomLevel, oldZoomLevel);
}
}
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();
- foreach (const KFileItem& item, list) {
+ for (const KFileItem& item : list) {
if (item.isDir()) {
++folderCount;
} else {
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);
}
} else {
summary = i18nc("@info:status", "0 Folders, 0 Files");
}
-
- return summary;
+ Q_EMIT statusBarTextChanged(summary);
}
QList<QAction*> DolphinView::versionControlActions(const KFileItemList& items) const
applyViewProperties();
loadDirectory(url);
- emit urlChanged(url);
+ Q_EMIT urlChanged(url);
}
void DolphinView::selectAll()
connect(m_view, &DolphinItemListView::roleEditingFinished,
this, &DolphinView::slotRoleEditingFinished);
} else {
- RenameDialog* dialog = new RenameDialog(this, items);
- connect(dialog, &RenameDialog::renamingFinished, this, &DolphinView::slotRenameDialogRenamingFinished);
+ KIO::RenameFileDialog* dialog = new KIO::RenameFileDialog(items, this);
+ connect(dialog, &KIO::RenameFileDialog::renamingFinished,
+ this, &DolphinView::slotRenameDialogRenamingFinished);
- dialog->show();
- dialog->raise();
- dialog->activateWindow();
+ dialog->open();
}
// Assure that the current index remains visible when KFileItemModel
}
}
-void DolphinView::cutSelectedItems()
+void DolphinView::cutSelectedItemsToClipboard()
{
QMimeData* mimeData = selectionMimeData();
KIO::setClipboardDataCut(mimeData, true);
QApplication::clipboard()->setMimeData(mimeData);
}
-void DolphinView::copySelectedItems()
+void DolphinView::copySelectedItemsToClipboard()
{
QMimeData* mimeData = selectionMimeData();
QApplication::clipboard()->setMimeData(mimeData);
}
+void DolphinView::copySelectedItems(const KFileItemList &selection, const QUrl &destinationUrl)
+{
+ 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);
+ KIO::FileUndoManager::self()->recordCopyJob(job);
+}
+
+void DolphinView::moveSelectedItems(const KFileItemList &selection, const QUrl &destinationUrl)
+{
+ 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);
+ KIO::FileUndoManager::self()->recordCopyJob(job);
+
+}
+
void DolphinView::paste()
{
pasteToUrl(url());
}
}
+void DolphinView::duplicateSelectedItems()
+{
+ const KFileItemList itemList = selectedItems();
+ if (itemList.isEmpty()) {
+ return;
+ }
+
+ const QMimeDatabase db;
+
+ // Duplicate all selected items and append "copy" to the end of the file name
+ // but before the filename extension, if present
+ QList<QUrl> newSelection;
+ for (const auto &item : itemList) {
+ const QUrl originalURL = item.url();
+ const QString originalDirectoryPath = originalURL.adjusted(QUrl::RemoveFilename).path();
+ const QString originalFileName = item.name();
+
+ QString extension = db.suffixForFileName(originalFileName);
+
+ QUrl duplicateURL = originalURL;
+
+ // No extension; new filename is "<oldfilename> copy"
+ if (extension.isEmpty()) {
+ duplicateURL.setPath(originalDirectoryPath + i18nc("<filename> copy", "%1 copy", originalFileName));
+ // There's an extension; new filename is "<oldfilename> copy.<extension>"
+ } else {
+ // Need to add a dot since QMimeDatabase::suffixForFileName() doesn't include it
+ extension = QLatin1String(".") + extension;
+ const QString originalFilenameWithoutExtension = originalFileName.chopped(extension.size());
+ // Preserve file's original filename extension in case the casing differs
+ // from what QMimeDatabase::suffixForFileName() returned
+ const QString originalExtension = originalFileName.right(extension.size());
+ duplicateURL.setPath(originalDirectoryPath + i18nc("<filename> copy", "%1 copy", originalFilenameWithoutExtension) + originalExtension);
+ }
+
+ KIO::CopyJob* job = KIO::copyAs(originalURL, duplicateURL);
+ KJobWidgets::setWindow(job, this);
+
+ if (job) {
+ newSelection << duplicateURL;
+ KIO::FileUndoManager::self()->recordCopyJob(job);
+ }
+ }
+
+ forceUrlsSelection(newSelection.first(), newSelection);
+}
+
void DolphinView::stopLoading()
{
m_model->cancelDirectoryLoading();
void DolphinView::updatePalette()
{
- QColor color = KColorScheme(QPalette::Active, KColorScheme::View).background().color();
+ QColor color = KColorScheme(isActiveWindow() ? QPalette::Active : QPalette::Inactive, KColorScheme::View).background().color();
if (!m_active) {
color.setAlpha(150);
}
QPixmapCache::clear();
break;
+ case QEvent::WindowActivate:
+ case QEvent::WindowDeactivate:
+ updatePalette();
+ break;
+
case QEvent::KeyPress:
+ hideToolTip(ToolTipManager::HideBehavior::Instantly);
if (GeneralSettings::useTabForSwitchingSplitView()) {
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
if (keyEvent->key() == Qt::Key_Tab && keyEvent->modifiers() == Qt::NoModifier) {
- emit toggleActiveViewRequested();
+ Q_EMIT toggleActiveViewRequested();
return true;
}
}
case QEvent::GraphicsSceneDragEnter:
if (watched == m_view) {
m_dragging = true;
+ abortTwoClicksRenaming();
}
break;
void DolphinView::wheelEvent(QWheelEvent* event)
{
if (event->modifiers().testFlag(Qt::ControlModifier)) {
- const int numDegrees = event->delta() / 8;
- const int numSteps = numDegrees / 15;
+ const QPoint numDegrees = event->angleDelta() / 8;
+ const QPoint numSteps = numDegrees / 15;
- setZoomLevel(zoomLevel() + numSteps);
+ setZoomLevel(zoomLevel() + numSteps.y());
event->accept();
} else {
event->ignore();
const KFileItem item = m_model->fileItem(index);
if (!item.isNull()) {
- emit itemActivated(item);
+ Q_EMIT itemActivated(item);
}
}
const QUrl& url = openItemAsFolderUrl(item);
if (!url.isEmpty()) { // Open folders in new tabs
- emit tabRequested(url);
+ Q_EMIT tabRequested(url);
} else {
items.append(item);
}
}
if (items.count() == 1) {
- emit itemActivated(items.first());
+ Q_EMIT itemActivated(items.first());
} else if (items.count() > 1) {
- emit itemsActivated(items);
+ Q_EMIT itemsActivated(items);
}
}
const KFileItem& item = m_model->fileItem(index);
const QUrl& url = openItemAsFolderUrl(item);
if (!url.isEmpty()) {
- emit tabRequested(url);
+ Q_EMIT tabRequested(url);
} else if (isTabsForFilesEnabled()) {
- emit tabRequested(item.url());
+ Q_EMIT tabRequested(item.url());
}
}
}
const KFileItem item = m_model->fileItem(index);
- emit requestContextMenu(pos.toPoint(), item, url(), QList<QAction*>());
+ Q_EMIT requestContextMenu(pos.toPoint(), item, url(), QList<QAction*>());
}
void DolphinView::slotViewContextMenuRequested(const QPointF& pos)
{
- emit requestContextMenu(pos.toPoint(), KFileItem(), url(), QList<QAction*>());
+ Q_EMIT requestContextMenu(pos.toPoint(), KFileItem(), url(), QList<QAction*>());
}
void DolphinView::slotHeaderContextMenuRequested(const QPointF& pos)
QPointer<QMenu> menu = new QMenu(QApplication::activeWindow());
KItemListView* view = m_container->controller()->view();
- const QSet<QByteArray> visibleRolesSet = view->visibleRoles().toSet();
+ const QList<QByteArray> visibleRolesSet = view->visibleRoles();
bool indexingEnabled = false;
#ifdef HAVE_BALOO
// Add all roles to the menu that can be shown or hidden by the user
const QList<KFileItemModel::RoleInfo> rolesInfo = KFileItemModel::rolesInformation();
- foreach (const KFileItemModel::RoleInfo& info, rolesInfo) {
+ for (const KFileItemModel::RoleInfo& info : rolesInfo) {
if (info.role == "text") {
// It should not be possible to hide the "text" role
continue;
// Apply the current column-widths as custom column-widths and turn
// off the automatic resizing of the columns
QList<int> columnWidths;
- columnWidths.reserve(view->visibleRoles().count());
- foreach (const QByteArray& role, view->visibleRoles()) {
+ const auto visibleRoles = view->visibleRoles();
+ columnWidths.reserve(visibleRoles.count());
+ for (const QByteArray& role : visibleRoles) {
columnWidths.append(header->columnWidth(role));
}
props.setHeaderColumnWidths(columnWidths);
QList<int> columnWidths;
if (!header->automaticColumnResizing()) {
- columnWidths.reserve(view->visibleRoles().count());
- foreach (const QByteArray& role, view->visibleRoles()) {
+ const auto visibleRoles = view->visibleRoles();
+ columnWidths.reserve(visibleRoles.count());
+ for (const QByteArray& role : visibleRoles) {
columnWidths.append(header->columnWidth(role));
}
}
columnWidths.clear();
columnWidths.reserve(visibleRoles.count());
const KItemListHeader* header = m_view->header();
- foreach (const QByteArray& role, visibleRoles) {
+ for (const QByteArray& role : visibleRoles) {
const int width = header->columnWidth(role);
columnWidths.append(width);
}
#endif
}
- emit requestItemInfo(item);
+ Q_EMIT requestItemInfo(item);
}
void DolphinView::slotItemUnhovered(int index)
{
- Q_UNUSED(index);
+ Q_UNUSED(index)
hideToolTip();
- emit requestItemInfo(KFileItem());
+ Q_EMIT requestItemInfo(KFileItem());
}
void DolphinView::slotItemDropEvent(int index, QGraphicsSceneDragDropEvent* event)
KIO::DropJob* job = DragAndDropHelper::dropUrls(destUrl, dropEvent, dropWidget);
if (job) {
- connect(job, &KIO::DropJob::result, this, &DolphinView::slotPasteJobResult);
+ connect(job, &KIO::DropJob::result, this, &DolphinView::slotJobResult);
if (destUrl == url()) {
// Mark the dropped urls as selected.
void DolphinView::slotMouseButtonPressed(int itemIndex, Qt::MouseButtons buttons)
{
- Q_UNUSED(itemIndex);
+ Q_UNUSED(itemIndex)
hideToolTip();
if (buttons & Qt::BackButton) {
- emit goBackRequested();
+ Q_EMIT goBackRequested();
} else if (buttons & Qt::ForwardButton) {
- emit goForwardRequested();
+ Q_EMIT goForwardRequested();
}
}
void DolphinView::slotSelectedItemTextPressed(int index)
{
- if (GeneralSettings::renameInline()) {
+ if (GeneralSettings::renameInline() && !m_view->style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick)) {
const KFileItem item = m_model->fileItem(index);
const KFileItemListProperties capabilities(KFileItemList() << item);
if (capabilities.supportsMoving()) {
}
}
+void DolphinView::slotCopyingDone(KIO::Job *, const QUrl &, const QUrl &to)
+{
+ slotItemCreated(to);
+}
+
void DolphinView::slotItemCreated(const QUrl& url)
{
if (m_markFirstNewlySelectedItemAsCurrent) {
m_selectedUrls << url;
}
-void DolphinView::slotPasteJobResult(KJob *job)
+void DolphinView::slotJobResult(KJob *job)
{
if (job->error()) {
- emit errorMessage(job->errorString());
+ Q_EMIT errorMessage(job->errorString());
}
if (!m_selectedUrls.isEmpty()) {
- m_selectedUrls << KDirModel::simplifiedUrlList(m_selectedUrls);
+ m_selectedUrls = KDirModel::simplifiedUrlList(m_selectedUrls);
}
}
void DolphinView::emitSelectionChangedSignal()
{
m_selectionChangedTimer->stop();
- emit selectionChanged(selectedItems());
+ 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<KIO::StatJob *>(job)->statResult();
+ if (entry.contains(KIO::UDSEntry::UDS_RECURSIVE_SIZE)) {
+ // We have a precomputed value.
+ totalFileSize = static_cast<KIO::filesize_t>(
+ 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)
KItemModelBase* model = m_container->controller()->model();
model->setSortRole(role);
- emit sortRoleChanged(role);
+ Q_EMIT sortRoleChanged(role);
}
void DolphinView::updateSortOrder(Qt::SortOrder order)
m_model->setSortOrder(order);
- emit sortOrderChanged(order);
+ Q_EMIT sortOrderChanged(order);
}
void DolphinView::updateSortFoldersFirst(bool foldersFirst)
m_model->setSortDirectoriesFirst(foldersFirst);
- emit sortFoldersFirstChanged(foldersFirst);
+ Q_EMIT sortFoldersFirstChanged(foldersFirst);
}
QPair<bool, QString> DolphinView::pasteInfo() const
return QUrl();
}
+void DolphinView::resetZoomLevel()
+{
+ ViewModeSettings::ViewMode mode;
+
+ switch (m_mode) {
+ case IconsView: mode = ViewModeSettings::IconsMode; break;
+ case CompactView: mode = ViewModeSettings::CompactMode; break;
+ case DetailsView: mode = ViewModeSettings::DetailsMode; break;
+ }
+ const ViewModeSettings settings(mode);
+ const QSize iconSize = QSize(settings.iconSize(), settings.iconSize());
+ setZoomLevel(ZoomLevelInfo::zoomLevelForIconSize(iconSize));
+}
+
void DolphinView::observeCreatedItem(const QUrl& url)
{
if (m_active) {
void DolphinView::slotDirectoryRedirection(const QUrl& oldUrl, const QUrl& newUrl)
{
if (oldUrl.matches(url(), QUrl::StripTrailingSlash)) {
- emit redirection(oldUrl, newUrl);
+ Q_EMIT redirection(oldUrl, newUrl);
m_url = newUrl; // #186947
}
}
}
}
-void DolphinView::hideToolTip()
+void DolphinView::hideToolTip(const ToolTipManager::HideBehavior behavior)
{
#ifdef HAVE_BALOO
if (GeneralSettings::showToolTips()) {
- m_toolTipManager->hideToolTip();
+ m_toolTipManager->hideToolTip(behavior);
}
+#else
+ Q_UNUSED(behavior)
#endif
}
-void DolphinView::calculateItemCount(int& fileCount,
- int& folderCount,
- KIO::filesize_t& totalFileSize) const
-{
- 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;
- totalFileSize += item.size();
- }
- }
-}
-
void DolphinView::slotTwoClicksRenamingTimerTimeout()
{
const KItemListSelectionManager* selectionManager = m_container->controller()->selectionManager();
- // verify that only one item is selected and that no item is dragged
- if (selectionManager->selectedItems().count() == 1 && !m_dragging) {
+ // verify that only one item is selected
+ if (selectionManager->selectedItems().count() == 1) {
const int index = selectionManager->currentItem();
const QUrl fileItemUrl = m_model->fileItem(index).url();
void DolphinView::slotTrashFileFinished(KJob* job)
{
if (job->error() == 0) {
- emit operationCompletedMessage(i18nc("@info:status", "Trash operation completed."));
+ Q_EMIT operationCompletedMessage(i18nc("@info:status", "Trash operation completed."));
} else if (job->error() != KIO::ERR_USER_CANCELED) {
- emit errorMessage(job->errorString());
+ Q_EMIT errorMessage(job->errorString());
}
}
void DolphinView::slotDeleteFileFinished(KJob* job)
{
if (job->error() == 0) {
- emit operationCompletedMessage(i18nc("@info:status", "Delete operation completed."));
+ Q_EMIT operationCompletedMessage(i18nc("@info:status", "Delete operation completed."));
} else if (job->error() != KIO::ERR_USER_CANCELED) {
- emit errorMessage(job->errorString());
+ Q_EMIT errorMessage(job->errorString());
}
}
void DolphinView::slotDirectoryLoadingStarted()
{
+ m_loading = true;
+ updatePlaceholderLabel();
+
// Disable the writestate temporary until it can be determined in a fast way
- // in DolphinView::slotLoadingCompleted()
+ // in DolphinView::slotDirectoryLoadingCompleted()
if (m_isFolderWritable) {
m_isFolderWritable = false;
- emit writeStateChanged(m_isFolderWritable);
+ Q_EMIT writeStateChanged(m_isFolderWritable);
}
- emit directoryLoadingStarted();
+ Q_EMIT directoryLoadingStarted();
}
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);
- emit directoryLoadingCompleted();
+ // Update the placeholder label in case we found that the folder was empty
+ // after loading it
+
+ Q_EMIT directoryLoadingCompleted();
+ updatePlaceholderLabel();
updateWritableState();
}
+void DolphinView::slotDirectoryLoadingCanceled()
+{
+ m_loading = false;
+
+ updatePlaceholderLabel();
+
+ Q_EMIT directoryLoadingCanceled();
+}
+
void DolphinView::slotItemsChanged()
{
m_assureVisibleCurrentIndex = false;
void DolphinView::slotSortOrderChangedByHeader(Qt::SortOrder current, Qt::SortOrder previous)
{
- Q_UNUSED(previous);
+ Q_UNUSED(previous)
Q_ASSERT(m_model->sortOrder() == current);
ViewProperties props(viewPropertiesUrl());
props.setSortOrder(current);
- emit sortOrderChanged(current);
+ Q_EMIT sortOrderChanged(current);
}
void DolphinView::slotSortRoleChangedByHeader(const QByteArray& current, const QByteArray& previous)
{
- Q_UNUSED(previous);
+ Q_UNUSED(previous)
Q_ASSERT(m_model->sortRole() == current);
ViewProperties props(viewPropertiesUrl());
props.setSortRole(current);
- emit sortRoleChanged(current);
+ Q_EMIT sortRoleChanged(current);
}
void DolphinView::slotVisibleRolesChangedByHeader(const QList<QByteArray>& current,
const QList<QByteArray>& previous)
{
- Q_UNUSED(previous);
+ Q_UNUSED(previous)
Q_ASSERT(m_container->controller()->view()->visibleRoles() == current);
const QList<QByteArray> previousVisibleRoles = m_visibleRoles;
ViewProperties props(viewPropertiesUrl());
props.setVisibleRoles(m_visibleRoles);
- emit visibleRolesChanged(m_visibleRoles, previousVisibleRoles);
+ Q_EMIT visibleRolesChanged(m_visibleRoles, previousVisibleRoles);
}
void DolphinView::slotRoleEditingCanceled()
if (role == "text") {
const KFileItem oldItem = m_model->fileItem(index);
const QString newName = value.toString();
- if (!newName.isEmpty() && newName != oldItem.text() && newName != QLatin1String(".") && newName != QLatin1String("..")) {
+ if (!newName.isEmpty() && newName != oldItem.text() && newName != QLatin1Char('.') && newName != QLatin1String("..")) {
const QUrl oldUrl = oldItem.url();
QUrl newUrl = oldUrl.adjusted(QUrl::RemoveFilename);
newUrl.setPath(newUrl.path() + KIO::encodeFileName(newName));
+#ifndef Q_OS_WIN
+ //Confirm hiding file/directory by renaming inline
+ if (!hiddenFilesShown() && newName.startsWith(QLatin1Char('.')) && !oldItem.name().startsWith(QLatin1Char('.'))) {
+ KGuiItem yesGuiItem(KStandardGuiItem::yes());
+ yesGuiItem.setText(i18nc("@action:button", "Rename and Hide"));
+
+ const auto code = KMessageBox::questionYesNo(this,
+ 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"
+ "Do you still want to rename it?"),
+ oldItem.isFile() ? i18n("Hide this File?") : i18n("Hide this Folder?"),
+ yesGuiItem,
+ KStandardGuiItem::cancel(),
+ QStringLiteral("ConfirmHide")
+ );
+
+ if (code == KMessageBox::No) {
+ return;
+ }
+ }
+#endif
+
const bool newNameExistsAlready = (m_model->index(newUrl) >= 0);
if (!newNameExistsAlready) {
// Only change the data in the model if no item with the new name
if (!url.isValid()) {
const QString location(url.toDisplayString(QUrl::PreferLocalFile));
if (location.isEmpty()) {
- emit errorMessage(i18nc("@info:status", "The location is empty."));
+ Q_EMIT errorMessage(i18nc("@info:status", "The location is empty."));
} else {
- emit errorMessage(i18nc("@info:status", "The location '%1' is invalid.", location));
+ Q_EMIT errorMessage(i18nc("@info:status", "The location '%1' is invalid.", location));
}
return;
}
const int oldZoomLevel = m_view->zoomLevel();
applyModeToView();
- emit modeChanged(m_mode, previousMode);
+ Q_EMIT modeChanged(m_mode, previousMode);
if (m_view->zoomLevel() != oldZoomLevel) {
- emit zoomLevelChanged(m_view->zoomLevel(), oldZoomLevel);
+ Q_EMIT zoomLevelChanged(m_view->zoomLevel(), oldZoomLevel);
}
}
const bool hiddenFilesShown = props.hiddenFilesShown();
if (hiddenFilesShown != m_model->showHiddenFiles()) {
m_model->setShowHiddenFiles(hiddenFilesShown);
- emit hiddenFilesShownChanged(hiddenFilesShown);
+ Q_EMIT hiddenFilesShownChanged(hiddenFilesShown);
}
const bool groupedSorting = props.groupedSorting();
if (groupedSorting != m_model->groupedSorting()) {
m_model->setGroupedSorting(groupedSorting);
- emit groupedSortingChanged(groupedSorting);
+ Q_EMIT groupedSortingChanged(groupedSorting);
}
const QByteArray sortRole = props.sortRole();
if (sortRole != m_model->sortRole()) {
m_model->setSortRole(sortRole);
- emit sortRoleChanged(sortRole);
+ Q_EMIT sortRoleChanged(sortRole);
}
const Qt::SortOrder sortOrder = props.sortOrder();
if (sortOrder != m_model->sortOrder()) {
m_model->setSortOrder(sortOrder);
- emit sortOrderChanged(sortOrder);
+ Q_EMIT sortOrderChanged(sortOrder);
}
const bool sortFoldersFirst = props.sortFoldersFirst();
if (sortFoldersFirst != m_model->sortDirectoriesFirst()) {
m_model->setSortDirectoriesFirst(sortFoldersFirst);
- emit sortFoldersFirstChanged(sortFoldersFirst);
+ Q_EMIT sortFoldersFirstChanged(sortFoldersFirst);
}
const QList<QByteArray> visibleRoles = props.visibleRoles();
const QList<QByteArray> previousVisibleRoles = m_visibleRoles;
m_visibleRoles = visibleRoles;
m_view->setVisibleRoles(visibleRoles);
- emit visibleRolesChanged(m_visibleRoles, previousVisibleRoles);
+ Q_EMIT visibleRolesChanged(m_visibleRoles, previousVisibleRoles);
}
const bool previewsShown = props.previewsShown();
const int oldZoomLevel = zoomLevel();
m_view->setPreviewsShown(previewsShown);
- emit previewsShownChanged(previewsShown);
+ Q_EMIT previewsShownChanged(previewsShown);
// Changing the preview-state might result in a changed zoom-level
if (oldZoomLevel != zoomLevel()) {
- emit zoomLevelChanged(zoomLevel(), oldZoomLevel);
+ Q_EMIT zoomLevelChanged(zoomLevel(), oldZoomLevel);
}
}
m_clearSelectionBeforeSelectingNewItems = true;
m_markFirstNewlySelectedItemAsCurrent = true;
connect(job, &KIO::PasteJob::itemCreated, this, &DolphinView::slotItemCreated);
- connect(job, &KIO::PasteJob::result, this, &DolphinView::slotPasteJobResult);
+ connect(job, &KIO::PasteJob::result, this, &DolphinView::slotJobResult);
}
QList<QUrl> DolphinView::simplifiedSelectedUrls() const
const KFileItemList items = selectedItems();
urls.reserve(items.count());
- foreach (const KFileItem& item, items) {
+ for (const KFileItem& item : items) {
urls.append(item.url());
}
m_isFolderWritable = capabilities.supportsWriting();
if (m_isFolderWritable != wasFolderWritable) {
- emit writeStateChanged(m_isFolderWritable);
+ Q_EMIT writeStateChanged(m_isFolderWritable);
}
}
markUrlAsCurrent(current);
markUrlsAsSelected(selected);
}
+
+void DolphinView::copyPathToClipboard()
+{
+ const KFileItemList list = selectedItems();
+ if (list.isEmpty()) {
+ return;
+ }
+ const KFileItem& item = list.at(0);
+ QString path = item.localPath();
+ if (path.isEmpty()) {
+ path = item.url().toDisplayString();
+ }
+ QClipboard* clipboard = QApplication::clipboard();
+ if (clipboard == nullptr) {
+ return;
+ }
+ clipboard->setText(path);
+}
+
+void DolphinView::slotIncreaseZoom()
+{
+ setZoomLevel(zoomLevel() + 1);
+}
+
+void DolphinView::slotDecreaseZoom()
+{
+ setZoomLevel(zoomLevel() - 1);
+}
+
+void DolphinView::slotSwipeUp()
+{
+ Q_EMIT goUpRequested();
+}
+
+void DolphinView::updatePlaceholderLabel()
+{
+ if (m_loading || itemsCount() > 0) {
+ m_placeholderLabel->setVisible(false);
+ 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")) {
+ m_placeholderLabel->setText(i18n("Trash is empty"));
+ } else if (m_url.scheme() == QLatin1String("tags")) {
+ m_placeholderLabel->setText(i18n("No tags"));
+ } else if (m_url.scheme() == QLatin1String("recentlyused")) {
+ m_placeholderLabel->setText(i18n("No recently used items"));
+ } else if (m_url.scheme() == QLatin1String("smb")) {
+ 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")) {
+ m_placeholderLabel->setText(i18n("No MTP-compatible devices found"));
+ } else if (m_url.scheme() == QLatin1String("bluetooth")) {
+ m_placeholderLabel->setText(i18n("No Bluetooth devices found"));
+ } else {
+ m_placeholderLabel->setText(i18n("Folder is empty"));
+ }
+
+ m_placeholderLabel->setVisible(true);
+}