X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/blobdiff_plain/63f4981fe01d88b2ef1b27e0577d7f5d4c8cc485..afba1fd4f3a79cb17d58f1330813624ab057e24f:/src/dolphinviewcontainer.cpp diff --git a/src/dolphinviewcontainer.cpp b/src/dolphinviewcontainer.cpp index 0fe8ee9d3..a38833481 100644 --- a/src/dolphinviewcontainer.cpp +++ b/src/dolphinviewcontainer.cpp @@ -12,33 +12,47 @@ #include "filterbar/filterbar.h" #include "global.h" #include "search/dolphinsearchbox.h" +#include "selectionmode/topbar.h" #include "statusbar/dolphinstatusbar.h" -#include "views/viewmodecontroller.h" -#include "views/viewproperties.h" #include "dolphin_detailsmodesettings.h" -#ifdef HAVE_KACTIVITIES +#include +#if HAVE_KACTIVITIES #include #endif #include #include -#include -#include +#include +#if KIO_VERSION >= QT_VERSION_CHECK(5, 98, 0) +#include +#else #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), @@ -48,19 +62,21 @@ DolphinViewContainer::DolphinViewContainer(const QUrl& url, QWidget* parent) : 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) -#ifdef HAVE_KACTIVITIES +#if HAVE_KACTIVITIES , m_activityResourceInstance(nullptr) #endif { hide(); - m_topLayout = new QVBoxLayout(this); + m_topLayout = new QGridLayout(this); m_topLayout->setSpacing(0); m_topLayout->setContentsMargins(0, 0, 0, 0); @@ -118,6 +134,10 @@ DolphinViewContainer::DolphinViewContainer(const QUrl& url, QWidget* parent) : 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, @@ -148,6 +168,12 @@ DolphinViewContainer::DolphinViewContainer(const QUrl& url, QWidget* parent) : 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); @@ -161,6 +187,10 @@ DolphinViewContainer::DolphinViewContainer(const QUrl& url, QWidget* parent) : 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, @@ -175,23 +205,34 @@ DolphinViewContainer::DolphinViewContainer(const QUrl& url, QWidget* parent) : connect(undoManager, &KIO::FileUndoManager::jobRecordingFinished, this, &DolphinViewContainer::delayedStatusBarUpdate); - m_topLayout->addWidget(m_searchBox); - m_topLayout->addWidget(m_messageWidget); - m_topLayout->addWidget(m_view); - m_topLayout->addWidget(m_filterBar); - m_topLayout->addWidget(m_statusBar); + 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)); connect(DetailsModeSettings::self(), &KCoreConfigSkeleton::configChanged, this, [=]() { - if (view()->mode() == DolphinView::Mode::DetailsView) { + if (view()->viewMode() == DolphinView::Mode::DetailsView) { view()->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 -#ifdef HAVE_KACTIVITIES +#if HAVE_KACTIVITIES m_activityResourceInstance = new KActivities::ResourceInstance(window()->winId(), url); m_activityResourceInstance->setParent(this); #endif @@ -214,7 +255,7 @@ void DolphinViewContainer::setActive(bool active) } m_view->setActive(active); -#ifdef HAVE_KACTIVITIES +#if HAVE_KACTIVITIES if (active) { m_activityResourceInstance->notifyFocusedIn(); } else { @@ -291,26 +332,26 @@ void DolphinViewContainer::connectUrlNavigator(DolphinUrlNavigator *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()); - connect(m_view, &DolphinView::urlChanged, - urlNavigator, &DolphinUrlNavigator::setLocationUrl); + // Url changes are still done via m_urlNavigator. connect(urlNavigator, &DolphinUrlNavigator::urlChanged, - this, &DolphinViewContainer::slotUrlNavigatorLocationChanged); - connect(urlNavigator, &DolphinUrlNavigator::activated, - this, &DolphinViewContainer::activate); - connect(urlNavigator, &DolphinUrlNavigator::urlAboutToBeChanged, - this, &DolphinViewContainer::slotUrlNavigatorLocationAboutToBeChanged); - connect(urlNavigator, &DolphinUrlNavigator::urlSelectionRequested, - this, &DolphinViewContainer::slotUrlSelectionRequested); + 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; } @@ -321,23 +362,97 @@ void DolphinViewContainer::disconnectUrlNavigator() 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::urlChanged, - this, &DolphinViewContainer::slotUrlNavigatorLocationChanged); disconnect(m_urlNavigatorConnected, &DolphinUrlNavigator::activated, this, &DolphinViewContainer::activate); - disconnect(m_urlNavigatorConnected, &DolphinUrlNavigator::urlAboutToBeChanged, - this, &DolphinViewContainer::slotUrlNavigatorLocationAboutToBeChanged); - disconnect(m_urlNavigatorConnected, &DolphinUrlNavigator::urlSelectionRequested, - this, &DolphinViewContainer::slotUrlSelectionRequested); - disconnect(m_urlNavigatorConnected, &DolphinUrlNavigator::urlsDropped, - this, nullptr); 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 + } + Q_CHECK_PTR(m_selectionModeTopBar); // there is no point in disabling selectionMode when it wasn't even enabled once. + Q_CHECK_PTR(m_selectionModeBottomBar); + m_selectionModeTopBar->setVisible(false, WithAnimation); + m_selectionModeBottomBar->setVisible(false, WithAnimation); + Q_EMIT selectionModeChanged(false); + return; + } + + 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()) { @@ -392,7 +507,7 @@ void DolphinViewContainer::setSearchModeEnabled(bool enabled) m_searchBox->setVisible(enabled); if (enabled) { - const QUrl& locationUrl = m_urlNavigatorConnected->locationUrl(); + const QUrl& locationUrl = m_urlNavigator->locationUrl(); m_searchBox->fromSearchUrl(locationUrl); } @@ -474,7 +589,8 @@ QString DolphinViewContainer::caption() const } KFilePlacesModel *placesModel = DolphinPlacesModelSingleton::instance().placesModel(); - const auto& matchedPlaces = placesModel->match(placesModel->index(0,0), KFilePlacesModel::UrlRole, QUrl(url().adjusted(QUrl::StripTrailingSlash).toString(QUrl::FullyEncoded).append("/?")), 1, Qt::MatchRegExp); + 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()); @@ -510,7 +626,7 @@ void DolphinViewContainer::setUrl(const QUrl& newUrl) m_urlNavigator->setLocationUrl(newUrl); } -#ifdef HAVE_KACTIVITIES +#if HAVE_KACTIVITIES m_activityResourceInstance->setUri(newUrl); #endif } @@ -546,10 +662,7 @@ void DolphinViewContainer::delayedStatusBarUpdate() void DolphinViewContainer::updateStatusBar() { m_statusBarTimestamp.start(); - - const QString text = m_view->statusBarText(); - m_statusBar->setDefaultText(text); - m_statusBar->resetToDefaultText(); + m_view->requestStatusBarText(); } void DolphinViewContainer::updateDirectoryLoadingProgress(int percent) @@ -626,7 +739,7 @@ void DolphinViewContainer::slotUrlIsFileError(const QUrl& url) } } -void DolphinViewContainer::slotItemActivated(const KFileItem& 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 @@ -635,13 +748,28 @@ void DolphinViewContainer::slotItemActivated(const KFileItem& item) const QUrl& url = DolphinView::openItemAsFolderUrl(item, GeneralSettings::browseThroughArchives()); if (!url.isEmpty()) { - setUrl(url); + 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 { + setUrl(url); + } return; } - KIO::OpenUrlJob *job = new KIO::OpenUrlJob(item.targetUrl()); + KIO::OpenUrlJob *job = new KIO::OpenUrlJob(item.targetUrl(), item.mimetype()); +#if KIO_VERSION >= QT_VERSION_CHECK(5, 98, 0) + job->setUiDelegate(KIO::createDefaultJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, this)); +#else job->setUiDelegate(new KIO::JobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, this)); +#endif job->setShowOpenOrExecuteDialog(true); + connect(job, &KIO::OpenUrlJob::finished, this, &DolphinViewContainer::slotOpenUrlFinished); job->start(); } @@ -650,7 +778,7 @@ void DolphinViewContainer::slotItemsActivated(const KFileItemList& items) Q_ASSERT(items.count() >= 2); KFileItemActions fileItemActions(this); - fileItemActions.runPreferredApplications(items, QString()); + fileItemActions.runPreferredApplications(items); } void DolphinViewContainer::showItemInfo(const KFileItem& item) @@ -728,6 +856,18 @@ void DolphinViewContainer::slotUrlSelectionRequested(const QUrl& 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) @@ -780,6 +920,47 @@ 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")); @@ -801,3 +982,14 @@ void DolphinViewContainer::tryRestoreViewState() 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{}; +}