X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/blobdiff_plain/be9746e87bb6a42e641dbf36c528a60fb564420a..1826f905d706925456763394de17294bcb6d1c35:/src/dolphinviewcontainer.cpp diff --git a/src/dolphinviewcontainer.cpp b/src/dolphinviewcontainer.cpp index 0b2812a7c..076551e5d 100644 --- a/src/dolphinviewcontainer.cpp +++ b/src/dolphinviewcontainer.cpp @@ -1,503 +1,1001 @@ -/*************************************************************************** - * Copyright (C) 2007 by Peter Penz * - * * - * 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: 2007 Peter Penz + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ #include "dolphinviewcontainer.h" -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "dolphincolumnview.h" -#include "dolphincontroller.h" -#include "dolphinstatusbar.h" -#include "dolphinmainwindow.h" -#include "dolphindirlister.h" -#include "dolphinsortfilterproxymodel.h" -#include "dolphindetailsview.h" -#include "dolphiniconsview.h" -#include "dolphincontextmenu.h" -#include "dolphinitemcategorizer.h" -#include "filterbar.h" -#include "renamedialog.h" -#include "kurlnavigator.h" -#include "viewproperties.h" -#include "dolphinsettings.h" +#include "dolphin_compactmodesettings.h" +#include "dolphin_contentdisplaysettings.h" +#include "dolphin_detailsmodesettings.h" #include "dolphin_generalsettings.h" - -DolphinViewContainer::DolphinViewContainer(DolphinMainWindow* mainWindow, - QWidget* parent, - const KUrl& url, - DolphinView::Mode mode, - bool showHiddenFiles) : - QWidget(parent), - m_showProgress(false), - m_folderCount(0), - m_fileCount(0), - m_mainWindow(mainWindow), - m_topLayout(0), - m_urlNavigator(0), - m_view(0), - m_filterBar(0), - m_statusBar(0), - m_dirModel(0), - m_dirLister(0), - m_proxyModel(0) +#include "dolphin_iconsmodesettings.h" +#include "dolphindebug.h" +#include "dolphinplacesmodelsingleton.h" +#include "filterbar/filterbar.h" +#include "global.h" +#include "search/dolphinsearchbox.h" +#include "selectionmode/topbar.h" +#include "statusbar/dolphinstatusbar.h" + +#include +#if HAVE_KACTIVITIES +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +// An overview of the widgets contained by this ViewContainer +struct LayoutStructure { + int searchBox = 0; + int messageWidget = 1; + int selectionModeTopBar = 2; + int view = 3; + int selectionModeBottomBar = 4; + int filterBar = 5; + int statusBar = 6; +}; +constexpr LayoutStructure positionFor; + +DolphinViewContainer::DolphinViewContainer(const QUrl &url, QWidget *parent) + : QWidget(parent) + , m_topLayout(nullptr) + , m_urlNavigator{new DolphinUrlNavigator(url)} + , m_urlNavigatorConnected{nullptr} + , m_searchBox(nullptr) + , m_searchModeEnabled(false) + , m_messageWidget(nullptr) + , m_selectionModeTopBar{nullptr} + , m_view(nullptr) + , m_filterBar(nullptr) + , m_selectionModeBottomBar{nullptr} + , m_statusBar(nullptr) + , m_statusBarTimer(nullptr) + , m_statusBarTimestamp() + , m_autoGrabFocus(true) +#if HAVE_KACTIVITIES + , m_activityResourceInstance(nullptr) +#endif { hide(); - setFocusPolicy(Qt::StrongFocus); - m_topLayout = new QVBoxLayout(this); + + m_topLayout = new QGridLayout(this); m_topLayout->setSpacing(0); - m_topLayout->setMargin(0); - - connect(m_mainWindow, SIGNAL(activeViewChanged()), - this, SLOT(updateActivationState())); - - QClipboard* clipboard = QApplication::clipboard(); - connect(clipboard, SIGNAL(dataChanged()), - this, SLOT(updateCutItems())); - - m_urlNavigator = new KUrlNavigator(DolphinSettings::instance().placesModel(), url, this); - - const GeneralSettings* settings = DolphinSettings::instance().generalSettings(); - m_urlNavigator->setUrlEditable(settings->editableUrl()); - m_urlNavigator->setHomeUrl(settings->homeUrl()); - - m_dirLister = new DolphinDirLister(); - m_dirLister->setAutoUpdate(true); - m_dirLister->setMainWindow(this); - m_dirLister->setShowingDotFiles(showHiddenFiles); - m_dirLister->setDelayedMimeTypes(true); - - m_dirModel = new KDirModel(); - m_dirModel->setDirLister(m_dirLister); - m_dirModel->setDropsAllowed(KDirModel::DropOnDirectory); - - m_proxyModel = new DolphinSortFilterProxyModel(this); - m_proxyModel->setSourceModel(m_dirModel); - - connect(m_dirLister, SIGNAL(clear()), - this, SLOT(updateStatusBar())); - connect(m_dirLister, SIGNAL(percent(int)), - this, SLOT(updateProgress(int))); - connect(m_dirLister, SIGNAL(deleteItem(KFileItem*)), - this, SLOT(updateStatusBar())); - connect(m_dirLister, SIGNAL(completed()), - this, SLOT(updateItemCount())); - connect(m_dirLister, SIGNAL(completed()), - this, SLOT(updateCutItems())); - connect(m_dirLister, SIGNAL(newItems(const KFileItemList&)), - this, SLOT(generatePreviews(const KFileItemList&))); - connect(m_dirLister, SIGNAL(infoMessage(const QString&)), - this, SLOT(showInfoMessage(const QString&))); - connect(m_dirLister, SIGNAL(errorMessage(const QString&)), - this, SLOT(showErrorMessage(const QString&))); - - m_view = new DolphinView(this, - url, - m_dirLister, - m_dirModel, - m_proxyModel, - mode, - showHiddenFiles); - connect(m_view, SIGNAL(urlChanged(const KUrl&)), - m_urlNavigator, SLOT(setUrl(const KUrl&))); - connect(m_view, SIGNAL(requestContextMenu(KFileItem*, const KUrl&)), - this, SLOT(openContextMenu(KFileItem*, const KUrl&))); - connect(m_view, SIGNAL(urlsDropped(const KUrl::List&, const KUrl&)), - m_mainWindow, SLOT(dropUrls(const KUrl::List&, const KUrl&))); - - connect(m_urlNavigator, SIGNAL(urlChanged(const KUrl&)), - m_view, SLOT(setUrl(const KUrl&))); - - m_statusBar = new DolphinStatusBar(this, url); + m_topLayout->setContentsMargins(0, 0, 0, 0); + + m_searchBox = new DolphinSearchBox(this); + m_searchBox->hide(); + connect(m_searchBox, &DolphinSearchBox::activated, this, &DolphinViewContainer::activate); + connect(m_searchBox, &DolphinSearchBox::openRequest, this, &DolphinViewContainer::openSearchBox); + connect(m_searchBox, &DolphinSearchBox::closeRequest, this, &DolphinViewContainer::closeSearchBox); + connect(m_searchBox, &DolphinSearchBox::searchRequest, this, &DolphinViewContainer::startSearching); + connect(m_searchBox, &DolphinSearchBox::focusViewRequest, this, &DolphinViewContainer::requestFocus); + m_searchBox->setWhatsThis(xi18nc("@info:whatsthis findbar", + "This helps you find files and folders. Enter a " + "search term and specify search settings with the " + "buttons at the bottom:Filename/Content: " + "Does the item you are looking for contain the search terms " + "within its filename or its contents?The contents of images, " + "audio files and videos will not be searched." + "From Here/Everywhere: Do you want to search in this " + "folder and its sub-folders or everywhere?" + "More Options: Click this to search by media type, access " + "time or rating.More Search Tools: Install other " + "means to find an item.")); + + m_messageWidget = new KMessageWidget(this); + m_messageWidget->setCloseButtonVisible(true); + m_messageWidget->hide(); + +#ifndef Q_OS_WIN + if (getuid() == 0) { + // We must be logged in as the root user; show a big scary warning + showMessage(i18n("Running Dolphin as root can be dangerous. Please be careful."), Warning); + } +#endif + // Initialize filter bar m_filterBar = new FilterBar(this); - m_filterBar->setVisible(settings->filterBar()); - connect(m_filterBar, SIGNAL(filterChanged(const QString&)), - this, SLOT(changeNameFilter(const QString&))); - connect(m_filterBar, SIGNAL(closeRequest()), - this, SLOT(closeFilterBar())); - - m_topLayout->addWidget(m_urlNavigator); - m_topLayout->addWidget(m_view); - m_topLayout->addWidget(m_filterBar); - m_topLayout->addWidget(m_statusBar); + m_filterBar->setVisible(GeneralSettings::filterBar()); + + connect(m_filterBar, &FilterBar::filterChanged, this, &DolphinViewContainer::setNameFilter); + connect(m_filterBar, &FilterBar::closeRequest, this, &DolphinViewContainer::closeFilterBar); + connect(m_filterBar, &FilterBar::focusViewRequest, this, &DolphinViewContainer::requestFocus); + + // Initialize the main view + m_view = new DolphinView(url, this); + connect(m_view, &DolphinView::urlChanged, m_filterBar, &FilterBar::clearIfUnlocked); + connect(m_view, &DolphinView::urlChanged, m_messageWidget, &KMessageWidget::hide); + // m_urlNavigator stays in sync with m_view's location changes and + // keeps track of them so going back and forth in the history works. + connect(m_view, &DolphinView::urlChanged, m_urlNavigator.get(), &DolphinUrlNavigator::setLocationUrl); + connect(m_urlNavigator.get(), &DolphinUrlNavigator::urlChanged, this, &DolphinViewContainer::slotUrlNavigatorLocationChanged); + connect(m_urlNavigator.get(), &DolphinUrlNavigator::urlAboutToBeChanged, this, &DolphinViewContainer::slotUrlNavigatorLocationAboutToBeChanged); + connect(m_urlNavigator.get(), &DolphinUrlNavigator::urlSelectionRequested, this, &DolphinViewContainer::slotUrlSelectionRequested); + connect(m_view, &DolphinView::writeStateChanged, this, &DolphinViewContainer::writeStateChanged); + connect(m_view, &DolphinView::requestItemInfo, this, &DolphinViewContainer::showItemInfo); + connect(m_view, &DolphinView::itemActivated, this, &DolphinViewContainer::slotItemActivated); + connect(m_view, &DolphinView::fileMiddleClickActivated, this, &DolphinViewContainer::slotfileMiddleClickActivated); + connect(m_view, &DolphinView::itemsActivated, this, &DolphinViewContainer::slotItemsActivated); + connect(m_view, &DolphinView::redirection, this, &DolphinViewContainer::redirect); + connect(m_view, &DolphinView::directoryLoadingStarted, this, &DolphinViewContainer::slotDirectoryLoadingStarted); + connect(m_view, &DolphinView::directoryLoadingCompleted, this, &DolphinViewContainer::slotDirectoryLoadingCompleted); + connect(m_view, &DolphinView::directoryLoadingCanceled, this, &DolphinViewContainer::slotDirectoryLoadingCanceled); + connect(m_view, &DolphinView::itemCountChanged, this, &DolphinViewContainer::delayedStatusBarUpdate); + connect(m_view, &DolphinView::directoryLoadingProgress, this, &DolphinViewContainer::updateDirectoryLoadingProgress); + connect(m_view, &DolphinView::directorySortingProgress, this, &DolphinViewContainer::updateDirectorySortingProgress); + connect(m_view, &DolphinView::selectionChanged, this, &DolphinViewContainer::delayedStatusBarUpdate); + connect(m_view, &DolphinView::errorMessage, this, &DolphinViewContainer::showErrorMessage); + connect(m_view, &DolphinView::urlIsFileError, this, &DolphinViewContainer::slotUrlIsFileError); + connect(m_view, &DolphinView::activated, this, &DolphinViewContainer::activate); + connect(m_view, &DolphinView::hiddenFilesShownChanged, this, &DolphinViewContainer::slotHiddenFilesShownChanged); + connect(m_view, &DolphinView::sortHiddenLastChanged, this, &DolphinViewContainer::slotSortHiddenLastChanged); + connect(m_view, &DolphinView::currentDirectoryRemoved, this, &DolphinViewContainer::slotCurrentDirectoryRemoved); + + // Initialize status bar + m_statusBar = new DolphinStatusBar(this); + m_statusBar->setUrl(m_view->url()); + m_statusBar->setZoomLevel(m_view->zoomLevel()); + connect(m_view, &DolphinView::urlChanged, m_statusBar, &DolphinStatusBar::setUrl); + connect(m_view, &DolphinView::zoomLevelChanged, m_statusBar, &DolphinStatusBar::setZoomLevel); + connect(m_view, &DolphinView::infoMessage, m_statusBar, &DolphinStatusBar::setText); + connect(m_view, &DolphinView::operationCompletedMessage, m_statusBar, &DolphinStatusBar::setText); + connect(m_view, &DolphinView::statusBarTextChanged, m_statusBar, &DolphinStatusBar::setDefaultText); + connect(m_view, &DolphinView::statusBarTextChanged, m_statusBar, &DolphinStatusBar::resetToDefaultText); + connect(m_statusBar, &DolphinStatusBar::stopPressed, this, &DolphinViewContainer::stopDirectoryLoading); + connect(m_statusBar, &DolphinStatusBar::zoomLevelChanged, this, &DolphinViewContainer::slotStatusBarZoomLevelChanged); + + m_statusBarTimer = new QTimer(this); + m_statusBarTimer->setSingleShot(true); + m_statusBarTimer->setInterval(300); + connect(m_statusBarTimer, &QTimer::timeout, this, &DolphinViewContainer::updateStatusBar); + + KIO::FileUndoManager *undoManager = KIO::FileUndoManager::self(); + connect(undoManager, &KIO::FileUndoManager::jobRecordingFinished, this, &DolphinViewContainer::delayedStatusBarUpdate); + + m_topLayout->addWidget(m_searchBox, positionFor.searchBox, 0); + m_topLayout->addWidget(m_messageWidget, positionFor.messageWidget, 0); + m_topLayout->addWidget(m_view, positionFor.view, 0); + m_topLayout->addWidget(m_filterBar, positionFor.filterBar, 0); + m_topLayout->addWidget(m_statusBar, positionFor.statusBar, 0); + + setSearchModeEnabled(isSearchUrl(url)); + + // Update view as the ContentDisplaySettings change + // this happens here and not in DolphinView as DolphinviewContainer and DolphinView are not in the same build target ATM + connect(ContentDisplaySettings::self(), &KCoreConfigSkeleton::configChanged, m_view, &DolphinView::reload); + + KFilePlacesModel *placesModel = DolphinPlacesModelSingleton::instance().placesModel(); + connect(placesModel, &KFilePlacesModel::dataChanged, this, &DolphinViewContainer::slotPlacesModelChanged); + connect(placesModel, &KFilePlacesModel::rowsInserted, this, &DolphinViewContainer::slotPlacesModelChanged); + connect(placesModel, &KFilePlacesModel::rowsRemoved, this, &DolphinViewContainer::slotPlacesModelChanged); + + connect(this, &DolphinViewContainer::searchModeEnabledChanged, this, &DolphinViewContainer::captionChanged); + + // Initialize kactivities resource instance + +#if HAVE_KACTIVITIES + m_activityResourceInstance = new KActivities::ResourceInstance(window()->winId(), url); + m_activityResourceInstance->setParent(this); +#endif } DolphinViewContainer::~DolphinViewContainer() { - delete m_dirLister; - m_dirLister = 0; } -void DolphinViewContainer::setUrl(const KUrl& url) +QUrl DolphinViewContainer::url() const { - m_urlNavigator->setUrl(url); + return m_view->url(); } -const KUrl& DolphinViewContainer::url() const +KFileItem DolphinViewContainer::rootItem() const { - return m_urlNavigator->url(); + return m_view->rootItem(); } void DolphinViewContainer::setActive(bool active) { - m_urlNavigator->setActive(active); + m_searchBox->setActive(active); + if (m_urlNavigatorConnected) { + m_urlNavigatorConnected->setActive(active); + } m_view->setActive(active); + +#if HAVE_KACTIVITIES + if (active) { + m_activityResourceInstance->notifyFocusedIn(); + } else { + m_activityResourceInstance->notifyFocusedOut(); + } +#endif } bool DolphinViewContainer::isActive() const { - Q_ASSERT(m_view->isActive() == m_urlNavigator->isActive()); return m_view->isActive(); } -void DolphinViewContainer::renameSelectedItems() +void DolphinViewContainer::setAutoGrabFocus(bool grab) { - DolphinViewContainer* view = m_mainWindow->activeViewContainer(); - const KUrl::List urls = m_view->selectedUrls(); - if (urls.count() > 1) { - // More than one item has been selected for renaming. Open - // a rename dialog and rename all items afterwards. - RenameDialog dialog(urls); - if (dialog.exec() == QDialog::Rejected) { - return; - } + m_autoGrabFocus = grab; +} - const QString& newName = dialog.newName(); - if (newName.isEmpty()) { - view->statusBar()->setMessage(dialog.errorString(), - DolphinStatusBar::Error); - } else { - // TODO: check how this can be integrated into KonqUndoManager/KonqOperations - // as one operation instead of n rename operations like it is done now... - Q_ASSERT(newName.contains('#')); - - // iterate through all selected items and rename them... - const int replaceIndex = newName.indexOf('#'); - Q_ASSERT(replaceIndex >= 0); - int index = 1; - - KUrl::List::const_iterator it = urls.begin(); - KUrl::List::const_iterator end = urls.end(); - while (it != end) { - const KUrl& oldUrl = *it; - QString number; - number.setNum(index++); - - QString name(newName); - name.replace(replaceIndex, 1, number); - - if (oldUrl.fileName() != name) { - KUrl newUrl = oldUrl; - newUrl.setFileName(name); - m_mainWindow->rename(oldUrl, newUrl); - } - ++it; - } +bool DolphinViewContainer::autoGrabFocus() const +{ + return m_autoGrabFocus; +} + +QString DolphinViewContainer::currentSearchText() const +{ + return m_searchBox->text(); +} + +const DolphinStatusBar *DolphinViewContainer::statusBar() const +{ + return m_statusBar; +} + +DolphinStatusBar *DolphinViewContainer::statusBar() +{ + return m_statusBar; +} + +const DolphinUrlNavigator *DolphinViewContainer::urlNavigator() const +{ + return m_urlNavigatorConnected; +} + +DolphinUrlNavigator *DolphinViewContainer::urlNavigator() +{ + return m_urlNavigatorConnected; +} + +const DolphinUrlNavigator *DolphinViewContainer::urlNavigatorInternalWithHistory() const +{ + return m_urlNavigator.get(); +} + +DolphinUrlNavigator *DolphinViewContainer::urlNavigatorInternalWithHistory() +{ + return m_urlNavigator.get(); +} + +const DolphinView *DolphinViewContainer::view() const +{ + return m_view; +} + +DolphinView *DolphinViewContainer::view() +{ + return m_view; +} + +void DolphinViewContainer::connectUrlNavigator(DolphinUrlNavigator *urlNavigator) +{ + Q_CHECK_PTR(urlNavigator); + Q_ASSERT(!m_urlNavigatorConnected); + Q_ASSERT(m_urlNavigator.get() != urlNavigator); + Q_CHECK_PTR(m_view); + + urlNavigator->setLocationUrl(m_view->url()); + urlNavigator->setShowHiddenFolders(m_view->hiddenFilesShown()); + urlNavigator->setSortHiddenFoldersLast(m_view->sortHiddenLast()); + if (m_urlNavigatorVisualState) { + urlNavigator->setVisualState(*m_urlNavigatorVisualState.get()); + m_urlNavigatorVisualState.reset(); + } + urlNavigator->setActive(isActive()); + + // Url changes are still done via m_urlNavigator. + connect(urlNavigator, &DolphinUrlNavigator::urlChanged, m_urlNavigator.get(), &DolphinUrlNavigator::setLocationUrl); + connect(urlNavigator, &DolphinUrlNavigator::urlsDropped, this, [=](const QUrl &destination, QDropEvent *event) { + m_view->dropUrls(destination, event, urlNavigator->dropWidget()); + }); + // Aside from these, only visual things need to be connected. + connect(m_view, &DolphinView::urlChanged, urlNavigator, &DolphinUrlNavigator::setLocationUrl); + connect(urlNavigator, &DolphinUrlNavigator::activated, this, &DolphinViewContainer::activate); + + m_urlNavigatorConnected = urlNavigator; +} + +void DolphinViewContainer::disconnectUrlNavigator() +{ + if (!m_urlNavigatorConnected) { + return; + } + + disconnect(m_urlNavigatorConnected, &DolphinUrlNavigator::urlChanged, m_urlNavigator.get(), &DolphinUrlNavigator::setLocationUrl); + disconnect(m_urlNavigatorConnected, &DolphinUrlNavigator::urlsDropped, this, nullptr); + disconnect(m_view, &DolphinView::urlChanged, m_urlNavigatorConnected, &DolphinUrlNavigator::setLocationUrl); + disconnect(m_urlNavigatorConnected, &DolphinUrlNavigator::activated, this, &DolphinViewContainer::activate); + + m_urlNavigatorVisualState = m_urlNavigatorConnected->visualState(); + m_urlNavigatorConnected = nullptr; +} + +void DolphinViewContainer::setSelectionModeEnabled(bool enabled, KActionCollection *actionCollection, SelectionMode::BottomBar::Contents bottomBarContents) +{ + const bool wasEnabled = m_view->selectionMode(); + m_view->setSelectionModeEnabled(enabled); + + if (!enabled) { + if (!wasEnabled) { + return; // nothing to do here } - } else { - // Only one item has been selected for renaming. Use the custom - // renaming mechanism from the views. - Q_ASSERT(urls.count() == 1); - - // TODO: Think about using KFileItemDelegate as soon as it supports editing. - // Currently the RenameDialog is used, but I'm not sure whether inline renaming - // is a benefit for the user at all -> let's wait for some input first... - RenameDialog dialog(urls); - if (dialog.exec() == QDialog::Rejected) { - return; + Q_CHECK_PTR(m_selectionModeTopBar); // there is no point in disabling selectionMode when it wasn't even enabled once. + Q_CHECK_PTR(m_selectionModeBottomBar); + if (m_selectionModeTopBar->isAncestorOf(QApplication::focusWidget()) || m_selectionModeBottomBar->isAncestorOf(QApplication::focusWidget())) { + m_view->setFocus(); } + m_selectionModeTopBar->setVisible(false, WithAnimation); + m_selectionModeBottomBar->setVisible(false, WithAnimation); + Q_EMIT selectionModeChanged(false); + return; + } - const QString& newName = dialog.newName(); - if (newName.isEmpty()) { - view->statusBar()->setMessage(dialog.errorString(), - DolphinStatusBar::Error); - } else { - const KUrl& oldUrl = urls.first(); - KUrl newUrl = oldUrl; - newUrl.setFileName(newName); - m_mainWindow->rename(oldUrl, newUrl); - } + if (!m_selectionModeTopBar) { + // Changing the location will disable selection mode. + connect(m_urlNavigator.get(), &DolphinUrlNavigator::urlChanged, this, [this]() { + setSelectionModeEnabled(false); + }); + + m_selectionModeTopBar = new SelectionMode::TopBar(this); // will be created hidden + connect(m_selectionModeTopBar, &SelectionMode::TopBar::selectionModeLeavingRequested, this, [this]() { + setSelectionModeEnabled(false); + }); + m_topLayout->addWidget(m_selectionModeTopBar, positionFor.selectionModeTopBar, 0); + } + + if (!m_selectionModeBottomBar) { + m_selectionModeBottomBar = new SelectionMode::BottomBar(actionCollection, this); + connect(m_view, &DolphinView::selectionChanged, this, [this](const KFileItemList &selection) { + m_selectionModeBottomBar->slotSelectionChanged(selection, m_view->url()); + }); + connect(m_selectionModeBottomBar, &SelectionMode::BottomBar::error, this, [this](const QString &errorMessage) { + showErrorMessage(errorMessage); + }); + connect(m_selectionModeBottomBar, &SelectionMode::BottomBar::selectionModeLeavingRequested, this, [this]() { + setSelectionModeEnabled(false); + }); + m_topLayout->addWidget(m_selectionModeBottomBar, positionFor.selectionModeBottomBar, 0); + } + m_selectionModeBottomBar->resetContents(bottomBarContents); + if (bottomBarContents == SelectionMode::BottomBar::GeneralContents) { + m_selectionModeBottomBar->slotSelectionChanged(m_view->selectedItems(), m_view->url()); + } + + if (!wasEnabled) { + m_selectionModeTopBar->setVisible(true, WithAnimation); + m_selectionModeBottomBar->setVisible(true, WithAnimation); + Q_EMIT selectionModeChanged(true); } } -DolphinStatusBar* DolphinViewContainer::statusBar() const +bool DolphinViewContainer::isSelectionModeEnabled() const { - return m_statusBar; + const bool isEnabled = m_view->selectionMode(); + Q_ASSERT((!isEnabled + // We can't assert that the bars are invisible only because the selection mode is disabled because the hide animation might still be playing. + && (!m_selectionModeBottomBar || !m_selectionModeBottomBar->isEnabled() || !m_selectionModeBottomBar->isVisible() + || m_selectionModeBottomBar->contents() == SelectionMode::BottomBar::PasteContents)) + || (isEnabled && m_selectionModeTopBar + && m_selectionModeTopBar->isVisible() + // The bottom bar is either visible or was hidden because it has nothing to show in GeneralContents mode e.g. because no items are selected. + && m_selectionModeBottomBar + && (m_selectionModeBottomBar->isVisible() || m_selectionModeBottomBar->contents() == SelectionMode::BottomBar::GeneralContents))); + return isEnabled; } -bool DolphinViewContainer::isFilterBarVisible() const +void DolphinViewContainer::slotSplitTabDisabled() { - return m_filterBar->isVisible(); + if (m_selectionModeBottomBar) { + m_selectionModeBottomBar->slotSplitTabDisabled(); + } } -bool DolphinViewContainer::isUrlEditable() const +void DolphinViewContainer::showMessage(const QString &msg, MessageType type) { - return m_urlNavigator->isUrlEditable(); + if (msg.isEmpty()) { + return; + } + + m_messageWidget->setText(msg); + + // TODO: wrap at arbitrary character positions once QLabel can do this + // https://bugreports.qt.io/browse/QTBUG-1276 + m_messageWidget->setWordWrap(true); + + switch (type) { + case Information: + m_messageWidget->setMessageType(KMessageWidget::Information); + break; + case Warning: + m_messageWidget->setMessageType(KMessageWidget::Warning); + break; + case Error: + m_messageWidget->setMessageType(KMessageWidget::Error); + break; + default: + Q_ASSERT(false); + break; + } + + m_messageWidget->setWordWrap(false); + const int unwrappedWidth = m_messageWidget->sizeHint().width(); + m_messageWidget->setWordWrap(unwrappedWidth > size().width()); + + if (m_messageWidget->isVisible()) { + m_messageWidget->hide(); + } + m_messageWidget->animatedShow(); } -KFileItem* DolphinViewContainer::fileItem(const QModelIndex index) const +void DolphinViewContainer::readSettings() { - const QModelIndex dirModelIndex = m_proxyModel->mapToSource(index); - return m_dirModel->itemForIndex(dirModelIndex); + // The startup settings should (only) get applied if they have been + // modified by the user. Otherwise keep the (possibly) different current + // setting of the filterbar. + if (GeneralSettings::modifiedStartupSettings()) { + setFilterBarVisible(GeneralSettings::filterBar()); + } + + m_view->readSettings(); + m_statusBar->readSettings(); +} + +bool DolphinViewContainer::isFilterBarVisible() const +{ + return m_filterBar->isVisible(); } -void DolphinViewContainer::rename(const KUrl& source, const QString& newName) +void DolphinViewContainer::setSearchModeEnabled(bool enabled) { - bool ok = false; + m_searchBox->setVisible(enabled); + + if (enabled) { + const QUrl &locationUrl = m_urlNavigator->locationUrl(); + m_searchBox->fromSearchUrl(locationUrl); + } - if (newName.isEmpty() || (source.fileName() == newName)) { + if (enabled == isSearchModeEnabled()) { + if (enabled && !m_searchBox->hasFocus()) { + m_searchBox->setFocus(); + m_searchBox->selectAll(); + } return; } - KUrl dest(source.upUrl()); - dest.addPath(newName); - - const bool destExists = KIO::NetAccess::exists(dest, false, this); - if (destExists) { - // the destination already exists, hence ask the user - // how to proceed... - KIO::RenameDialog renameDialog(this, - i18n("File Already Exists"), - source.path(), - dest.path(), - KIO::M_OVERWRITE); - switch (renameDialog.exec()) { - case KIO::R_OVERWRITE: - // the destination should be overwritten - ok = KIO::NetAccess::file_move(source, dest, -1, true); - break; - - case KIO::R_RENAME: { - // a new name for the destination has been used - KUrl newDest(renameDialog.newDestUrl()); - ok = KIO::NetAccess::file_move(source, newDest); - break; + if (!enabled) { + m_view->setViewPropertiesContext(QString()); + + // Restore the URL for the URL navigator. If Dolphin has been + // started with a search-URL, the home URL is used as fallback. + QUrl url = m_searchBox->searchPath(); + if (url.isEmpty() || !url.isValid() || isSearchUrl(url)) { + url = Dolphin::homeUrl(); } + m_urlNavigatorConnected->setLocationUrl(url); + } + + m_searchModeEnabled = enabled; - default: - // the renaming operation has been canceled - return; + Q_EMIT searchModeEnabledChanged(enabled); +} + +bool DolphinViewContainer::isSearchModeEnabled() const +{ + return m_searchModeEnabled; +} + +QString DolphinViewContainer::placesText() const +{ + QString text; + + if (isSearchModeEnabled()) { + text = i18n("Search for %1 in %2", m_searchBox->text(), m_searchBox->searchPath().fileName()); + } else { + text = url().adjusted(QUrl::StripTrailingSlash).fileName(); + if (text.isEmpty()) { + text = url().host(); + } + if (text.isEmpty()) { + text = url().scheme(); + } + } + + return text; +} + +void DolphinViewContainer::reload() +{ + view()->reload(); + m_messageWidget->hide(); +} + +QString DolphinViewContainer::captionWindowTitle() const +{ + if (GeneralSettings::showFullPathInTitlebar() && !isSearchModeEnabled()) { + if (!url().isLocalFile()) { + return url().adjusted(QUrl::StripTrailingSlash).toString(); } + return url().adjusted(QUrl::StripTrailingSlash).path(); } else { - // no destination exists, hence just move the file to - // do the renaming - ok = KIO::NetAccess::file_move(source, dest); + return DolphinViewContainer::caption(); + } +} + +QString DolphinViewContainer::caption() const +{ + if (isSearchModeEnabled()) { + if (currentSearchText().isEmpty()) { + return i18n("Search"); + } else { + return i18n("Search for %1", currentSearchText()); + } + } + + KFilePlacesModel *placesModel = DolphinPlacesModelSingleton::instance().placesModel(); + const QString pattern = url().adjusted(QUrl::StripTrailingSlash).toString(QUrl::FullyEncoded).append("/?"); + const auto &matchedPlaces = + placesModel->match(placesModel->index(0, 0), KFilePlacesModel::UrlRole, QRegularExpression::anchoredPattern(pattern), 1, Qt::MatchRegularExpression); + + if (!matchedPlaces.isEmpty()) { + return placesModel->text(matchedPlaces.first()); + } + + if (!url().isLocalFile()) { + QUrl adjustedUrl = url().adjusted(QUrl::StripTrailingSlash); + QString caption; + if (!adjustedUrl.fileName().isEmpty()) { + caption = adjustedUrl.fileName(); + } else if (!adjustedUrl.path().isEmpty() && adjustedUrl.path() != "/") { + caption = adjustedUrl.path(); + } else if (!adjustedUrl.host().isEmpty()) { + caption = adjustedUrl.host(); + } else { + caption = adjustedUrl.toString(); + } + return caption; + } + + QString fileName = url().adjusted(QUrl::StripTrailingSlash).fileName(); + if (fileName.isEmpty()) { + fileName = '/'; + } + + return fileName; +} + +void DolphinViewContainer::setUrl(const QUrl &newUrl) +{ + if (newUrl != m_urlNavigator->locationUrl()) { + m_urlNavigator->setLocationUrl(newUrl); } - const QString destFileName = dest.fileName(); - if (ok) { - m_statusBar->setMessage(i18n("Renamed file '%1' to '%2'.", source.fileName(), destFileName), - DolphinStatusBar::OperationCompleted); +#if HAVE_KACTIVITIES + m_activityResourceInstance->setUri(newUrl); +#endif +} - KonqOperations::rename(this, source, destFileName); +void DolphinViewContainer::setFilterBarVisible(bool visible) +{ + Q_ASSERT(m_filterBar); + if (visible) { + m_view->hideToolTip(ToolTipManager::HideBehavior::Instantly); + m_filterBar->show(); + m_filterBar->setFocus(); + m_filterBar->selectAll(); } else { - m_statusBar->setMessage(i18n("Renaming of file '%1' to '%2' failed.", source.fileName(), destFileName), - DolphinStatusBar::Error); + closeFilterBar(); } } -DolphinMainWindow* DolphinViewContainer::mainWindow() const +void DolphinViewContainer::delayedStatusBarUpdate() { - return m_mainWindow; + if (m_statusBarTimer->isActive() && (m_statusBarTimestamp.elapsed() > 2000)) { + // No update of the statusbar has been done during the last 2 seconds, + // although an update has been requested. Trigger an immediate update. + m_statusBarTimer->stop(); + updateStatusBar(); + } else { + // Invoke updateStatusBar() with a small delay. This assures that + // when a lot of delayedStatusBarUpdates() are done in a short time, + // no bottleneck is given. + m_statusBarTimer->start(); + } +} + +void DolphinViewContainer::updateStatusBar() +{ + m_statusBarTimestamp.start(); + m_view->requestStatusBarText(); +} + +void DolphinViewContainer::updateDirectoryLoadingProgress(int percent) +{ + if (m_statusBar->progressText().isEmpty()) { + m_statusBar->setProgressText(i18nc("@info:progress", "Loading folder…")); + } + m_statusBar->setProgress(percent); } -void DolphinViewContainer::updateProgress(int percent) +void DolphinViewContainer::updateDirectorySortingProgress(int percent) { - if (m_showProgress) { - m_statusBar->setProgress(percent); + if (m_statusBar->progressText().isEmpty()) { + m_statusBar->setProgressText(i18nc("@info:progress", "Sorting…")); } + m_statusBar->setProgress(percent); } -void DolphinViewContainer::updateItemCount() +void DolphinViewContainer::slotDirectoryLoadingStarted() { - if (m_showProgress) { + if (isSearchUrl(url())) { + // Search KIO-slaves usually don't provide any progress information. Give + // a hint to the user that a searching is done: + updateStatusBar(); + m_statusBar->setProgressText(i18nc("@info", "Searching…")); + m_statusBar->setProgress(-1); + } else { + // Trigger an undetermined progress indication. The progress + // information in percent will be triggered by the percent() signal + // of the directory lister later. + m_statusBar->setProgressText(QString()); + updateDirectoryLoadingProgress(-1); + } +} + +void DolphinViewContainer::slotDirectoryLoadingCompleted() +{ + if (!m_statusBar->progressText().isEmpty()) { + m_statusBar->setProgressText(QString()); + m_statusBar->setProgress(100); + } + + if (isSearchUrl(url()) && m_view->itemsCount() == 0) { + // The dir lister has been completed on a Baloo-URI and no items have been found. Instead + // of showing the default status bar information ("0 items") a more helpful information is given: + m_statusBar->setText(i18nc("@info:status", "No items found.")); + } else { + updateStatusBar(); + } +} + +void DolphinViewContainer::slotDirectoryLoadingCanceled() +{ + if (!m_statusBar->progressText().isEmpty()) { m_statusBar->setProgressText(QString()); m_statusBar->setProgress(100); - m_showProgress = false; } - KFileItemList items(m_dirLister->items()); - KFileItemList::const_iterator it = items.begin(); - const KFileItemList::const_iterator end = items.end(); + m_statusBar->setText(QString()); +} - m_fileCount = 0; - m_folderCount = 0; +void DolphinViewContainer::slotUrlIsFileError(const QUrl &url) +{ + const KFileItem item(url); + + // Find out if the file can be opened in the view (for example, this is the + // case if the file is an archive). The mime type must be known for that. + item.determineMimeType(); + const QUrl &folderUrl = DolphinView::openItemAsFolderUrl(item, true); + if (!folderUrl.isEmpty()) { + setUrl(folderUrl); + } else { + slotItemActivated(item); + } +} - while (it != end) { - KFileItem* item = *it; - if (item->isDir()) { - ++m_folderCount; +void DolphinViewContainer::slotItemActivated(const KFileItem &item) +{ + // It is possible to activate items on inactive views by + // drag & drop operations. Assure that activating an item always + // results in an active view. + m_view->setActive(true); + + const QUrl &url = DolphinView::openItemAsFolderUrl(item, GeneralSettings::browseThroughArchives()); + if (!url.isEmpty()) { + const auto modifiers = QGuiApplication::keyboardModifiers(); + // keep in sync with KUrlNavigator::slotNavigatorButtonClicked + if (modifiers & Qt::ControlModifier && modifiers & Qt::ShiftModifier) { + Q_EMIT activeTabRequested(url); + } else if (modifiers & Qt::ControlModifier) { + Q_EMIT tabRequested(url); + } else if (modifiers & Qt::ShiftModifier) { + Dolphin::openNewWindow({KFilePlacesModel::convertedUrl(url)}, this); } else { - ++m_fileCount; + setUrl(url); } - ++it; + return; } - updateStatusBar(); + KIO::OpenUrlJob *job = new KIO::OpenUrlJob(item.targetUrl(), item.mimetype()); + // Auto*Warning*Handling, errors are put in a KMessageWidget by us in slotOpenUrlFinished. + job->setUiDelegate(KIO::createDefaultJobUiDelegate(KJobUiDelegate::AutoWarningHandlingEnabled, this)); + job->setShowOpenOrExecuteDialog(true); + connect(job, &KIO::OpenUrlJob::finished, this, &DolphinViewContainer::slotOpenUrlFinished); + job->start(); +} + +void DolphinViewContainer::slotfileMiddleClickActivated(const KFileItem &item) +{ + KService::List services = KApplicationTrader::queryByMimeType(item.mimetype()); - QTimer::singleShot(0, this, SLOT(restoreContentsPos())); + int indexOfAppToOpenFileWith = 1; + + // executable scripts + auto mimeType = item.currentMimeType(); + if (item.isLocalFile() && mimeType.inherits(QStringLiteral("application/x-executable")) && mimeType.inherits(QStringLiteral("text/plain")) + && QFileInfo(item.localPath()).isExecutable()) { + KConfigGroup cfgGroup(KSharedConfig::openConfig(QStringLiteral("kiorc")), "Executable scripts"); + const QString value = cfgGroup.readEntry("behaviourOnLaunch", "alwaysAsk"); + + // in case KIO::WidgetsOpenOrExecuteFileHandler::promptUserOpenOrExecute would not open the file + if (value != QLatin1String("open")) { + indexOfAppToOpenFileWith = 0; + } + } + + if (services.length() >= indexOfAppToOpenFileWith + 1) { + auto service = services.at(indexOfAppToOpenFileWith); + + KIO::ApplicationLauncherJob *job = new KIO::ApplicationLauncherJob(service, this); + job->setUrls({item.url()}); + + job->setUiDelegate(KIO::createDefaultJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, this)); + connect(job, &KIO::OpenUrlJob::finished, this, &DolphinViewContainer::slotOpenUrlFinished); + job->start(); + } } -void DolphinViewContainer::showInfoMessage(const QString& msg) +void DolphinViewContainer::slotItemsActivated(const KFileItemList &items) { - m_statusBar->setMessage(msg, DolphinStatusBar::Information); + Q_ASSERT(items.count() >= 2); + + KFileItemActions fileItemActions(this); + fileItemActions.runPreferredApplications(items); } -void DolphinViewContainer::showErrorMessage(const QString& msg) +void DolphinViewContainer::showItemInfo(const KFileItem &item) { - m_statusBar->setMessage(msg, DolphinStatusBar::Error); + if (item.isNull()) { + m_statusBar->resetToDefaultText(); + } else { + m_statusBar->setText(item.getStatusBarInfo()); + } } void DolphinViewContainer::closeFilterBar() { - m_filterBar->hide(); - emit showFilterBarChanged(false); + m_filterBar->closeFilterBar(); + m_view->setFocus(); + Q_EMIT showFilterBarChanged(false); } -QString DolphinViewContainer::defaultStatusBarText() const +void DolphinViewContainer::clearFilterBar() { - return KIO::itemsSummaryString(m_fileCount + m_folderCount, - m_fileCount, - m_folderCount, - 0, false); + m_filterBar->clearIfUnlocked(); } -QString DolphinViewContainer::selectionStatusBarText() const +void DolphinViewContainer::setNameFilter(const QString &nameFilter) { - QString text; - const KFileItemList list = m_view->selectedItems(); - if (list.isEmpty()) { - // when an item is triggered, it is temporary selected but selectedItems() - // will return an empty list - return QString(); - } - - int fileCount = 0; - int folderCount = 0; - KIO::filesize_t byteSize = 0; - KFileItemList::const_iterator it = list.begin(); - const KFileItemList::const_iterator end = list.end(); - while (it != end) { - KFileItem* item = *it; - if (item->isDir()) { - ++folderCount; + m_view->hideToolTip(ToolTipManager::HideBehavior::Instantly); + m_view->setNameFilter(nameFilter); + delayedStatusBarUpdate(); +} + +void DolphinViewContainer::activate() +{ + setActive(true); +} + +void DolphinViewContainer::slotUrlNavigatorLocationAboutToBeChanged(const QUrl &) +{ + saveViewState(); +} + +void DolphinViewContainer::slotUrlNavigatorLocationChanged(const QUrl &url) +{ + if (m_urlNavigatorConnected) { + m_urlNavigatorConnected->slotReturnPressed(); + } + + if (KProtocolManager::supportsListing(url)) { + const bool searchBoxInitialized = isSearchModeEnabled() && m_searchBox->text().isEmpty(); + setSearchModeEnabled(isSearchUrl(url) || searchBoxInitialized); + + m_view->setUrl(url); + tryRestoreViewState(); + + if (m_autoGrabFocus && isActive() && !isSearchModeEnabled()) { + // When an URL has been entered, the view should get the focus. + // The focus must be requested asynchronously, as changing the URL might create + // a new view widget. + QTimer::singleShot(0, this, &DolphinViewContainer::requestFocus); + } + } else if (KProtocolManager::isSourceProtocol(url)) { + if (url.scheme().startsWith(QLatin1String("http"))) { + showMessage(i18nc("@info:status", // krazy:exclude=qmethods + "Dolphin does not support web pages, the web browser has been launched"), + Information); } else { - ++fileCount; - byteSize += item->size(); + showMessage(i18nc("@info:status", "Protocol not supported by Dolphin, default application has been launched"), Information); } - ++it; - } - if (folderCount > 0) { - text = i18np("1 Folder selected", "%1 Folders selected", folderCount); - if (fileCount > 0) { - text += ", "; + QDesktopServices::openUrl(url); + redirect(QUrl(), m_urlNavigator->locationUrl(1)); + } else { + if (!url.scheme().isEmpty()) { + showMessage(i18nc("@info:status", "Invalid protocol '%1'", url.scheme()), Error); + } else { + showMessage(i18nc("@info:status", "Invalid protocol"), Error); } + m_urlNavigator->goBack(); } +} + +void DolphinViewContainer::slotUrlSelectionRequested(const QUrl &url) +{ + m_view->markUrlsAsSelected({url}); + m_view->markUrlAsCurrent(url); // makes the item scroll into view +} - if (fileCount > 0) { - const QString sizeText(KIO::convertSize(byteSize)); - text += i18np("1 File selected (%2)", "%1 Files selected (%2)", fileCount, sizeText); +void DolphinViewContainer::disableUrlNavigatorSelectionRequests() +{ + disconnect(m_urlNavigator.get(), &KUrlNavigator::urlSelectionRequested, this, &DolphinViewContainer::slotUrlSelectionRequested); +} + +void DolphinViewContainer::enableUrlNavigatorSelectionRequests() +{ + connect(m_urlNavigator.get(), &KUrlNavigator::urlSelectionRequested, this, &DolphinViewContainer::slotUrlSelectionRequested); +} + +void DolphinViewContainer::redirect(const QUrl &oldUrl, const QUrl &newUrl) +{ + Q_UNUSED(oldUrl) + const bool block = m_urlNavigator->signalsBlocked(); + m_urlNavigator->blockSignals(true); + + // Assure that the location state is reset for redirection URLs. This + // allows to skip redirection URLs when going back or forward in the + // URL history. + m_urlNavigator->saveLocationState(QByteArray()); + m_urlNavigator->setLocationUrl(newUrl); + setSearchModeEnabled(isSearchUrl(newUrl)); + + m_urlNavigator->blockSignals(block); +} + +void DolphinViewContainer::requestFocus() +{ + m_view->setFocus(); +} + +void DolphinViewContainer::startSearching() +{ + Q_CHECK_PTR(m_urlNavigatorConnected); + const QUrl url = m_searchBox->urlForSearching(); + if (url.isValid() && !url.isEmpty()) { + m_view->setViewPropertiesContext(QStringLiteral("search")); + m_urlNavigatorConnected->setLocationUrl(url); } +} - return text; +void DolphinViewContainer::openSearchBox() +{ + setSearchModeEnabled(true); } -void DolphinViewContainer::showFilterBar(bool show) +void DolphinViewContainer::closeSearchBox() { - Q_ASSERT(m_filterBar != 0); - m_filterBar->setVisible(show); + setSearchModeEnabled(false); } -void DolphinViewContainer::updateStatusBar() +void DolphinViewContainer::stopDirectoryLoading() { - // As the item count information is less important - // in comparison with other messages, it should only - // be shown if: - // - the status bar is empty or - // - shows already the item count information or - // - shows only a not very important information - // - if any progress is given don't show the item count info at all - const QString msg(m_statusBar->message()); - const bool updateStatusBarMsg = (msg.isEmpty() || - (msg == m_statusBar->defaultText()) || - (m_statusBar->type() == DolphinStatusBar::Information)) && - (m_statusBar->progress() == 100); - - const QString text(m_view->hasSelection() ? selectionStatusBarText() : defaultStatusBarText()); - m_statusBar->setDefaultText(text); - - if (updateStatusBarMsg) { - m_statusBar->setMessage(text, DolphinStatusBar::Default); - } -} - -void DolphinViewContainer::changeNameFilter(const QString& nameFilter) -{ - // The name filter of KDirLister does a 'hard' filtering, which - // means that only the items are shown where the names match - // exactly the filter. This is non-transparent for the user, which - // just wants to have a 'soft' filtering: does the name contain - // the filter string? - QString adjustedFilter(nameFilter); - adjustedFilter.insert(0, '*'); - adjustedFilter.append('*'); - - // Use the ProxyModel to filter: - // This code is #ifdefed as setNameFilter behaves - // slightly different than the QSortFilterProxyModel - // as it will not remove directories. I will ask - // our beloved usability experts for input - // -- z. -#if 0 - m_dirLister->setNameFilter(adjustedFilter); - m_dirLister->emitChanges(); -#else - m_proxyModel->setFilterRegExp(nameFilter); -#endif + m_view->stopLoading(); + m_statusBar->setProgress(100); +} + +void DolphinViewContainer::slotStatusBarZoomLevelChanged(int zoomLevel) +{ + m_view->setZoomLevel(zoomLevel); +} + +void DolphinViewContainer::showErrorMessage(const QString &msg) +{ + showMessage(msg, Error); } -void DolphinViewContainer::openContextMenu(KFileItem* item, - const KUrl& url) +void DolphinViewContainer::slotPlacesModelChanged() { - DolphinContextMenu contextMenu(m_mainWindow, item, url); - contextMenu.open(); + if (!GeneralSettings::showFullPathInTitlebar() && !isSearchModeEnabled()) { + Q_EMIT captionChanged(); + } +} + +void DolphinViewContainer::slotHiddenFilesShownChanged(bool showHiddenFiles) +{ + if (m_urlNavigatorConnected) { + m_urlNavigatorConnected->setShowHiddenFolders(showHiddenFiles); + } +} + +void DolphinViewContainer::slotSortHiddenLastChanged(bool hiddenLast) +{ + if (m_urlNavigatorConnected) { + m_urlNavigatorConnected->setSortHiddenFoldersLast(hiddenLast); + } +} + +void DolphinViewContainer::slotCurrentDirectoryRemoved() +{ + const QString location(url().toDisplayString(QUrl::PreferLocalFile)); + if (url().isLocalFile()) { + const QString dirPath = url().toLocalFile(); + const QString newPath = getNearestExistingAncestorOfPath(dirPath); + const QUrl newUrl = QUrl::fromLocalFile(newPath); + setUrl(newUrl); + } + + showMessage(xi18n("Current location changed, %1 is no longer accessible.", location), Warning); +} + +void DolphinViewContainer::slotOpenUrlFinished(KJob *job) +{ + if (job->error() && job->error() != KIO::ERR_USER_CANCELED) { + showErrorMessage(job->errorString()); + } +} + +bool DolphinViewContainer::isSearchUrl(const QUrl &url) const +{ + return url.scheme().contains(QLatin1String("search")); +} + +void DolphinViewContainer::saveViewState() +{ + QByteArray locationState; + QDataStream stream(&locationState, QIODevice::WriteOnly); + m_view->saveState(stream); + m_urlNavigator->saveLocationState(locationState); +} + +void DolphinViewContainer::tryRestoreViewState() +{ + QByteArray locationState = m_urlNavigator->locationState(); + if (!locationState.isEmpty()) { + QDataStream stream(&locationState, QIODevice::ReadOnly); + m_view->restoreState(stream); + } +} + +QString DolphinViewContainer::getNearestExistingAncestorOfPath(const QString &path) const +{ + QDir dir(path); + do { + dir.setPath(QDir::cleanPath(dir.filePath(QStringLiteral("..")))); + } while (!dir.exists() && !dir.isRoot()); + + return dir.exists() ? dir.path() : QString{}; } -#include "dolphinviewcontainer.moc" +#include "moc_dolphinviewcontainer.cpp"