X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/blobdiff_plain/3bf8fa5901f200d26acc2eb527eef88087e6edb9..1826f905d706925456763394de17294bcb6d1c35:/src/dolphinviewcontainer.cpp diff --git a/src/dolphinviewcontainer.cpp b/src/dolphinviewcontainer.cpp index 5194646f6..076551e5d 100644 --- a/src/dolphinviewcontainer.cpp +++ b/src/dolphinviewcontainer.cpp @@ -1,260 +1,465 @@ -/*************************************************************************** - * 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 "dolphinmodel.h" -#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 "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) : - 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_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); - - m_urlNavigator = new KUrlNavigator(DolphinSettings::instance().placesModel(), url, this); - connect(m_urlNavigator, SIGNAL(urlsDropped(const KUrl::List&, const KUrl&)), - m_mainWindow, SLOT(dropUrls(const KUrl::List&, const KUrl&))); - connect(m_urlNavigator, SIGNAL(activated()), - this, SLOT(activate())); - - 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->setDelayedMimeTypes(true); - - m_dolphinModel = new DolphinModel(); - m_dolphinModel->setDirLister(m_dirLister); - m_dolphinModel->setDropsAllowed(DolphinModel::DropOnDirectory); - - - m_proxyModel = new DolphinSortFilterProxyModel(this); - m_proxyModel->setSourceModel(m_dolphinModel); - - 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(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_dolphinModel, - m_proxyModel); - 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_view, SIGNAL(contentsMoved(int, int)), - this, SLOT(saveContentsPos(int, int))); - connect(m_view, SIGNAL(requestItemInfo(KFileItem)), - this, SLOT(showItemInfo(KFileItem))); - connect(m_view, SIGNAL(errorMessage(const QString&)), - this, SLOT(showErrorMessage(const QString&))); - connect(m_view, SIGNAL(infoMessage(const QString&)), - this, SLOT(showInfoMessage(const QString&))); - connect(m_view, SIGNAL(itemTriggered(KFileItem)), - this, SLOT(slotItemTriggered(KFileItem))); - connect(m_view, SIGNAL(startedPathLoading(const KUrl&)), - this, SLOT(saveRootUrl(const KUrl&))); - - connect(m_urlNavigator, SIGNAL(urlChanged(const KUrl&)), - this, SLOT(restoreView(const KUrl&))); - - m_statusBar = new DolphinStatusBar(this, url); - connect(m_view, SIGNAL(urlChanged(const KUrl&)), - m_statusBar, SLOT(updateSpaceInfoContent(const KUrl&))); + 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 QList items = m_view->selectedItems(); - if (items.count() > 1) { - // More than one item has been selected for renaming. Open - // a rename dialog and rename all items afterwards. - RenameDialog dialog(items); - 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; - - QList::const_iterator it = items.begin(); - QList::const_iterator end = items.end(); - while (it != end) { - const KUrl& oldUrl = (*it).url(); - 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(items.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(items); - 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 = items.first().url(); - 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); + } +} + +bool DolphinViewContainer::isSelectionModeEnabled() const +{ + 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; +} + +void DolphinViewContainer::slotSplitTabDisabled() +{ + if (m_selectionModeBottomBar) { + m_selectionModeBottomBar->slotSplitTabDisabled(); + } +} + +void DolphinViewContainer::showMessage(const QString &msg, MessageType type) +{ + 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(); +} + +void DolphinViewContainer::readSettings() +{ + // 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 @@ -262,230 +467,339 @@ bool DolphinViewContainer::isFilterBarVisible() const return m_filterBar->isVisible(); } -bool DolphinViewContainer::isUrlEditable() const +void DolphinViewContainer::setSearchModeEnabled(bool enabled) { - return m_urlNavigator->isUrlEditable(); + m_searchBox->setVisible(enabled); + + if (enabled) { + const QUrl &locationUrl = m_urlNavigator->locationUrl(); + m_searchBox->fromSearchUrl(locationUrl); + } + + if (enabled == isSearchModeEnabled()) { + if (enabled && !m_searchBox->hasFocus()) { + m_searchBox->setFocus(); + m_searchBox->selectAll(); + } + return; + } + + 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; + + Q_EMIT searchModeEnabledChanged(enabled); } -KFileItem DolphinViewContainer::fileItem(const QModelIndex& index) const +bool DolphinViewContainer::isSearchModeEnabled() const { - const QModelIndex dolphinModelIndex = m_proxyModel->mapToSource(index); - return m_dolphinModel->itemForIndex(dolphinModelIndex); + return m_searchModeEnabled; } -void DolphinViewContainer::updateProgress(int percent) +QString DolphinViewContainer::placesText() const { - if (!m_showProgress) { - // Only show the directory loading progress if the status bar does - // not contain another progress information. This means that - // the directory loading progress information has the lowest priority. - const QString progressText(m_statusBar->progressText()); - const QString loadingText(i18nc("@info:progress", "Loading folder...")); - m_showProgress = progressText.isEmpty() || (progressText == loadingText); - if (m_showProgress) { - m_statusBar->setProgressText(loadingText); - m_statusBar->setProgress(0); + 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(); } } - if (m_showProgress) { - m_statusBar->setProgress(percent); + 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 { + return DolphinViewContainer::caption(); } } -void DolphinViewContainer::updateItemCount() +QString DolphinViewContainer::caption() const { - if (m_showProgress) { - m_statusBar->setProgressText(QString()); - m_statusBar->setProgress(100); - m_showProgress = false; + if (isSearchModeEnabled()) { + if (currentSearchText().isEmpty()) { + return i18n("Search"); + } else { + return i18n("Search for %1", currentSearchText()); + } } - KFileItemList items(m_dirLister->items()); - KFileItemList::const_iterator it = items.begin(); - const KFileItemList::const_iterator end = items.end(); + 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); - m_fileCount = 0; - m_folderCount = 0; + if (!matchedPlaces.isEmpty()) { + return placesModel->text(matchedPlaces.first()); + } - while (it != end) { - KFileItem* item = *it; - if (item->isDir()) { - ++m_folderCount; + 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 { - ++m_fileCount; + caption = adjustedUrl.toString(); } - ++it; + return caption; } - updateStatusBar(); + QString fileName = url().adjusted(QUrl::StripTrailingSlash).fileName(); + if (fileName.isEmpty()) { + fileName = '/'; + } - QTimer::singleShot(100, this, SLOT(restoreContentsPos())); + return fileName; } -void DolphinViewContainer::showItemInfo(const KFileItem& item) +void DolphinViewContainer::setUrl(const QUrl &newUrl) { - if (item.isNull()) { - m_statusBar->clear(); + if (newUrl != m_urlNavigator->locationUrl()) { + m_urlNavigator->setLocationUrl(newUrl); + } + +#if HAVE_KACTIVITIES + m_activityResourceInstance->setUri(newUrl); +#endif +} + +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 { + closeFilterBar(); + } +} + +void DolphinViewContainer::delayedStatusBarUpdate() +{ + 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 { - m_statusBar->setMessage(item.getStatusBarInfo(), DolphinStatusBar::Default); + // 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::showInfoMessage(const QString& msg) +void DolphinViewContainer::updateStatusBar() { - m_statusBar->setMessage(msg, DolphinStatusBar::Information); + m_statusBarTimestamp.start(); + m_view->requestStatusBarText(); } -void DolphinViewContainer::showErrorMessage(const QString& msg) +void DolphinViewContainer::updateDirectoryLoadingProgress(int percent) { - m_statusBar->setMessage(msg, DolphinStatusBar::Error); + if (m_statusBar->progressText().isEmpty()) { + m_statusBar->setProgressText(i18nc("@info:progress", "Loading folder…")); + } + m_statusBar->setProgress(percent); } -void DolphinViewContainer::closeFilterBar() +void DolphinViewContainer::updateDirectorySortingProgress(int percent) { - m_filterBar->hide(); - emit showFilterBarChanged(false); + if (m_statusBar->progressText().isEmpty()) { + m_statusBar->setProgressText(i18nc("@info:progress", "Sorting…")); + } + m_statusBar->setProgress(percent); } -QString DolphinViewContainer::defaultStatusBarText() const +void DolphinViewContainer::slotDirectoryLoadingStarted() { - int m_fileCount = 0; - int m_folderCount = 0; + 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); + } +} - for (int i = 0; i < m_proxyModel->rowCount(); i++) - { - if (m_dolphinModel->itemForIndex(m_proxyModel->mapToSource(m_proxyModel->index(i, m_proxyModel->sortColumn()))).isDir()) - { - m_folderCount++; - } - else - { - m_fileCount++; - } +void DolphinViewContainer::slotDirectoryLoadingCompleted() +{ + if (!m_statusBar->progressText().isEmpty()) { + m_statusBar->setProgressText(QString()); + m_statusBar->setProgress(100); } - return KIO::itemsSummaryString(m_fileCount + m_folderCount, - m_fileCount, - m_folderCount, - 0, false); + 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(); + } } -QString DolphinViewContainer::selectionStatusBarText() const +void DolphinViewContainer::slotDirectoryLoadingCanceled() { - QString text; - const QList 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; - QList::const_iterator it = list.begin(); - const QList::const_iterator end = list.end(); - while (it != end) { - const KFileItem& item = *it; - if (item.isDir()) { - ++folderCount; + if (!m_statusBar->progressText().isEmpty()) { + m_statusBar->setProgressText(QString()); + m_statusBar->setProgress(100); + } + + m_statusBar->setText(QString()); +} + +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); + } +} + +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 { - ++fileCount; - byteSize += item.size(); + setUrl(url); } - ++it; + return; } - if (folderCount > 0) { - text = i18ncp("@info:status", "1 Folder selected", "%1 Folders selected", folderCount); - if (fileCount > 0) { - text += ", "; + 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()); + + 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 (fileCount > 0) { - const QString sizeText(KIO::convertSize(byteSize)); - text += i18ncp("@info:status", "1 File selected (%2)", "%1 Files selected (%2)", fileCount, sizeText); - } + if (services.length() >= indexOfAppToOpenFileWith + 1) { + auto service = services.at(indexOfAppToOpenFileWith); - return text; + 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::showFilterBar(bool show) +void DolphinViewContainer::slotItemsActivated(const KFileItemList &items) { - Q_ASSERT(m_filterBar != 0); - m_filterBar->setVisible(show); + Q_ASSERT(items.count() >= 2); + + KFileItemActions fileItemActions(this); + fileItemActions.runPreferredApplications(items); } -void DolphinViewContainer::updateStatusBar() +void DolphinViewContainer::showItemInfo(const KFileItem &item) { - // 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 - - updateStatusBar(); + if (item.isNull()) { + m_statusBar->resetToDefaultText(); + } else { + m_statusBar->setText(item.getStatusBarInfo()); + } } -void DolphinViewContainer::openContextMenu(const KFileItem& item, - const KUrl& url) +void DolphinViewContainer::closeFilterBar() { - DolphinContextMenu contextMenu(m_mainWindow, item, url); - contextMenu.open(); + m_filterBar->closeFilterBar(); + m_view->setFocus(); + Q_EMIT showFilterBarChanged(false); } -void DolphinViewContainer::saveContentsPos(int x, int y) +void DolphinViewContainer::clearFilterBar() { - m_urlNavigator->savePosition(x, y); + m_filterBar->clearIfUnlocked(); } -void DolphinViewContainer::restoreContentsPos() +void DolphinViewContainer::setNameFilter(const QString &nameFilter) { - if (!url().isEmpty()) { - const QPoint pos = m_urlNavigator->savedPosition(); - m_view->setContentsPosition(pos.x(), pos.y()); - } + m_view->hideToolTip(ToolTipManager::HideBehavior::Instantly); + m_view->setNameFilter(nameFilter); + delayedStatusBarUpdate(); } void DolphinViewContainer::activate() @@ -493,44 +807,195 @@ void DolphinViewContainer::activate() setActive(true); } -void DolphinViewContainer::restoreView(const KUrl& url) +void DolphinViewContainer::slotUrlNavigatorLocationAboutToBeChanged(const QUrl &) { - m_view->updateView(url, m_urlNavigator->savedRootUrl()); + saveViewState(); } -void DolphinViewContainer::saveRootUrl(const KUrl& url) +void DolphinViewContainer::slotUrlNavigatorLocationChanged(const QUrl &url) { - Q_UNUSED(url); - m_urlNavigator->saveRootUrl(m_view->rootUrl()); -} + if (m_urlNavigatorConnected) { + m_urlNavigatorConnected->slotReturnPressed(); + } -void DolphinViewContainer::slotItemTriggered(const KFileItem& item) -{ - // Prefer the local path over the URL. - bool isLocal; - KUrl url = item.mostLocalUrl(isLocal); + if (KProtocolManager::supportsListing(url)) { + const bool searchBoxInitialized = isSearchModeEnabled() && m_searchBox->text().isEmpty(); + setSearchModeEnabled(isSearchUrl(url) || searchBoxInitialized); - if (item.isDir()) { m_view->setUrl(url); - } else if (item.isFile()) { - // allow to browse through ZIP and tar files - KMimeType::Ptr mime = item.mimeTypePtr(); - if (mime->is("application/zip")) { - url.setProtocol("zip"); - m_view->setUrl(url); - } else if (mime->is("application/x-tar") || - mime->is("application/x-tarz") || - mime->is("application/x-bzip-compressed-tar") || - mime->is("application/x-compressed-tar") || - mime->is("application/x-tzo")) { - url.setProtocol("tar"); - 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 { - item.run(); + showMessage(i18nc("@info:status", "Protocol not supported by Dolphin, default application has been launched"), Information); } + + QDesktopServices::openUrl(url); + redirect(QUrl(), m_urlNavigator->locationUrl(1)); } else { - item.run(); + 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(); } } -#include "dolphinviewcontainer.moc" +void DolphinViewContainer::slotUrlSelectionRequested(const QUrl &url) +{ + m_view->markUrlsAsSelected({url}); + m_view->markUrlAsCurrent(url); // makes the item scroll into view +} + +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); + } +} + +void DolphinViewContainer::openSearchBox() +{ + setSearchModeEnabled(true); +} + +void DolphinViewContainer::closeSearchBox() +{ + setSearchModeEnabled(false); +} + +void DolphinViewContainer::stopDirectoryLoading() +{ + 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::slotPlacesModelChanged() +{ + 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 "moc_dolphinviewcontainer.cpp"