From 462e220c64e7a686372226ecae88120995a04fc0 Mon Sep 17 00:00:00 2001 From: David Korth Date: Sun, 5 Jan 2025 14:42:03 -0500 Subject: [PATCH] [kde] stub-export.cpp: Use KPropertiesDialog instead of creating a dialog manually. Using KPropertiesDialog causes KDE to find all of the plugins itself, so it'll load XAttrView. I tried using QPluginLoader, which mostly worked, but it crashed when trying to add itself to the KPropertiesDialog, since we were using a plain old QDialog. Creating a KPropertiesDialog instead makes the QPluginLoader (and manual RomDataView creation) unnecessary, since KDE does it for us. NOTE: Removing other tabs causes random segfaults, so we can't remove tabs from other plugins. Instead, set the first ROM Properties tab as the current tab. For setting the initial URL, we use QUrl::fromUserInput() to convert the specified filename to a QUrl. For Qt versions older than 5.4, we have to handle the current working directory manually. --- src/kde/config/stub-export.cpp | 124 ++++++++++++++------------------- 1 file changed, 53 insertions(+), 71 deletions(-) diff --git a/src/kde/config/stub-export.cpp b/src/kde/config/stub-export.cpp index 8b8997529..c9dc068a8 100644 --- a/src/kde/config/stub-export.cpp +++ b/src/kde/config/stub-export.cpp @@ -2,7 +2,7 @@ * ROM Properties Page shell extension. (KDE) * * stub-export.cpp: Exported function for the rp-config stub. * * * - * Copyright (c) 2016-2022 by David Korth. * + * Copyright (c) 2016-2025 by David Korth. * * SPDX-License-Identifier: GPL-2.0-or-later * ***************************************************************************/ @@ -33,9 +33,15 @@ using namespace LibRpTexture; # include "../GettextTranslator.hpp" #endif -// KCrash +// Qt +#include "RpQt.hpp" + +// KDE #include #include +#include +#include +#include // C++ STL classes using std::string; @@ -199,87 +205,63 @@ Q_DECL_EXPORT int RP_C_API rp_show_RomDataView_dialog(int argc, char *argv[]) AchQtDBus::instance(); #endif /* ENABLE_ACHIEVEMENTS && HAVE_QtDBus_NOTIFY */ - // Create a QDialog. - QDialog *const dialog = new QDialog(nullptr, - Qt::Dialog | - Qt::CustomizeWindowHint | - Qt::WindowTitleHint | - Qt::WindowSystemMenuHint | - Qt::WindowMinimizeButtonHint | - Qt::WindowCloseButtonHint); - dialog->setObjectName(QLatin1String("dialog")); - dialog->show(); - - // TODO: Verify on Qt4. -#if QT_VERSION < QT_VERSION_CHECK(5,0,0) - dialog->setWindowTitle(applicationDisplayName); -#endif /* QT_VERSION < QT_VERSION_CHECK(5,0,0) */ - dialog->setWindowFilePath(QString::fromUtf8(uri)); - - // Create a QVBoxLayout for the dialog. - QVBoxLayout *const vboxDialog = new QVBoxLayout(dialog); - vboxDialog->setObjectName(QLatin1String("vboxDialog")); - - // Create a QTabWidget to simulate KDE Dolphin. - QTabWidget *const tabWidget = new QTabWidget(dialog); - tabWidget->setObjectName(QLatin1String("tabWidget")); - vboxDialog->addWidget(tabWidget); - - // Create a button box for the standard buttons. (and RomDataView's "Options" button) - QDialogButtonBox *const buttonBox = new QDialogButtonBox(dialog); - buttonBox->setObjectName(QLatin1String("buttonBox")); - buttonBox->setOrientation(Qt::Horizontal); - buttonBox->setStandardButtons(QDialogButtonBox::Apply | QDialogButtonBox::Cancel | QDialogButtonBox::Ok); - vboxDialog->addWidget(buttonBox); - QObject::connect(buttonBox, SIGNAL(accepted()), dialog, SLOT(accept())); - QObject::connect(buttonBox, SIGNAL(rejected()), dialog, SLOT(reject())); - // Parse the specified URI and localize it. - QUrl localUrl(QString::fromUtf8(uri)); + const QString qs_uri(QString::fromUtf8(uri)); +#if QT_VERSION >= QT_VERSION_CHECK(5,4,0) + const QUrl localUrl(QUrl::fromUserInput(qs_uri, QDir::current().absolutePath())); +#else /* QT_VERSION < QT_VERSION_CHECK(5,4,0) */ + // QUrl::fromUserInput()'s workingDirectory parameter was added in Qt 5.4. + // For older versions, we'll have to check the CWD ourselves. + const QFileInfo fileInfo(QDir::current(), qs_uri); + const QUrl localUrl = (fileInfo.exists()) + ? QUrl::fromLocalFile(fileInfo.absoluteFilePath()) + : QUrl::fromUserInput(qs_uri); +#endif /* QT_VERSION >= QT_VERSION_CHECK(5,4,0) */ if (localUrl.isEmpty()) { fprintf(stderr, "*** " RP_KDE_UPPER " rp_show_RomDataView_dialog(): URI '%s' is invalid.\n", uri); return EXIT_FAILURE; } fprintf(stderr, "*** " RP_KDE_UPPER " rp_show_RomDataView_dialog(): Opening URI: '%s'\n", uri); - // Get the local filename. - string s_local_filename; - if (localUrl.scheme().isEmpty()) { - s_local_filename = localUrl.path().toUtf8().constData(); - } else if (localUrl.isLocalFile()) { - s_local_filename = localUrl.toLocalFile().toUtf8().constData(); - } + // Create a KPropertiesDialog. + // FIXME: Remove the default "General" and "Permissions" tabs. + // NOTE: Assuming we have a valid URL, KDE will automatically load + // the rom-properties KPropertiesDialogPlugins. + KPropertiesDialog *const dialog = new KPropertiesDialog(localUrl); + dialog->setObjectName(QLatin1String("propertiesDialog")); + dialog->show(); - // Open a RomData object. - RomDataPtr romData; - if (likely(!s_local_filename.empty())) { - romData = RomDataFactory::create(s_local_filename.c_str()); - if (romData) { - // Create a RomDataView object. - RomDataView *const romDataView = new RomDataView(romData, dialog); - romDataView->setObjectName(QLatin1String("romDataView")); - tabWidget->addTab(romDataView, QLatin1String("ROM Properties")); + // Set the current tab to one of our tabs (whichever shows up first). + // FIXME: Removing tabs causes random SIGSEGV... + bool hasPlugins = false; + KPageWidget *const kpw = findDirectChild(dialog); + if (kpw) { + // Remove tabs that aren't for our plugins. + // TODO + KPageWidgetModel *const model = findDirectChild(kpw); + + // Assuming a single "column". + assert(model->columnCount() == 1); + const int rowCount = model->rowCount(); + for (int row = 0; row < rowCount; row++) { + KPageWidgetItem *const item = model->item(model->index(row, 0)); + QWidget *const widget = item->widget(); + const char *const className = widget->metaObject()->className(); + + if (!strcmp(className, "RomDataView") || + !strcmp(className, "XAttrView")) + { + // Found one of our tabs. + hasPlugins = true; + kpw->setCurrentPage(item); + break; + } } - } - if (!romData) { - fputs("*** " RP_KDE_UPPER " rp_show_RomDataView_dialog(): RomData object could not be created for this URI.\n", stderr); - } -#if 0 - // Create an XAttrView object. - // FIXME: Need to reference the XAttrView plugin? - XAttrView *const xattrView = new XAttrView(localUrl, dialog); - if (xattrView->hasAttributes()) { - xattrView->setObjectName(QLatin1String("xattrView")); - tabWidget->addTab(xattrView, QLatin1String("xattrs")); - } else { - fputs("*** " RP_KDE_UPPER " rp_show_RomDataView_dialog(): No extended attributes found; not showing xattrs tab.\n", stderr); - delete xattrView; + hasPlugins = (model->rowCount() > 0); } -#endif - // Make sure we have at least one tab. - if (tabWidget->count() < 1) { + if (!hasPlugins) { fputs("*** " RP_KDE_UPPER " rp_show_RomDataView_dialog(): No tabs were created; exiting.\n", stderr); return EXIT_FAILURE; }