Enable Ctrl/Shift-Click to open folder in a new tab/window

and more
This commit is contained in:
Alessio Bonfiglio 2021-12-17 14:11:46 +00:00 committed by Méven Car
parent 3c5bf0c96c
commit 65b18bf935
12 changed files with 182 additions and 52 deletions

View file

@ -445,6 +445,16 @@ void DolphinMainWindow::openNewTab(const QUrl& url)
m_tabWidget->openNewTab(url, QUrl());
}
void DolphinMainWindow::openNewTabAndActivate(const QUrl &url)
{
m_tabWidget->openNewActivatedTab(url, QUrl());
}
void DolphinMainWindow::openNewWindow(const QUrl &url)
{
Dolphin::openNewWindow({url}, this);
}
void DolphinMainWindow::slotSplitViewChanged()
{
m_tabWidget->currentTabPage()->setSplitViewEnabled(GeneralSettings::splitView(), WithAnimation);
@ -1859,8 +1869,10 @@ void DolphinMainWindow::setupDockWidgets()
foldersPanel, &FoldersPanel::setUrl);
connect(foldersPanel, &FoldersPanel::folderActivated,
this, &DolphinMainWindow::changeUrl);
connect(foldersPanel, &FoldersPanel::folderMiddleClicked,
connect(foldersPanel, &FoldersPanel::folderInNewTab,
this, &DolphinMainWindow::openNewTab);
connect(foldersPanel, &FoldersPanel::folderInNewActiveTab,
this, &DolphinMainWindow::openNewTabAndActivate);
connect(foldersPanel, &FoldersPanel::errorMessage,
this, &DolphinMainWindow::showErrorMessage);
@ -1942,8 +1954,10 @@ void DolphinMainWindow::setupDockWidgets()
addDockWidget(Qt::LeftDockWidgetArea, placesDock);
connect(m_placesPanel, &PlacesPanel::placeActivated,
this, &DolphinMainWindow::slotPlaceActivated);
connect(m_placesPanel, &PlacesPanel::placeMiddleClicked,
connect(m_placesPanel, &PlacesPanel::placeActivatedInNewTab,
this, &DolphinMainWindow::openNewTab);
connect(m_placesPanel, &PlacesPanel::placeActivatedInNewActiveTab,
this, &DolphinMainWindow::openNewTabAndActivate);
connect(m_placesPanel, &PlacesPanel::errorMessage,
this, &DolphinMainWindow::showErrorMessage);
connect(this, &DolphinMainWindow::urlChanged,
@ -2134,6 +2148,10 @@ void DolphinMainWindow::connectViewSignals(DolphinViewContainer* container)
this, &DolphinMainWindow::updateSearchAction);
connect(container, &DolphinViewContainer::captionChanged,
this, &DolphinMainWindow::updateWindowTitle);
connect(container, &DolphinViewContainer::tabRequested,
this, &DolphinMainWindow::openNewTab);
connect(container, &DolphinViewContainer::activeTabRequested,
this, &DolphinMainWindow::openNewTabAndActivate);
const QAction* toggleSearchAction = actionCollection()->action(QStringLiteral("toggle_search"));
connect(toggleSearchAction, &QAction::triggered, container, &DolphinViewContainer::setSearchModeEnabled);
@ -2147,6 +2165,10 @@ void DolphinMainWindow::connectViewSignals(DolphinViewContainer* container)
this, &DolphinMainWindow::fileItemsChanged);
connect(view, &DolphinView::tabRequested,
this, &DolphinMainWindow::openNewTab);
connect(view, &DolphinView::activeTabRequested,
this, &DolphinMainWindow::openNewTabAndActivate);
connect(view, &DolphinView::windowRequested,
this, &DolphinMainWindow::openNewWindow);
connect(view, &DolphinView::requestContextMenu,
this, &DolphinMainWindow::openContextMenu);
connect(view, &DolphinView::directoryLoadingStarted,
@ -2181,6 +2203,10 @@ void DolphinMainWindow::connectViewSignals(DolphinViewContainer* container)
this, &DolphinMainWindow::slotEditableStateChanged);
connect(navigator, &KUrlNavigator::tabRequested,
this, &DolphinMainWindow::openNewTab);
connect(navigator, &KUrlNavigator::activeTabRequested,
this, &DolphinMainWindow::openNewTabAndActivate);
connect(navigator, &KUrlNavigator::newWindowRequested,
this, &DolphinMainWindow::openNewWindow);
}

