aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/src/plugincontainer.cpp23
-rw-r--r--src/src/settingsdialog.cpp3
-rw-r--r--src/src/settingsdialog.ui161
-rw-r--r--src/src/settingsdialogpython.cpp206
-rw-r--r--src/src/settingsdialogpython.h29
5 files changed, 5 insertions, 417 deletions
diff --git a/src/src/plugincontainer.cpp b/src/src/plugincontainer.cpp
index a170c99..aa11f6c 100644
--- a/src/src/plugincontainer.cpp
+++ b/src/src/plugincontainer.cpp
@@ -63,10 +63,8 @@ static void ensureBundledPluginsLinked(const QString& bundledDir,
}
#endif
-static void printPluginDiagToStderr(const QString& message)
+static void printPluginDiagToStderr(const QString&)
{
- std::fprintf(stderr, "[plugin-diag] %s\n", qUtf8Printable(message));
- std::fflush(stderr);
}
// Welcome to the wonderful world of MO2 plugin management!
@@ -654,7 +652,7 @@ IPlugin* PluginContainer::registerPlugin(QObject* plugin, const QString& filepat
const QString pluginRoot =
m_PluginPath.isEmpty() ? AppConfig::pluginsPath() : m_PluginPath;
QStringList filepaths = proxy->pluginList(pluginRoot);
- log::warn("proxy '{}' discovered {} proxied plugin candidate(s) in '{}'",
+ log::debug("proxy '{}' discovered {} proxied plugin candidate(s) in '{}'",
proxy->name(), filepaths.size(),
QDir::toNativeSeparators(pluginRoot));
printPluginDiagToStderr(
@@ -859,7 +857,7 @@ std::vector<QObject*> PluginContainer::loadProxied(const QString& filepath,
std::vector<QObject*> proxiedPlugins;
try {
- log::warn("loading proxied plugin candidate '{}' via proxy '{}'",
+ log::debug("loading proxied plugin candidate '{}' via proxy '{}'",
QDir::toNativeSeparators(filepath),
(proxy ? proxy->name() : QStringLiteral("<null>")));
printPluginDiagToStderr(
@@ -871,7 +869,7 @@ std::vector<QObject*> PluginContainer::loadProxied(const QString& filepath,
// per file and do not have a good way of supporting multiple inheritance.
QList<QObject*> matchingPlugins = proxy->load(filepath);
if (matchingPlugins.isEmpty()) {
- log::warn("no plugins were returned for proxied candidate '{}' via proxy '{}'",
+ log::debug("no plugins were returned for proxied candidate '{}' via proxy '{}'",
QDir::toNativeSeparators(filepath), proxy->name());
printPluginDiagToStderr(
QString("no plugins were returned for proxied candidate '%1' via proxy '%2'")
@@ -930,7 +928,7 @@ std::vector<QObject*> PluginContainer::loadProxied(const QString& filepath,
}
}
}
- log::warn("finished proxied candidate '{}' via proxy '{}': {} plugin(s) loaded",
+ log::debug("finished proxied candidate '{}' via proxy '{}': {} plugin(s) loaded",
QDir::toNativeSeparators(filepath), proxy->name(),
proxiedPlugins.size());
printPluginDiagToStderr(
@@ -1305,17 +1303,6 @@ void PluginContainer::loadPlugins()
}
}
- // Skip the Python proxy plugin unless the user has enabled Python support
- // in Settings > Python. Native C++ replacements handle all default plugins.
- if (iter.fileName() == "libplugin_python.so" ||
- iter.fileName() == "plugin_python.dll") {
- if (!QSettings().value("fluorine/python_enabled", false).toBool()) {
- log::debug("plugin \"{}\" skipped (Python plugins disabled in settings)",
- iter.fileName());
- continue;
- }
- }
-
if (loadCheck.isOpen()) {
loadCheck.write(iter.fileName().toUtf8());
loadCheck.write("\n");
diff --git a/src/src/settingsdialog.cpp b/src/src/settingsdialog.cpp
index 757c6f8..7a4c2b9 100644
--- a/src/src/settingsdialog.cpp
+++ b/src/src/settingsdialog.cpp
@@ -25,7 +25,6 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "settingsdialogpaths.h"
#include "settingsdialogplugins.h"
#include "settingsdialogproton.h"
-#include "settingsdialogpython.h"
#include "settingsdialogtheme.h"
#include "settingsdialogworkarounds.h"
#include "ui_settingsdialog.h"
@@ -53,8 +52,6 @@ SettingsDialog::SettingsDialog(PluginContainer* pluginContainer, Settings& setti
m_tabs.push_back(
std::unique_ptr<SettingsTab>(new ProtonSettingsTab(settings, *this)));
m_tabs.push_back(
- std::unique_ptr<SettingsTab>(new PythonSettingsTab(settings, *this)));
- m_tabs.push_back(
std::unique_ptr<SettingsTab>(new WorkaroundsSettingsTab(settings, *this)));
}
diff --git a/src/src/settingsdialog.ui b/src/src/settingsdialog.ui
index 2089c06..646b9b6 100644
--- a/src/src/settingsdialog.ui
+++ b/src/src/settingsdialog.ui
@@ -1897,167 +1897,6 @@ If you disable this feature, MO will only display official DLCs this way. Please
</item>
</layout>
</widget>
- <widget class="QWidget" name="pythonTab">
- <attribute name="title">
- <string>Python</string>
- </attribute>
- <layout class="QVBoxLayout" name="verticalLayout_python">
- <item>
- <widget class="QGroupBox" name="groupBox_python">
- <property name="title">
- <string>Python Plugin Support</string>
- </property>
- <layout class="QGridLayout" name="gridLayout_python">
- <item row="0" column="0">
- <widget class="QLabel" name="pythonEnableLabel">
- <property name="text">
- <string>Enable Python Plugins:</string>
- </property>
- </widget>
- </item>
- <item row="0" column="1" colspan="2">
- <widget class="QCheckBox" name="pythonEnableCheck">
- <property name="text">
- <string>Load .py plugins (requires Python 3 and PyQt6)</string>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="pythonPathLabel">
- <property name="text">
- <string>Python Path:</string>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QLineEdit" name="pythonPathEdit">
- <property name="readOnly">
- <bool>true</bool>
- </property>
- <property name="placeholderText">
- <string>Auto-detected</string>
- </property>
- </widget>
- </item>
- <item row="1" column="2">
- <widget class="QPushButton" name="pythonRefreshButton">
- <property name="text">
- <string>Detect</string>
- </property>
- </widget>
- </item>
- <item row="2" column="0">
- <widget class="QLabel" name="pythonVersionLabel">
- <property name="text">
- <string>Version:</string>
- </property>
- </widget>
- </item>
- <item row="2" column="1" colspan="2">
- <widget class="QLabel" name="pythonVersionValue">
- <property name="text">
- <string>Not detected</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <widget class="QGroupBox" name="groupBox_venv">
- <property name="title">
- <string>Virtual Environment</string>
- </property>
- <layout class="QGridLayout" name="gridLayout_venv">
- <item row="0" column="0">
- <widget class="QLabel" name="venvPathLabel">
- <property name="text">
- <string>Venv Location:</string>
- </property>
- </widget>
- </item>
- <item row="0" column="1" colspan="2">
- <widget class="QLineEdit" name="venvPathEdit">
- <property name="readOnly">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="venvStatusLabel">
- <property name="text">
- <string>Status:</string>
- </property>
- </widget>
- </item>
- <item row="1" column="1" colspan="2">
- <widget class="QLabel" name="venvStatusValue">
- <property name="text">
- <string>Not created</string>
- </property>
- </widget>
- </item>
- <item row="2" column="0">
- <widget class="QPushButton" name="createVenvButton">
- <property name="text">
- <string>Create Virtual Environment</string>
- </property>
- <property name="toolTip">
- <string>Creates a Python virtual environment and installs PyQt6. Required for loading .py plugins.</string>
- </property>
- </widget>
- </item>
- <item row="2" column="1">
- <widget class="QPushButton" name="deleteVenvButton">
- <property name="text">
- <string>Delete Venv</string>
- </property>
- </widget>
- </item>
- <item row="2" column="2">
- <widget class="QPushButton" name="openVenvFolderButton">
- <property name="text">
- <string>Open Folder</string>
- </property>
- </widget>
- </item>
- <item row="3" column="0" colspan="3">
- <widget class="QTextEdit" name="pythonLogOutput">
- <property name="readOnly">
- <bool>true</bool>
- </property>
- <property name="visible">
- <bool>false</bool>
- </property>
- <property name="maximumHeight">
- <number>150</number>
- </property>
- <property name="font">
- <font>
- <family>monospace</family>
- <pointsize>9</pointsize>
- </font>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <spacer name="verticalSpacer_python">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>40</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </widget>
<widget class="QWidget" name="workaroundTab">
<attribute name="title">
<string>Workarounds</string>
diff --git a/src/src/settingsdialogpython.cpp b/src/src/settingsdialogpython.cpp
deleted file mode 100644
index ebad6eb..0000000
--- a/src/src/settingsdialogpython.cpp
+++ /dev/null
@@ -1,206 +0,0 @@
-#include "settingsdialogpython.h"
-
-#include "fluorinepaths.h"
-#include "ui_settingsdialog.h"
-
-#include <log.h>
-#include <uibase/utility.h>
-
-#include <QCheckBox>
-#include <QDir>
-#include <QFileInfo>
-#include <QMessageBox>
-#include <QProcess>
-#include <QPushButton>
-#include <QSettings>
-#include <QStandardPaths>
-
-PythonSettingsTab::PythonSettingsTab(Settings& s, SettingsDialog& d)
- : QObject(&d), SettingsTab(s, d)
-{
- m_venvPath = fluorineDataDir() + "/python-venv";
- ui->venvPathEdit->setText(m_venvPath);
-
- // Load saved state
- bool pythonEnabled = QSettings().value("fluorine/python_enabled", false).toBool();
- ui->pythonEnableCheck->setChecked(pythonEnabled);
-
- detectPython();
- refreshVenvState();
-
- QObject::connect(ui->pythonRefreshButton, &QPushButton::clicked, this,
- &PythonSettingsTab::detectPython);
- QObject::connect(ui->createVenvButton, &QPushButton::clicked, this,
- &PythonSettingsTab::onCreateVenv);
- QObject::connect(ui->deleteVenvButton, &QPushButton::clicked, this,
- &PythonSettingsTab::onDeleteVenv);
- QObject::connect(ui->openVenvFolderButton, &QPushButton::clicked, this,
- &PythonSettingsTab::onOpenVenvFolder);
-}
-
-void PythonSettingsTab::update()
-{
- QSettings().setValue("fluorine/python_enabled",
- ui->pythonEnableCheck->isChecked());
-}
-
-void PythonSettingsTab::detectPython()
-{
- m_pythonPath = QStandardPaths::findExecutable("python3");
- if (m_pythonPath.isEmpty()) {
- m_pythonPath = QStandardPaths::findExecutable("python");
- }
-
- if (m_pythonPath.isEmpty()) {
- ui->pythonPathEdit->setText("");
- ui->pythonVersionValue->setText("Python 3 not found in PATH");
- return;
- }
-
- ui->pythonPathEdit->setText(m_pythonPath);
-
- // Get version
- QProcess proc;
- proc.start(m_pythonPath, {"--version"});
- proc.waitForFinished(5000);
-
- if (proc.exitCode() == 0) {
- QString version = QString::fromUtf8(proc.readAllStandardOutput()).trimmed();
- if (version.isEmpty()) {
- version = QString::fromUtf8(proc.readAllStandardError()).trimmed();
- }
- ui->pythonVersionValue->setText(version);
- } else {
- ui->pythonVersionValue->setText("Error detecting version");
- }
-}
-
-void PythonSettingsTab::refreshVenvState()
-{
- QDir venvDir(m_venvPath);
- bool exists = venvDir.exists() && venvDir.exists("bin/python3");
-
- if (exists) {
- // Check if PyQt6 is installed
- QProcess proc;
- proc.start(m_venvPath + "/bin/python3",
- {"-c", "import PyQt6; print(PyQt6.__file__)"});
- proc.waitForFinished(5000);
-
- if (proc.exitCode() == 0) {
- ui->venvStatusValue->setText("Active (PyQt6 installed)");
- } else {
- ui->venvStatusValue->setText("Active (PyQt6 NOT installed)");
- }
- } else {
- ui->venvStatusValue->setText("Not created");
- }
-
- ui->deleteVenvButton->setEnabled(exists);
- ui->openVenvFolderButton->setEnabled(exists);
-}
-
-void PythonSettingsTab::onCreateVenv()
-{
- if (m_pythonPath.isEmpty()) {
- QMessageBox::warning(parentWidget(), tr("No Python"),
- tr("Python 3 was not found in PATH.\n\n"
- "Install Python 3 using your package manager:\n"
- " Arch: pacman -S python\n"
- " Ubuntu: apt install python3 python3-venv\n"
- " Fedora: dnf install python3"));
- return;
- }
-
- ui->pythonLogOutput->setVisible(true);
- ui->pythonLogOutput->clear();
- ui->venvStatusValue->setText("Creating virtual environment...");
-
- // Create venv
- {
- QProcess proc;
- proc.start(m_pythonPath, {"-m", "venv", m_venvPath});
- proc.waitForFinished(30000);
-
- QString output = QString::fromUtf8(proc.readAllStandardOutput());
- QString errors = QString::fromUtf8(proc.readAllStandardError());
- if (!output.isEmpty())
- ui->pythonLogOutput->append(output);
- if (!errors.isEmpty())
- ui->pythonLogOutput->append(errors);
-
- if (proc.exitCode() != 0) {
- ui->venvStatusValue->setText("Failed to create venv");
- ui->pythonLogOutput->append("venv creation failed with exit code " +
- QString::number(proc.exitCode()));
- return;
- }
- }
-
- ui->pythonLogOutput->append("Virtual environment created. Installing PyQt6...");
- ui->venvStatusValue->setText("Installing PyQt6...");
-
- // Install PyQt6
- {
- QProcess proc;
- proc.start(m_venvPath + "/bin/pip",
- {"install", "--upgrade", "pip", "PyQt6"});
- proc.waitForFinished(120000); // PyQt6 is large, give it time
-
- QString output = QString::fromUtf8(proc.readAllStandardOutput());
- QString errors = QString::fromUtf8(proc.readAllStandardError());
- if (!output.isEmpty())
- ui->pythonLogOutput->append(output);
- if (!errors.isEmpty())
- ui->pythonLogOutput->append(errors);
-
- if (proc.exitCode() != 0) {
- ui->venvStatusValue->setText("PyQt6 installation failed");
- ui->pythonLogOutput->append("pip install failed with exit code " +
- QString::number(proc.exitCode()));
- refreshVenvState();
- return;
- }
- }
-
- ui->pythonLogOutput->append("PyQt6 installed successfully.");
- MOBase::log::info("Python venv created at {}", m_venvPath);
-
- refreshVenvState();
-}
-
-void PythonSettingsTab::onDeleteVenv()
-{
- QDir venvDir(m_venvPath);
- if (!venvDir.exists()) {
- refreshVenvState();
- return;
- }
-
- auto result = QMessageBox::question(
- parentWidget(), tr("Delete Virtual Environment"),
- tr("Delete the Python virtual environment at:\n%1\n\n"
- "This will disable .py plugin loading until recreated.")
- .arg(m_venvPath));
-
- if (result != QMessageBox::Yes)
- return;
-
- if (venvDir.removeRecursively()) {
- ui->pythonLogOutput->setVisible(false);
- MOBase::log::info("Python venv deleted at {}", m_venvPath);
- } else {
- QMessageBox::warning(parentWidget(), tr("Error"),
- tr("Failed to delete the virtual environment."));
- }
-
- refreshVenvState();
-}
-
-void PythonSettingsTab::onOpenVenvFolder()
-{
- QDir venvDir(m_venvPath);
- if (venvDir.exists()) {
- MOBase::shell::Explore(venvDir);
- }
-}
diff --git a/src/src/settingsdialogpython.h b/src/src/settingsdialogpython.h
deleted file mode 100644
index 187d04b..0000000
--- a/src/src/settingsdialogpython.h
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef SETTINGSDIALOGPYTHON_H
-#define SETTINGSDIALOGPYTHON_H
-
-#include <QObject>
-
-#include "settings.h"
-#include "settingsdialog.h"
-
-class PythonSettingsTab : public QObject, public SettingsTab
-{
- Q_OBJECT
-
-public:
- PythonSettingsTab(Settings& settings, SettingsDialog& dialog);
-
- void update() override;
-
-private:
- void detectPython();
- void refreshVenvState();
- void onCreateVenv();
- void onDeleteVenv();
- void onOpenVenvFolder();
-
- QString m_pythonPath;
- QString m_venvPath;
-};
-
-#endif // SETTINGSDIALOGPYTHON_H