17#include <KDesktopFile>
18#include <KLocalizedString>
19#include <KSharedConfig>
20#include <KConfigGroup>
29 const QStringList languages = KLocalizedString::languages();
30 if (languages.isEmpty()) {
31 return QLocale().name();
33 return languages.first();
44 return filePath.replace(
".",
"/");
54 dbgScript <<
"Ignore desktop file w/o a name";
58 dbgScript <<
"Ignore desktop file w/o a module to import";
78 if (index >= 0 && index <
m_plugins.count()) {
104 rel_path = rel_path +
"/" +
"__init__.py";
105 dbgScript <<
"Finding Python module with rel_path:" << rel_path;
109 dbgScript <<
"module_path:" << module_path;
111 if (module_path.isEmpty()) {
114 dbgScript <<
"Finding Python module with rel_path:" << rel_path;
116 dbgScript <<
"module_path:" << module_path;
120 if (module_path.isEmpty()) {
124 ,
"Unable to find the module specified <application>%1</application>"
130 dbgScript <<
"Found module path:" << module_path;
137 const int pnfo = d.indexOf(
'(');
139 QString dependency = d.mid(0, pnfo);
140 QString version_str = d.mid(pnfo + 1, d.size() - pnfo - 2).trimmed();
141 dbgScript <<
"Desired version spec [" << dependency <<
"]:" << version_str;
143 if (!(checker.
isValid() && d.endsWith(
')'))) {
144 dbgScript <<
"Invalid version spec " << d;
145 QString reason = i18nc(
147 ,
"<p>Specified version has invalid format for dependency <application>%1</application>: "
148 "<icode>%2</icode>. Skipped</p>"
154 return qMakePair(dependency, checker);
174 QString reason = i18nc(
"@info:tooltip",
"<title>Dependency check</title>");
175 Q_FOREACH(
const QString & d, dependencies) {
176 QPair<QString, PyKrita::version_checker> info_pair =
parseDependency(d);
180 reason += info_pair.first;
184 dbgScript <<
"Try to import dependency module/package:" << d;
187 const QString& dependency = info_pair.first;
188 PyObject*
module = py.moduleImport(PQ(dependency));
191 dbgScript <<
"No version to check, just make sure it's loaded:" << dependency;
197 PyObject* version_obj = py.
itemString(
"__version__",
PQ(dependency));
199 dbgScript <<
"No __version__ for " << dependency
205 ,
"<p>Failed to check version of dependency <application>%1</application>: "
206 "Module do not have PEP396 <code>__version__</code> attribute. "
207 "It is not disabled, but behaviour is unpredictable...</p>"
215 dbgScript <<
"***: Can't parse module version for" << dependency;
219 ,
"<p><application>%1</application>: Unexpected module's version format"
222 }
else if (!checker(dep_version)) {
223 dbgScript <<
"Version requirement check failed ["
227 <<
", but found" << QString(dep_version)
232 ,
"<p><application>%1</application>: No suitable version found. "
233 "Required version %2 %3, but found %4</p>"
237 , QString(dep_version)
247 ,
"<p>Failure on module load <application>%1</application>:</p><pre>%2</pre>"
263 KConfigGroup pluginSettings(KSharedConfig::openConfig(),
"python");
267 Q_FOREACH(
const QString &desktopFile, desktopFiles) {
269 KDesktopFile df(desktopFile);
271 const KConfigGroup dg = df.desktopGroup();
272 if (dg.readEntry(
"ServiceTypes") ==
"Krita/PythonPlugin") {
278 QString manual = dg.readEntry(
"X-Krita-Manual");
279 if (!manual.isEmpty()) {
282 f.open(QFile::ReadOnly);
283 QByteArray ba = f.readAll();
330 dbgScript <<
"Loading module: " << module_name;
339 PyObject*
module = py.moduleImport(PQ(module_name));
342 const int ins_result = PyDict_SetItemString(
plugins,
PQ(module_name), module);
346 if (ins_result == 0) {
348 PyObject*
const args = Py_BuildValue(
"(s)",
PQ(module_name));
361 ,
"Module not loaded:<br/>%1"
366 warnScript <<
"Error loading plugin" << module_name;
391 PyObject* sys_modules = py.
itemString(
"modules",
"sys");
402 if (wasEnabled && !enabled) {
407 KConfigGroup pluginSettings(KSharedConfig::openConfig(),
"python");
408 pluginSettings.writeEntry(QString(
"enable_") +
plugin.
moduleName(), enabled);
410 if (!wasEnabled && enabled) {
static QString currentLocale()
static QString currentLocale()
PythonPluginManager * instance
static void writeSysInfo(const QString &message)
Writes to the system information file and Krita log.
static QStringList findAllAssets(const QString &type, const QString &filter=QString(), SearchOptions options=NoSearchOptions)
static QString findAsset(const QString &type, const QString &fileName)
bool functionCall(const char *functionName, const char *moduleName=PYKRITA_ENGINE)
static const char * PYKRITA_ENGINE
PyObject * itemString(const char *item, const char *moduleName=PYKRITA_ENGINE)
QString lastTraceback(void) const
QString operationToString() const
static version_checker fromString(const QString &version_info)
static version fromPythonObject(PyObject *version_obj)
QList< PythonPlugin > m_plugins
PythonPluginsModel * model()
void setPluginEnabled(PythonPlugin &plugin, bool enabled)
PythonPlugin * plugin(int index)
PythonPluginsModel m_model
void tryLoadEnabledPlugins()
static bool verifyModuleExists(PythonPlugin &)
const QList< PythonPlugin > & plugins() const
void loadModule(PythonPlugin &plugin)
static void verifyDependenciesSetStatus(PythonPlugin &)
static QPair< QString, PyKrita::version_checker > parseDependency(const QString &)
void unloadModule(PythonPlugin &plugin)
QString moduleName() const
const QString & errorReason() const
QString moduleFilePathPart() const
QVariant property(const QString &name) const
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
#define PQ(x)
Save us some ruddy time when printing out QStrings with UTF-8.