View file

@ -171,6 +171,16 @@ public Q_SLOTS:
*/
void openNewTab(const QUrl& url);
/**
* Opens a new tab showing the URL \a url and activate it.
*/
void openNewTabAndActivate(const QUrl &url);
/**
* Opens a new window showing the URL \a url.
*/
void openNewWindow(const QUrl &url);
/** @see GeneralSettings::splitViewChanged() */
void slotSplitViewChanged();

View file

@ -32,6 +32,7 @@
#include <KUrlComboBox>
#include <QDropEvent>
#include <QGuiApplication>
#include <QLoggingCategory>
#include <QMimeData>
#include <QTimer>
@ -642,7 +643,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
@ -651,7 +652,17 @@ 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;
}

View file

@ -229,6 +229,16 @@ Q_SIGNALS:
*/
void captionChanged();
/**
* Is emitted if a new tab should be opened in the background for the URL \a url.
*/
void tabRequested(const QUrl &url);
/**
* Is emitted if a new tab should be opened for the URL \a url and set as active.
*/
void activeTabRequested(const QUrl &url);
private Q_SLOTS:
/**
* Updates the number of items (= number of files + number of
@ -281,7 +291,7 @@ private Q_SLOTS:
* directory is opened in the view. If the item is a file, the file
* gets started by the corresponding application.
*/
void slotItemActivated(const KFileItem& item);
void slotItemActivated(const KFileItem &item);
/**
* Handles activation of multiple files. The files get started by

View file

@ -1583,14 +1583,10 @@ bool KItemListController::onRelease(const QPointF& pos, const Qt::KeyboardModifi
Q_EMIT itemExpansionToggleClicked(index);
emitItemActivated = false;
} else if (shiftOrControlPressed) {
// The mouse click should only update the selection, not trigger the item
} else if (shiftOrControlPressed && m_selectionBehavior != SingleSelection) {
// The mouse click should only update the selection, not trigger the item, except when
// we are in single selection mode
emitItemActivated = false;
// When Ctrl-clicking an item when in single selection mode
// i.e. where Ctrl won't change the selection, pretend it was middle clicked
if (controlPressed && m_selectionBehavior == SingleSelection) {
Q_EMIT itemMiddleClicked(index);
}
} else if (!(m_view->style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick) || m_singleClickActivationEnforced)) {
if (touch) {
emitItemActivated = true;

View file

@ -137,7 +137,7 @@ Q_SIGNALS:
* Is emitted if more than one item has been activated by pressing Return/Enter
* when having a selection.
*/
void itemsActivated(const KItemSet& indexes);
void itemsActivated(const KItemSet &indexes);
void itemMiddleClicked(int index);

View file

@ -189,7 +189,19 @@ void FoldersPanel::slotItemActivated(int index)
{
const KFileItem item = m_model->fileItem(index);
if (!item.isNull()) {
Q_EMIT folderActivated(item.url());
const auto modifiers = QGuiApplication::keyboardModifiers();
// keep in sync with KUrlNavigator::slotNavigatorButtonClicked
if (modifiers & Qt::ControlModifier && modifiers & Qt::ShiftModifier) {
Q_EMIT folderInNewActiveTab(item.url());
} else if (modifiers & Qt::ControlModifier) {
Q_EMIT folderInNewTab(item.url());
} else if (modifiers & Qt::ShiftModifier) {
// The shift modifier is not considered because it is used to expand the tree view without actually
// opening the folder
return;
} else {
Q_EMIT folderActivated(item.url());
}
}
}
@ -197,7 +209,13 @@ void FoldersPanel::slotItemMiddleClicked(int index)
{
const KFileItem item = m_model->fileItem(index);
if (!item.isNull()) {
Q_EMIT folderMiddleClicked(item.url());
const auto modifiers = QGuiApplication::keyboardModifiers();
// keep in sync with KUrlNavigator::slotNavigatorButtonClicked
if (modifiers & Qt::ShiftModifier) {
Q_EMIT folderInNewActiveTab(item.url());
} else {
Q_EMIT folderInNewTab(item.url());
}
}
}

