TextWidgets
Notifications
Crash
+ WindowSystem
)
find_package(KF5 ${KF5_MIN_VERSION} OPTIONAL_COMPONENTS
Activities
KF5::ConfigCore
KF5::NewStuff
KF5::Parts
+ KF5::WindowSystem
)
if(HAVE_BALOO)
#include "dbusinterface.h"
#include "global.h"
+#include "dolphin_generalsettings.h"
#include <KPropertiesDialog>
+#include <QApplication>
#include <QDBusConnection>
+#include <QDBusInterface>
#include <QDBusConnectionInterface>
DBusInterface::DBusInterface() :
if (urls.isEmpty()) {
return;
}
- Dolphin::openNewWindow(urls);
+ const auto serviceName = QStringLiteral("org.kde.dolphin-%1").arg(QCoreApplication::applicationPid());
+ if(!Dolphin::attachToExistingInstance(urls, false, GeneralSettings::splitView(), serviceName)) {
+ Dolphin::openNewWindow(urls);
+ }
}
void DBusInterface::ShowItems(const QStringList& uriList, const QString& startUpId)
if (urls.isEmpty()) {
return;
}
- Dolphin::openNewWindow(urls, nullptr, Dolphin::OpenNewWindowFlag::Select);
+ const auto serviceName = QStringLiteral("org.kde.dolphin-%1").arg(QCoreApplication::applicationPid());
+ if(!Dolphin::attachToExistingInstance(urls, true, GeneralSettings::splitView(), serviceName)) {
+ Dolphin::openNewWindow(urls);
+ };
}
void DBusInterface::ShowItemProperties(const QStringList& uriList, const QString& startUpId)
#include <KRun>
#include <KShell>
#include <KStandardAction>
+#include <KStartupInfo>
#include <KToggleAction>
#include <KToolBar>
#include <KToolInvocation>
#include <KUrlComboBox>
#include <KUrlNavigator>
+#include <KWindowSystem>
#include <QApplication>
#include <QClipboard>
m_tabWidget->openDirectories(dirs, splitView);
}
+void DolphinMainWindow::openDirectories(const QStringList& dirs, bool splitView)
+{
+ openDirectories(QUrl::fromStringList(dirs), splitView);
+}
+
void DolphinMainWindow::openFiles(const QList<QUrl>& files, bool splitView)
{
m_tabWidget->openFiles(files, splitView);
}
+void DolphinMainWindow::openFiles(const QStringList& files, bool splitView)
+{
+ openFiles(QUrl::fromStringList(files), splitView);
+}
+
+void DolphinMainWindow::activateWindow()
+{
+ KStartupInfo::setNewStartupId(window(), KStartupInfo::startupId());
+ KWindowSystem::activateWindow(window()->effectiveWinId());
+}
+
void DolphinMainWindow::showCommand(CommandType command)
{
DolphinStatusBar* statusBar = m_activeViewContainer->statusBar();
}
}
+bool DolphinMainWindow::isUrlOpen(const QString& url)
+{
+ if (m_tabWidget->getIndexByUrl(QUrl::fromUserInput((url))) >= 0) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
void setTabsToHomeIfMountPathOpen(const QString& mountPath);
public slots:
+ /**
+ * Opens each directory in \p dirs in a separate tab. If \a splitView is set,
+ * 2 directories are collected within one tab.
+ * \pre \a dirs must contain at least one url.
+ *
+ * @note this function is overloaded so that it is callable via DBus.
+ */
+ void openDirectories(const QStringList &dirs, bool splitView);
+
+ /**
+ * Opens the directories which contain the files \p files and selects all files.
+ * If \a splitView is set, 2 directories are collected within one tab.
+ * \pre \a files must contain at least one url.
+ *
+ * @note this is overloaded so that this function is callable via DBus.
+ */
+ void openFiles(const QStringList &files, bool splitView);
+
+ /**
+ * Tries to raise/activate the Dolphin window.
+ */
+ void activateWindow();
+
+ /**
+ * Determines if a URL is open in any tab.
+ * @note Use of QString instead of QUrl is required to be callable via DBus.
+ *
+ * @param url URL to look for
+ * @returns true if url is currently open in a tab, false otherwise.
+ */
+ bool isUrlOpen(const QString &url);
+
+
/**
* Pastes the clipboard data into the currently selected folder
* of the active view. If not exactly one folder is selected,
QList<QUrl>::const_iterator it = dirs.constBegin();
while (it != dirs.constEnd()) {
const QUrl& primaryUrl = *(it++);
+ const int index = getIndexByUrl(primaryUrl);
+ if (index >= 0) {
+ setCurrentIndex(index);
+ continue;
+ }
if (splitView && (it != dirs.constEnd())) {
const QUrl& secondaryUrl = *(it++);
- openNewTab(primaryUrl, secondaryUrl);
+ openNewActivatedTab(primaryUrl, secondaryUrl);
} else {
- openNewTab(primaryUrl);
+ openNewActivatedTab(primaryUrl);
}
}
}
args << tabPage->secondaryViewContainer()->url().url();
args << QStringLiteral("--split");
}
+ args << QStringLiteral("--new-window");
const QString command = QStringLiteral("dolphin %1").arg(KShell::joinArgs(args));
KRun::runCommand(command, this);
// and not misinterpreted as a keyboard shortcut in QTabBar::setTabText()
return name.replace('&', QLatin1String("&&"));
}
+
+int DolphinTabWidget::getIndexByUrl(const QUrl& url) const
+{
+ for (int i = 0; i < count(); i++) {
+ // Conversion to display string is necessary to deal with the '~' alias.
+ // i.e. to acknowledge that ~/ is equivalent to /home/user/
+ const QUrl tabUrl = tabPageAt(i)->activeViewContainer()->url();
+ if (url == tabUrl ||
+ url.toDisplayString(QUrl::StripTrailingSlash) == tabUrl.toDisplayString(QUrl::StripTrailingSlash)) {
+ return i;
+ }
+ }
+ return -1;
+}
*/
void refreshViews();
+ /**
+ * @param url The URL that we would like
+ * @return index of the tab with the desired URL. returns -1 if not found
+ */
+ int getIndexByUrl(const QUrl& url) const;
+
signals:
/**
* Is emitted when the active view has been changed, by changing the current
#include "dolphindebug.h"
#include <KRun>
+#include <KWindowSystem>
#include <QApplication>
#include <QIcon>
+#include <QDBusInterface>
+#include <QDBusConnectionInterface>
QList<QUrl> Dolphin::validateUris(const QStringList& uriList)
{
void Dolphin::openNewWindow(const QList<QUrl> &urls, QWidget *window, const OpenNewWindowFlags &flags)
{
- QString command = QStringLiteral("dolphin");
+ QString command = QStringLiteral("dolphin --new-window");
if (flags.testFlag(OpenNewWindowFlag::Select)) {
command.append(QLatin1String(" --select"));
if (!urls.isEmpty()) {
command.append(QLatin1String(" %U"));
}
+ KRun::run(
+ command,
+ urls,
+ window,
+ QApplication::applicationDisplayName(),
+ QApplication::windowIcon().name()
+ );
+}
+
+bool Dolphin::attachToExistingInstance(const QList<QUrl>& urls, bool openFiles, bool splitView, const QString& preferredService)
+{
+ if (KWindowSystem::isPlatformWayland()) {
+ // TODO: once Wayland clients can raise or activate themselves remove this conditional
+ return false;
+ }
+
+ const QStringList services = QDBusConnection::sessionBus().interface()->registeredServiceNames().value();
+
+ // Don't match the service without trailing "-" (unique instance)
+ const QString pattern = QStringLiteral("org.kde.dolphin-");
+ const QString myPid = QString::number(QCoreApplication::applicationPid());
+ QVector<QPair<QSharedPointer<QDBusInterface>, QStringList>> dolphinServices;
+ if (!preferredService.isEmpty()) {
+ QSharedPointer<QDBusInterface> preferred(
+ new QDBusInterface(preferredService,
+ QStringLiteral("/dolphin/Dolphin_1"),
+ QStringLiteral("org.kde.dolphin.MainWindow"))
+ );
+ if (preferred->isValid()) {
+ dolphinServices.append(qMakePair(preferred, QStringList() ));
+ }
+ }
+
+ // find all dolphin instances
+ for (const QString& service : services) {
+ if (service.startsWith(pattern) && !service.endsWith(myPid)) {
+ // Check if instance can handle our URLs
+ QSharedPointer<QDBusInterface> instance(
+ new QDBusInterface(service,
+ QStringLiteral("/dolphin/Dolphin_1"),
+ QStringLiteral("org.kde.dolphin.MainWindow"))
+ );
+ if (!instance->isValid()) {
+ continue;
+ }
+ dolphinServices.append(qMakePair(instance, QStringList()));
+ }
+ }
+
+ if (dolphinServices.isEmpty()) {
+ return false;
+ }
+
+ QStringList newUrls;
+
+ // check to see if any instances already have any of the given URLs open
+ for (const QString& url : QUrl::toStringList(urls)) {
+ bool urlFound = false;
+ for (auto& service: dolphinServices) {
+ QDBusReply<bool> isUrlOpen = service.first->call(QStringLiteral("isUrlOpen"), url);
+ if (isUrlOpen.isValid() && isUrlOpen.value()) {
+ service.second.append(url);
+ urlFound = true;
+ break;
+ }
+ }
+ if (!urlFound) {
+ newUrls.append(url);
+ }
+ }
+ dolphinServices.front().second << newUrls;
- KRun::run(command, urls, window, qApp->applicationDisplayName(), qApp->windowIcon().name());
+ for (const auto& service: dolphinServices) {
+ if (!service.second.isEmpty()) {
+ service.first->call(openFiles ? QStringLiteral("openFiles") : QStringLiteral("openDirectories"), service.second, splitView);
+ service.first->call(QStringLiteral("activateWindow"));
+ }
+ }
+ return true;
}
*/
void openNewWindow(const QList<QUrl> &urls = {}, QWidget *window = nullptr, const OpenNewWindowFlags &flags = OpenNewWindowFlag::None);
+ /**
+ * Attaches URLs to an existing Dolphin instance if possible.
+ * Returns true if URLs were successfully attached
+ */
+ bool attachToExistingInstance(const QList<QUrl>& urls, bool openFiles, bool splitView, const QString& preferredService = QString());
+
/**
* TODO: Move this somewhere global to all KDE apps, not just Dolphin
*/
#include <QApplication>
#include <QCommandLineParser>
+#include <QDBusConnection>
+#include <QDBusInterface>
+#include <QDBusAbstractInterface>
+#include <QDBusConnectionInterface>
#ifndef Q_OS_WIN
#include <unistd.h>
parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("select"), i18nc("@info:shell", "The files and folders passed as arguments "
"will be selected.")));
parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("split"), i18nc("@info:shell", "Dolphin will get started with a split view.")));
+ parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("new-window"), i18nc("@info:shell", "Dolphin will explicitly open in a new window.")));
parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("daemon"), i18nc("@info:shell", "Start Dolphin Daemon (only required for DBus Interface)")));
parser.addPositionalArgument(QStringLiteral("+[Url]"), i18nc("@info:shell", "Document to open"));
parser.process(app);
aboutData.processCommandLine(&parser);
+ const bool splitView = parser.isSet(QStringLiteral("split")) || GeneralSettings::splitView();
+ const bool openFiles = parser.isSet(QStringLiteral("select"));
+ const QStringList args = parser.positionalArguments();
+ QList<QUrl> urls = Dolphin::validateUris(args);
+
if (parser.isSet(QStringLiteral("daemon"))) {
return app.exec();
}
- const QStringList args = parser.positionalArguments();
- QList<QUrl> urls = Dolphin::validateUris(args);
-
if (urls.isEmpty()) {
// We need at least one URL to open Dolphin
urls.append(Dolphin::homeUrl());
}
- const bool splitView = parser.isSet(QStringLiteral("split")) || GeneralSettings::splitView();
if (splitView && urls.size() < 2) {
// Split view does only make sense if we have at least 2 URLs
urls.append(urls.last());
}
+ if (!parser.isSet(QStringLiteral("new-window"))) {
+ if (Dolphin::attachToExistingInstance(urls, openFiles, splitView)) {
+ // Successfully attached to existing instance of Dolphin
+ return 0;
+ }
+ }
+
DolphinMainWindow* mainWindow = new DolphinMainWindow();
- if (parser.isSet(QStringLiteral("select"))) {
+ if (openFiles) {
mainWindow->openFiles(urls, splitView);
} else {
mainWindow->openDirectories(urls, splitView);