Skip to content

Commit

Permalink
[kde] stub-export.cpp: Use KPropertiesDialog instead of creating a di…
Browse files Browse the repository at this point in the history
…alog 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.
  • Loading branch information
GerbilSoft committed Jan 5, 2025
1 parent 9d5fb09 commit 462e220
Showing 1 changed file with 53 additions and 71 deletions.
124 changes: 53 additions & 71 deletions src/kde/config/stub-export.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 *
***************************************************************************/

Expand Down Expand Up @@ -33,9 +33,15 @@ using namespace LibRpTexture;
# include "../GettextTranslator.hpp"
#endif

// KCrash
// Qt
#include "RpQt.hpp"

// KDE
#include <KAboutData>
#include <KCrash>
#include <KPageWidget>
#include <KPageWidgetModel>
#include <KPropertiesDialog>

// C++ STL classes
using std::string;
Expand Down Expand Up @@ -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<KPageWidget*>(dialog);
if (kpw) {
// Remove tabs that aren't for our plugins.
// TODO
KPageWidgetModel *const model = findDirectChild<KPageWidgetModel*>(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;
}
Expand Down

0 comments on commit 462e220

Please sign in to comment.