View file

@ -42,7 +42,8 @@ public:
Q_SIGNALS:
void folderActivated(const QUrl& url);
void folderMiddleClicked(const QUrl& url);
void folderInNewTab(const QUrl &url);
void folderInNewActiveTab(const QUrl &url);
void errorMessage(const QString& error);
protected:

View file

@ -36,6 +36,7 @@
#include <KPropertiesDialog>
#include <QActionGroup>
#include <QApplication>
#include <QGraphicsSceneDragDropEvent>
#include <QIcon>
#include <QMenu>
@ -44,16 +45,16 @@
#include <QToolTip>
PlacesPanel::PlacesPanel(QWidget* parent) :
Panel(parent),
m_controller(nullptr),
m_model(nullptr),
m_view(nullptr),
m_storageSetupFailedUrl(),
m_triggerStorageSetupButton(),
m_itemDropEventIndex(-1),
m_itemDropEventMimeData(nullptr),
m_itemDropEvent(nullptr),
m_tooltipTimer()
Panel(parent),
m_controller(nullptr),
m_model(nullptr),
m_view(nullptr),
m_storageSetupFailedUrl(),
m_triggerStorageSetupModifier(),
m_itemDropEventIndex(-1),
m_itemDropEventMimeData(nullptr),
m_itemDropEvent(nullptr),
m_tooltipTimer()
{
m_tooltipTimer.setInterval(500);
m_tooltipTimer.setSingleShot(true);
@ -163,12 +164,28 @@ bool PlacesPanel::eventFilter(QObject * /* obj */, QEvent *event)
void PlacesPanel::slotItemActivated(int index)
{
triggerItem(index, Qt::LeftButton);
const auto modifiers = QGuiApplication::keyboardModifiers();
// keep in sync with KUrlNavigator::slotNavigatorButtonClicked
if (modifiers & Qt::ControlModifier && modifiers & Qt::ShiftModifier) {
triggerItem(index, TriggerItemModifier::ToNewActiveTab);
} else if (modifiers & Qt::ControlModifier) {
triggerItem(index, TriggerItemModifier::ToNewTab);
} else if (modifiers & Qt::ShiftModifier) {
triggerItem(index, TriggerItemModifier::ToNewWindow);
} else {
triggerItem(index, TriggerItemModifier::None);
}
}
void PlacesPanel::slotItemMiddleClicked(int index)
{
triggerItem(index, Qt::MiddleButton);
const auto modifiers = QGuiApplication::keyboardModifiers();
// keep in sync with KUrlNavigator::slotNavigatorButtonClicked
if (modifiers & Qt::ShiftModifier) {
triggerItem(index, TriggerItemModifier::ToNewActiveTab);
} else {
triggerItem(index, TriggerItemModifier::ToNewTab);
}
}
void PlacesPanel::slotItemContextMenuRequested(int index, const QPointF& pos)
@ -287,9 +304,7 @@ void PlacesPanel::slotItemContextMenuRequested(int index, const QPointF& pos)
} else if (action == openInNewWindowAction) {
Dolphin::openNewWindow({KFilePlacesModel::convertedUrl(m_model->data(index).value("url").toUrl())}, this);
} else if (action == openInNewTabAction) {
// TriggerItem does set up the storage first and then it will
// emit the slotItemMiddleClicked signal, because of Qt::MiddleButton.
triggerItem(index, Qt::MiddleButton);
triggerItem(index, TriggerItemModifier::ToNewTab);
} else if (action == mountAction) {
m_model->requestStorageSetup(index);
} else if (action == teardownAction) {
@ -480,14 +495,14 @@ void PlacesPanel::slotStorageSetupDone(int index, bool success)
disconnect(m_model, &PlacesItemModel::storageSetupDone,
this, &PlacesPanel::slotStorageSetupDone);
if (m_triggerStorageSetupButton == Qt::NoButton) {
if (m_triggerStorageSetupModifier == TriggerItemModifier::None) {
return;
}
if (success) {
Q_ASSERT(!m_model->storageSetupNeeded(index));
triggerItem(index, m_triggerStorageSetupButton);
m_triggerStorageSetupButton = Qt::NoButton;
triggerItem(index, m_triggerStorageSetupModifier);
m_triggerStorageSetupModifier = TriggerItemModifier::None;
} else {
setUrl(m_storageSetupFailedUrl);
m_storageSetupFailedUrl = QUrl();
@ -553,7 +568,7 @@ void PlacesPanel::selectItem()
}
}
void PlacesPanel::triggerItem(int index, Qt::MouseButton button)
void PlacesPanel::triggerItem(int index, TriggerItemModifier modifier)
{
const PlacesItem* item = m_model->placesItem(index);
if (!item) {
@ -561,7 +576,7 @@ void PlacesPanel::triggerItem(int index, Qt::MouseButton button)
}
if (m_model->storageSetupNeeded(index)) {
m_triggerStorageSetupButton = button;
m_triggerStorageSetupModifier = modifier;
m_storageSetupFailedUrl = url();
connect(m_model, &PlacesItemModel::storageSetupDone,
@ -569,14 +584,23 @@ void PlacesPanel::triggerItem(int index, Qt::MouseButton button)
m_model->requestStorageSetup(index);
} else {
m_triggerStorageSetupButton = Qt::NoButton;
m_triggerStorageSetupModifier = TriggerItemModifier::None;
const QUrl url = m_model->data(index).value("url").toUrl();
if (!url.isEmpty()) {
if (button == Qt::MiddleButton) {
Q_EMIT placeMiddleClicked(KFilePlacesModel::convertedUrl(url));
} else {
Q_EMIT placeActivated(KFilePlacesModel::convertedUrl(url));
switch (modifier) {
case TriggerItemModifier::ToNewTab:
Q_EMIT placeActivatedInNewTab(KFilePlacesModel::convertedUrl(url));
break;
case TriggerItemModifier::ToNewActiveTab:
Q_EMIT placeActivatedInNewActiveTab(KFilePlacesModel::convertedUrl(url));
break;
case TriggerItemModifier::ToNewWindow:
Dolphin::openNewWindow({KFilePlacesModel::convertedUrl(url)}, this);
break;
case TriggerItemModifier::None:
Q_EMIT placeActivated(KFilePlacesModel::convertedUrl(url));
break;
}
}
}

View file

@ -35,7 +35,8 @@ public:
Q_SIGNALS:
void placeActivated(const QUrl& url);
void placeMiddleClicked(const QUrl& url);
void placeActivatedInNewTab(const QUrl &url);
void placeActivatedInNewActiveTab(const QUrl &url);
void errorMessage(const QString& error);
void storageTearDownRequested(const QString& mountPath);
void storageTearDownExternallyRequested(const QString& mountPath);
@ -63,6 +64,9 @@ private Q_SLOTS:
void slotStorageSetupDone(int index, bool success);
void slotShowTooltip();
private:
enum class TriggerItemModifier { None, ToNewTab, ToNewActiveTab, ToNewWindow };
private:
void addEntry();
void editEntry(int index);
@ -73,7 +77,7 @@ private:
*/
void selectItem();
void triggerItem(int index, Qt::MouseButton button);
void triggerItem(int index, TriggerItemModifier modifier);
QAction* buildGroupContextMenu(QMenu* menu, int index);
@ -83,7 +87,7 @@ private:
PlacesView* m_view;
QUrl m_storageSetupFailedUrl;
Qt::MouseButton m_triggerStorageSetupButton;
TriggerItemModifier m_triggerStorageSetupModifier;
int m_itemDropEventIndex;
QMimeData* m_itemDropEventMimeData;

View file

@ -974,12 +974,14 @@ void DolphinView::slotItemActivated(int index)
}
}
void DolphinView::slotItemsActivated(const KItemSet& indexes)
void DolphinView::slotItemsActivated(const KItemSet &indexes)
{
Q_ASSERT(indexes.count() >= 2);
abortTwoClicksRenaming();
const auto modifiers = QGuiApplication::keyboardModifiers();
if (indexes.count() > 5) {
QString question = i18np("Are you sure you want to open 1 item?", "Are you sure you want to open %1 items?", indexes.count());
const int answer = KMessageBox::warningYesNo(this, question);
@ -995,8 +997,15 @@ void DolphinView::slotItemsActivated(const KItemSet& indexes)
KFileItem item = m_model->fileItem(index);
const QUrl& url = openItemAsFolderUrl(item);
if (!url.isEmpty()) { // Open folders in new tabs
Q_EMIT tabRequested(url);
if (!url.isEmpty()) {
// Open folders in new tabs or in new windows depending on the modifier
// The ctrl+shift behavior is ignored because we are handling multiple items
// keep in sync with KUrlNavigator::slotNavigatorButtonClicked
if (modifiers & Qt::ShiftModifier && !(modifiers & Qt::ControlModifier)) {
Q_EMIT windowRequested(url);
} else {
Q_EMIT tabRequested(url);
}
} else {
items.append(item);
}
@ -1013,10 +1022,21 @@ void DolphinView::slotItemMiddleClicked(int index)
{
const KFileItem& item = m_model->fileItem(index);
const QUrl& url = openItemAsFolderUrl(item);
const auto modifiers = QGuiApplication::keyboardModifiers();
if (!url.isEmpty()) {
Q_EMIT tabRequested(url);
// keep in sync with KUrlNavigator::slotNavigatorButtonClicked
if (modifiers & Qt::ShiftModifier) {
Q_EMIT activeTabRequested(url);
} else {
Q_EMIT tabRequested(url);
}
} else if (isTabsForFilesEnabled()) {
Q_EMIT tabRequested(item.url());
// keep in sync with KUrlNavigator::slotNavigatorButtonClicked
if (modifiers & Qt::ShiftModifier) {
Q_EMIT activeTabRequested(item.url());
} else {
Q_EMIT tabRequested(item.url());
}
}
}

View file

@ -425,13 +425,13 @@ Q_SIGNALS:
/**
* Is emitted when clicking on an item with the left mouse button.
*/
void itemActivated(const KFileItem& item);
void itemActivated(const KFileItem &item);
/**
* Is emitted when multiple items have been activated by e. g.
* context menu open with.
*/
void itemsActivated(const KFileItemList& items);
void itemsActivated(const KFileItemList &items);
/**
* Is emitted if items have been added or deleted.
@ -443,6 +443,16 @@ Q_SIGNALS:
*/
void tabRequested(const QUrl& url);
/**
* Is emitted if a new tab should be opened for the URL \a url and set as active.
*/
void activeTabRequested(const QUrl &url);
/**
* Is emitted if a new window should be opened for the URL \a url.
*/
void windowRequested(const QUrl &url);
/**
* Is emitted if the view mode (IconsView, DetailsView,
* PreviewsView) has been changed.
@ -619,7 +629,7 @@ private Q_SLOTS:
void activate();
void slotItemActivated(int index);
void slotItemsActivated(const KItemSet& indexes);
void slotItemsActivated(const KItemSet &indexes);
void slotItemMiddleClicked(int index);
void slotItemContextMenuRequested(int index, const QPointF& pos);
void slotViewContextMenuRequested(const QPointF& pos);