aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEike Ziller <eike.ziller@qt.io>2018-10-01 12:29:21 +0200
committerEike Ziller <eike.ziller@qt.io>2018-10-01 12:29:21 +0200
commitada8aaffed20dfbe6bc6df8c21c85b4138957490 (patch)
treed738ea0a24c1013e589e69240d6fc91ae13ed999
parent55732e19082a566f644e08bd28b9cff6161dcb7e (diff)
parent3412dc563119221bd730c1487937519df0761792 (diff)
Merge remote-tracking branch 'origin/4.8'
-rw-r--r--README.md14
-rw-r--r--docs/extensions.md37
-rw-r--r--examples/examples.pro4
-rw-r--r--examples/examples_common.py8
-rw-r--r--examples/macroexpander.py (renamed from examples/macroexpander/__init__.py)13
-rw-r--r--examples/projects/__init__.py8
-rw-r--r--examples/projects/view.py6
-rw-r--r--examples/requirerequests/__init__.py6
-rw-r--r--examples/smallmenu/__init__.py10
-rw-r--r--examples/transform/__init__.py8
-rw-r--r--examples/transform/actions.py7
-rw-r--r--examples/transform/ui.py4
-rw-r--r--optional/projectexplorer/binding.cpp2
-rw-r--r--optional/projectexplorer/projectexplorer.pro1
-rw-r--r--optional/projectexplorer/typesystem_projectexplorer.xml4
-rw-r--r--optional/texteditor/binding.cpp2
-rw-r--r--plugins/pythonextensions/bindingheaders/pythonextensions_extension.h0
-rw-r--r--plugins/pythonextensions/pythonextensions.pro3
-rw-r--r--plugins/pythonextensions/pythonextensionsplugin.cpp96
-rw-r--r--plugins/pythonextensions/pythonextensionsplugin.h14
-rw-r--r--plugins/pythonextensions/pyutil.cpp11
-rw-r--r--plugins/pythonextensions/pyutil.h4
-rw-r--r--plugins/pythonextensions/typesystem_qtcreator.xml3
-rw-r--r--python/extensionmanager/__init__.py13
-rw-r--r--python/extensionmanager/actions.py12
-rw-r--r--python/extensionmanager/list.py19
26 files changed, 175 insertions, 134 deletions
diff --git a/README.md b/README.md
index 58f2ee5..709dbc8 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,10 @@
# Python Extensions for Qt Creator
This plugin for Qt Creator makes it possible to extend the Qt Creator by
-writing Python extensions. These extensions are simply Python packages,
-so they are directories containing a `__init__.py` and any other Python
-files necessary. They can be shared as zip archives, installed and managed
+writing Python extensions. These extensions are simply Python modules or
+packages, so they are either single Python files or directories containing a
+`__init__.py` and any other Python files necessary.
+They can be shared as zip archives, installed and managed
through the included extension manager (which is a Python extension itself) and
thus allow the Qt Creator to be easily extended with custom functionality.
@@ -129,9 +130,10 @@ The following process allows the plugin to work:
2. When Qt Creator is executed, the C++ plugin searches the standard
Qt Creator plugin directories for a directory named `python`, the
first directory found is the Python extension directory.
- Each python package in this directory represents it's own Python extension.
- Each package is loaded with `import`, which executes the initialization
- code in its `__init__.py`.
+ Each python module and package in this directory represents it's own Python
+ extension. Each extension is loaded with `import`, which executes the
+ module's initialization code (for extensions in the form of Python packages
+ that is the code in `__init__.py`).
3. Now all Python extensions have registered their actions / menus / etc.,
which can be triggered from the Qt Creator interface.
diff --git a/docs/extensions.md b/docs/extensions.md
index 7152ef6..57a6f15 100644
--- a/docs/extensions.md
+++ b/docs/extensions.md
@@ -6,33 +6,28 @@ for Qt Creator.
## Importing Qt Creator specific modules
Currently, the bindings are available from Python under the following names:
```Python
-from PythonExtension import QtCreator # Imports the generated module for the typesystem
-from PythonExtension import PluginInstance # Imports the plugin instance
+from QtCreator import Utils # Imports Qt Creator's Utils helper library
+from QtCreator import Core # Imports Qt Creator's Core plugin API
+from QtCreator import PythonExtensions # Imports Python extension specific helper functions
```
-## `PythonExtension.PluginInstance`
+## `QtCreator.PythonExtensions`
This is the Python binding for the extension manager that works on the C++ side. It provides the
-following functions, that can (and should) be used from Python:
+following functions, that can be used from Python:
```Python
-from PythonExtension import PluginInstance as inst
+from QtCreator import PythonExtensions
# Returns a PySide QDir which points to the extension directory
-inst.extensionDir()
+PythonExtensions.extensionDir()
# Returns a list with the names of all Python extensions
-# If loaded only is supplied as True, only extensions that
-# where loaded successfully are returned
-inst.extensionList(loadedOnly = False)
-
-# Mark an extension as loaded
-# This should normally not be used and exists mainly
-# for use by the extension manager
-inst.flagAsLoaded("name_of_extension")
+# Each extension has properties 'name' and 'loaded'
+PythonExtensions.extensionList()
# Returns the path of the custom location to
# where missing dependencies should be pip installed
-inst.pythonPackagePath()
+PythonExtensions.pythonPackagePath()
```
@@ -48,7 +43,7 @@ add a new action container, that holds a sub-menu.
The following code snippet illustrates how to add a new menu.
```Python
-from PythonExtension import QtCreator
+from QtCreator import Core
def hello():
print("Hello World.")
@@ -56,24 +51,24 @@ def hello():
# By convention, the menuId starts with "Python"
menuId = "Python.SmallMenu.Menu"
-menu = QtCreator.Core.ActionManager.createMenu(menuId)
+menu = Core.ActionManager.createMenu(menuId)
menu.menu().setTitle("My menu")
menu.menu().addAction("My action", hello)
-# Add our new menu to the "Tools" menu in QtCreator
-QtCreator.Core.ActionManager.actionContainer("QtCreator.Menu.Tools").addMenu(menu)
+# Add our new menu to the "Tools" menu in Qt Creator
+Core.ActionManager.actionContainer("QtCreator.Menu.Tools").addMenu(menu)
```
### Adding a new action directly
The following code snippet illustrates how to add a new action to an existing action container.
```Python
-from PythonExtension import QtCreator
+from QtCreator import Core
def hello():
print("Hello World.")
# Add a new action to the "Tools" menu
-menu = QtCreator.Core.ActionManager.actionContainer("QtCreator.Menu.Tools")
+menu = Core.ActionManager.actionContainer("QtCreator.Menu.Tools")
menu.menu().addAction("My action", hello)
```
diff --git a/examples/examples.pro b/examples/examples.pro
index 57b1764..34b5843 100644
--- a/examples/examples.pro
+++ b/examples/examples.pro
@@ -7,7 +7,6 @@ include(../plugins/pythonextensions/qtcreator.pri)
include($$IDE_SOURCE_TREE/qtcreator.pri)
inst_examples.files = \
- macroexpander \
projects \
requirerequests \
smallmenu \
@@ -18,7 +17,8 @@ inst_examples.CONFIG += no_default_install directory
INSTALLS += inst_examples
inst_examplefiles.files = \
- examples_common.py
+ examples_common.py \
+ macroexpander.py
inst_examplefiles.path = $$IDE_PLUGIN_PATH/python
inst_examplefiles.CONFIG += no_default_install
diff --git a/examples/examples_common.py b/examples/examples_common.py
index db7f669..0bb93d4 100644
--- a/examples/examples_common.py
+++ b/examples/examples_common.py
@@ -38,15 +38,15 @@
##
#############################################################################
-from PythonExtension import QtCreator
+from QtCreator import Core
def ensureExamplesMenu():
menuId = 'PythonExtensions.Examples'
- menu = QtCreator.Core.ActionManager.actionContainer(menuId)
+ menu = Core.ActionManager.actionContainer(menuId)
if not menu:
- menu = QtCreator.Core.ActionManager.createMenu(menuId)
+ menu = Core.ActionManager.createMenu(menuId)
menu.menu().setTitle("Python Extensions Examples")
- toolsMenu = QtCreator.Core.ActionManager.actionContainer("QtCreator.Menu.Tools")
+ toolsMenu = Core.ActionManager.actionContainer("QtCreator.Menu.Tools")
toolsMenu.addMenu(menu)
return menu
diff --git a/examples/macroexpander/__init__.py b/examples/macroexpander.py
index 20e10a3..17c30cc 100644
--- a/examples/macroexpander/__init__.py
+++ b/examples/macroexpander.py
@@ -45,22 +45,23 @@ import examples_common
from PySide2.QtCore import QObject, SIGNAL
from PySide2.QtWidgets import QInputDialog, QMessageBox, QAction
-from PythonExtension import QtCreator
+from QtCreator import Core
+from QtCreator import Utils
# Register our macro (it can be used as %{Python:exp})
-QtCreator.Utils.MacroExpander().registerPrefix(b"Python", "Evaluate Python expressions.", lambda x: eval(x))
+Utils.MacroExpander().registerPrefix(b"Python", "Evaluate Python expressions.", lambda x: eval(x))
# Add a small menu item, that let's us test the macro
def act():
- text = QInputDialog.getMultiLineText(QtCreator.Core.ICore.dialogParent(),
+ text = QInputDialog.getMultiLineText(Core.ICore.dialogParent(),
"Input Text", "Input your text, including some macros",
"3 + 3 = %{Python:3+3}")
- text = QtCreator.Utils.MacroExpander().expand(text[0])
- QMessageBox.information(QtCreator.Core.ICore.dialogParent(), "Result", text)
+ text = Utils.MacroExpander().expand(text[0])
+ QMessageBox.information(Core.ICore.dialogParent(), "Result", text)
# Add this to the "Tools" menu
action = QAction("Test Macro Expander...")
-command = QtCreator.Core.ActionManager.registerAction(action, 'PythonExtensions.Examples.MacroExpander')
+command = Core.ActionManager.registerAction(action, 'PythonExtensions.Examples.MacroExpander')
QObject.connect(action, SIGNAL('triggered()'), act)
examples_common.addExampleItem(command)
diff --git a/examples/projects/__init__.py b/examples/projects/__init__.py
index c7919fc..a618e5b 100644
--- a/examples/projects/__init__.py
+++ b/examples/projects/__init__.py
@@ -42,16 +42,16 @@
# project. It also includes a dependency on a plugin
# that can be disabled.
+from . import view
import examples_common
-import view
-from PythonExtension import QtCreator
+from QtCreator import Core
from PySide2.QtCore import QObject, SIGNAL
from PySide2.QtWidgets import QAction
# When importing optional bindings, we can warn the user in case things go south
try:
- from PythonExtension.QtCreator import ProjectExplorer
+ from QtCreator import ProjectExplorer
except ImportError:
view.error("The extension \"projects\" could not be loaded, since it depends on a disabled plugin.")
raise Exception("Dependencies missing")
@@ -65,7 +65,7 @@ def showProjectPath():
view.error("Please open a project")
action = QAction("Show Project Directory")
-command = QtCreator.Core.ActionManager.registerAction(action, 'PythonExtensions.Examples.ShowProjectDirectory')
+command = Core.ActionManager.registerAction(action, 'PythonExtensions.Examples.ShowProjectDirectory')
QObject.connect(action, SIGNAL('triggered()'), showProjectPath)
examples_common.addExampleItem(command)
diff --git a/examples/projects/view.py b/examples/projects/view.py
index 31dbbe6..df1eeb0 100644
--- a/examples/projects/view.py
+++ b/examples/projects/view.py
@@ -41,10 +41,10 @@
# This contains all the display logic
from PySide2 import QtWidgets
-from PythonExtension import QtCreator
+from QtCreator import Core
def error(text, title="Error"):
- QtWidgets.QMessageBox.critical(QtCreator.Core.ICore.instance().dialogParent(), title, text)
+ QtWidgets.QMessageBox.critical(Core.ICore.instance().dialogParent(), title, text)
def show(text, title="Result"):
- QtWidgets.QMessageBox.information(QtCreator.Core.ICore.instance().dialogParent(), title, text)
+ QtWidgets.QMessageBox.information(Core.ICore.instance().dialogParent(), title, text)
diff --git a/examples/requirerequests/__init__.py b/examples/requirerequests/__init__.py
index acbf9e6..3fb14c7 100644
--- a/examples/requirerequests/__init__.py
+++ b/examples/requirerequests/__init__.py
@@ -44,7 +44,7 @@
import examples_common
-from PythonExtension import QtCreator
+from QtCreator import Core
from PySide2.QtCore import QObject, SIGNAL
from PySide2.QtWidgets import QAction, QMessageBox
@@ -52,14 +52,14 @@ import requests
def load(url):
r = requests.get(url)
- box = QMessageBox(QtCreator.Core.ICore.dialogParent())
+ box = QMessageBox(Core.ICore.dialogParent())
box.setWindowTitle("Request results")
box.setText("The request status is {}".format(r.status_code))
box.setDetailedText(r.text)
box.exec_()
action = QAction("Load from the web...")
-command = QtCreator.Core.ActionManager.registerAction(action, 'PythonExtensions.Examples.LoadFromWeb')
+command = Core.ActionManager.registerAction(action, 'PythonExtensions.Examples.LoadFromWeb')
QObject.connect(action, SIGNAL('triggered()'), lambda: load("https://www.qt.io/"))
examples_common.addExampleItem(command)
diff --git a/examples/smallmenu/__init__.py b/examples/smallmenu/__init__.py
index 5dcfef9..f26b637 100644
--- a/examples/smallmenu/__init__.py
+++ b/examples/smallmenu/__init__.py
@@ -41,27 +41,27 @@
# This example illustrates the use of action
# containers to create new menus
-from actions import hello, goodbye
+from .actions import hello, goodbye
import examples_common
-from PythonExtension import QtCreator
+from QtCreator import Core
from PySide2.QtCore import QObject, SIGNAL
from PySide2.QtWidgets import QAction
# Create submenu and add it to examples menu
menuId = "PythonExtensions.Examples.SmallMenu"
-menu = QtCreator.Core.ActionManager.createMenu(menuId)
+menu = Core.ActionManager.createMenu(menuId)
menu.menu().setTitle("Small Menu")
examplesMenu = examples_common.ensureExamplesMenu()
examplesMenu.addMenu(menu)
# Add actions to our new menu
helloAction = QAction("Say Hello")
-command = QtCreator.Core.ActionManager.registerAction(helloAction, 'PythonExtensions.Examples.SayHello')
+command = Core.ActionManager.registerAction(helloAction, 'PythonExtensions.Examples.SayHello')
QObject.connect(helloAction, SIGNAL('triggered()'), hello)
menu.addAction(command)
goodbyeAction = QAction("Say Goodbye")
-command = QtCreator.Core.ActionManager.registerAction(goodbyeAction, 'PythonExtensions.Examples.SayGoodbye')
+command = Core.ActionManager.registerAction(goodbyeAction, 'PythonExtensions.Examples.SayGoodbye')
QObject.connect(goodbyeAction, SIGNAL('triggered()'), goodbye)
menu.addAction(command)
diff --git a/examples/transform/__init__.py b/examples/transform/__init__.py
index c58f4e6..f2647dc 100644
--- a/examples/transform/__init__.py
+++ b/examples/transform/__init__.py
@@ -42,11 +42,11 @@
# user supplied function that executes on
# a set of files specified by the user
-import actions
+from . import actions
+from . import ui
import examples_common
-import ui
-from PythonExtension import QtCreator
+from QtCreator import Core
from PySide2.QtCore import QObject, SIGNAL
from PySide2.QtWidgets import QAction
@@ -56,7 +56,7 @@ def transform():
actions.run(code[0])
action = QAction("Transform files...")
-command = QtCreator.Core.ActionManager.registerAction(action, 'PythonExtensions.Examples.TransformFiles')
+command = Core.ActionManager.registerAction(action, 'PythonExtensions.Examples.TransformFiles')
QObject.connect(action, SIGNAL('triggered()'), transform)
examples_common.addExampleItem(command)
diff --git a/examples/transform/actions.py b/examples/transform/actions.py
index de54d94..e459ab2 100644
--- a/examples/transform/actions.py
+++ b/examples/transform/actions.py
@@ -38,13 +38,14 @@
##
#############################################################################
-from PythonExtension import QtCreator
-import ui
+from . import ui
+
+from QtCreator import Core
# Apply a function to each file
def run(code):
try:
- files = QtCreator.Core.DocumentManager.getOpenFileNames("")
+ files = Core.DocumentManager.getOpenFileNames("")
if len(files) == 0:
ui.error("No files were selected.")
return
diff --git a/examples/transform/ui.py b/examples/transform/ui.py
index 21892ef..cc5b7f1 100644
--- a/examples/transform/ui.py
+++ b/examples/transform/ui.py
@@ -38,7 +38,7 @@
##
#############################################################################
-from PythonExtension import QtCreator
+from QtCreator import Core
from PySide2 import QtWidgets
template = """# Parameters:
@@ -53,7 +53,7 @@ filebody
def getCode():
return QtWidgets.QInputDialog.getMultiLineText(
- QtCreator.Core.ICore.dialogParent(),
+ Core.ICore.dialogParent(),
"Input transformation expression",
"Transform expression:",
template
diff --git a/optional/projectexplorer/binding.cpp b/optional/projectexplorer/binding.cpp
index 325027b..ae1bbc7 100644
--- a/optional/projectexplorer/binding.cpp
+++ b/optional/projectexplorer/binding.cpp
@@ -59,7 +59,7 @@ void bind()
// Bind module into interpreter
bool pythonError = PyErr_Occurred() != nullptr;
if (pythonInitialized && !pythonError) {
- PyUtil::bindSubPyObject("PythonExtension.QtCreator", "ProjectExplorer", (void *)SbkQtCreatorBindingProjectExplorerModuleObject);
+ PyUtil::bindSubPyObject("QtCreator", "ProjectExplorer", (void *)SbkQtCreatorBindingProjectExplorerModuleObject);
} else {
if (pythonError)
PyErr_Print();
diff --git a/optional/projectexplorer/projectexplorer.pro b/optional/projectexplorer/projectexplorer.pro
index a60ac99..b998d93 100644
--- a/optional/projectexplorer/projectexplorer.pro
+++ b/optional/projectexplorer/projectexplorer.pro
@@ -18,6 +18,7 @@ QTC_PLUGIN_RECOMMENDS += \
include(../binding/binding.pri)
INCLUDEPATH *= $$IDE_SOURCE_TREE/src/plugins/projectexplorer
+win32: DEFINES += NOMINMAX
# Shiboken binding generation setup
diff --git a/optional/projectexplorer/typesystem_projectexplorer.xml b/optional/projectexplorer/typesystem_projectexplorer.xml
index b663619..0e0eeff 100644
--- a/optional/projectexplorer/typesystem_projectexplorer.xml
+++ b/optional/projectexplorer/typesystem_projectexplorer.xml
@@ -60,7 +60,9 @@
<object-type name="ProjectTree"/>
<object-type name="Project">
<enum-type name="ModelRoles"/>
- <enum-type name="RestoreResult"/>
+ <!-- protected methods that return enum classes fail on Windows, remove for now -->
+ <!--<enum-type name="RestoreResult"/>-->
+ <modify-function signature="fromMap(const QVariantMap&amp;,QString*)" remove="all"/>
</object-type>
</namespace-type>
diff --git a/optional/texteditor/binding.cpp b/optional/texteditor/binding.cpp
index d2d5b83..6b9007f 100644
--- a/optional/texteditor/binding.cpp
+++ b/optional/texteditor/binding.cpp
@@ -59,7 +59,7 @@ void bind()
// Bind module into interpreter
bool pythonError = PyErr_Occurred() != nullptr;
if (pythonInitialized && !pythonError) {
- PyUtil::bindSubPyObject("PythonExtension.QtCreator", "TextEditor", (void *)SbkQtCreatorBindingTextEditorModuleObject);
+ PyUtil::bindSubPyObject("QtCreator", "TextEditor", (void *)SbkQtCreatorBindingTextEditorModuleObject);
} else {
if (pythonError)
PyErr_Print();
diff --git a/plugins/pythonextensions/bindingheaders/pythonextensions_extension.h b/plugins/pythonextensions/bindingheaders/pythonextensions_extension.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/plugins/pythonextensions/bindingheaders/pythonextensions_extension.h
diff --git a/plugins/pythonextensions/pythonextensions.pro b/plugins/pythonextensions/pythonextensions.pro
index c8fe73d..334e029 100644
--- a/plugins/pythonextensions/pythonextensions.pro
+++ b/plugins/pythonextensions/pythonextensions.pro
@@ -24,7 +24,7 @@ include($$IDE_SOURCE_TREE/src/qtcreatorplugin.pri)
# Qt Creator Core bindings
WRAPPED_HEADER = $$PWD/wrappedclasses.h
-WRAPPER_DIR = $$OUT_PWD/PythonExtension/QtCreator
+WRAPPER_DIR = $$OUT_PWD/QtCreator
TYPESYSTEM_FILE = typesystem_qtcreator.xml
TYPESYSTEM_NAME = qtcreator
SHIBOKEN_QT = core gui widgets
@@ -36,6 +36,7 @@ WRAPPED_CLASSES = \
bindingheaders/pythonextensions.h \
bindingheaders/pythonextensions_internal.h \
bindingheaders/pythonextensions_internal_pythonextensionsplugin.h \
+ bindingheaders/pythonextensions_extension.h \
bindingheaders/core.h \
bindingheaders/core_actioncontainer.h \
bindingheaders/core_actionmanager.h \
diff --git a/plugins/pythonextensions/pythonextensionsplugin.cpp b/plugins/pythonextensions/pythonextensionsplugin.cpp
index 3547a59..59b32a1 100644
--- a/plugins/pythonextensions/pythonextensionsplugin.cpp
+++ b/plugins/pythonextensions/pythonextensionsplugin.cpp
@@ -39,6 +39,8 @@
#include <extensionsystem/pluginmanager.h>
#include <extensionsystem/pluginspec.h>
+#include <utils/algorithm.h>
+
#include <QDir>
#include <QIODevice>
#include <QFile>
@@ -131,23 +133,39 @@ QDir PythonExtensionsPlugin::extensionDir()
return extension_dir;
}
-QStringList PythonExtensionsPlugin::extensionList(const bool loadedOnly)
+static QVector<Extension> getExtensionList(const QDir &directory)
{
- if (loadedOnly)
- return m_loadedExtensions;
-
- QDir extension_dir = extensionDir();
- if (!extension_dir.exists())
- return QStringList();
+ if (!directory.exists())
+ return {};
+
+ QStringList entries = directory.entryList(QDir::AllDirs | QDir::NoDotAndDotDot);
+ entries.removeAll("site-packages");
+ entries.removeAll("__pycache__");
+ const QVector<Extension> packageExtensions
+ = Utils::transform<QVector>(entries, [](const QString &entry) {
+ return Extension({entry, false});
+ });
+ const QStringList fileEntries = directory.entryList({"*.py"}, QDir::Files);
+ const QVector<Extension> fileExtensions
+ = Utils::transform<QVector>(fileEntries, [](const QString &entry) {
+ return Extension({entry.left(entry.size() - 3), false});
+ });
+ return packageExtensions + fileExtensions;
+}
- QStringList extension_list = extension_dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot);
- extension_list.removeOne("site-packages");
- return extension_list;
+QVector<Extension> PythonExtensionsPlugin::extensionList()
+{
+ return extensionListRef();
}
-void PythonExtensionsPlugin::flagAsLoaded(const QString &extension)
+QVector<Extension> &PythonExtensionsPlugin::extensionListRef()
{
- m_loadedExtensions << extension;
+ static bool initialized = false;
+ if (!initialized) {
+ m_extensions = getExtensionList(extensionDir());
+ initialized = true;
+ }
+ return m_extensions;
}
QString PythonExtensionsPlugin::pythonPackagePath()
@@ -162,18 +180,21 @@ QString PythonExtensionsPlugin::pythonPackagePath()
void PythonExtensionsPlugin::initializePythonBindings()
{
// Add our custom module directory
- if (extensionDir().exists()) {
+ if (extensionDir().exists())
PyUtil::addToSysPath(extensionDir().path().toStdString());
- PyUtil::addToSysPath(pythonPackagePath().toStdString());
- }
+ // Add directory for local python packages that are installed as requirements of extensions
+ // Need to create it first if it doesn't exist, otherwise python will ignore the path
+ if (!QFile::exists(pythonPackagePath()))
+ QDir().mkpath(pythonPackagePath());
+ PyUtil::addToSysPath(pythonPackagePath().toStdString());
// Initialize the Python context and register global Qt Creator variable
- if (!PyUtil::bindShibokenModuleObject("PythonExtension", "QtCreator")) {
+ if (!PyUtil::bindCoreModules()) {
qWarning() << "Python bindings could not be initialized";
Core::MessageManager::write(Constants::MESSAGE_MANAGER_PREFIX + tr("Python bindings could not be initialized"));
return;
}
// Bind the plugin instance
- PyUtil::bindObject("PythonExtension", "PluginInstance", PyUtil::PythonExtensionsPluginType, this);
+ PyUtil::bindObject("QtCreator", "PythonExtensions", PyUtil::PythonExtensionsPluginType, this);
}
void PythonExtensionsPlugin::initializeOptionalBindings()
@@ -208,16 +229,18 @@ void PythonExtensionsPlugin::installRequirements()
if (!extension_dir.exists())
return;
- QStringList extension_list = extensionList();
- for (const QString &extension : extension_list) {
- QString extension_requirements(extension_dir.absolutePath() + "/" + extension + "/requirements.txt");
- if (QFileInfo::exists(extension_requirements) && !QFileInfo::exists(extension_requirements + ".installed")) {
- if (!PyUtil::pipInstallRequirements(
- extension_requirements.toStdString(),
- pythonPackagePath().toStdString()
- )) {
- qWarning() << "Failed to install requirements for extension" << extension;
- Core::MessageManager::write(Constants::MESSAGE_MANAGER_PREFIX + tr("Failed to install requirements for extension ") + extension);
+ QVector<Extension> extension_list = extensionListRef();
+ for (const Extension &extension : extension_list) {
+ QString extension_requirements(extension_dir.absolutePath() + "/" + extension.name
+ + "/requirements.txt");
+ if (QFileInfo::exists(extension_requirements)
+ && !QFileInfo::exists(extension_requirements + ".installed")) {
+ if (!PyUtil::pipInstallRequirements(extension_requirements.toStdString(),
+ pythonPackagePath().toStdString())) {
+ qWarning() << "Failed to install requirements for extension" << extension.name;
+ Core::MessageManager::write(Constants::MESSAGE_MANAGER_PREFIX
+ + tr("Failed to install requirements for extension ")
+ + extension.name);
}
}
}
@@ -235,22 +258,25 @@ void PythonExtensionsPlugin::initializePythonExtensions()
qDebug() << "Found Python extension directory at location" << extension_dir.absolutePath();
- QStringList extension_list = extensionList();
+ QVector<Extension> &extension_list = extensionListRef();
qDebug() << "Number of Python extensions found:" << extension_list.size();
+ int loadedCount = 0;
// Run the extension initialization code
- for (const QString &extension : extension_list) {
- qDebug() << "Trying to initialize extension" << extension;
- if (!PyUtil::runScript("import " + extension.toStdString())) {
- qWarning() << "Failed to initialize extension" << extension;
- Core::MessageManager::write(Constants::MESSAGE_MANAGER_PREFIX + tr("Failed to initialize extension ") + extension);
+ for (Extension &extension : extension_list) {
+ qDebug() << "Trying to initialize extension" << extension.name;
+ if (PyUtil::runScript("import " + extension.name.toStdString())) {
+ extension.loaded = true;
+ ++loadedCount;
} else {
- m_loadedExtensions << extension;
+ qWarning() << "Failed to initialize extension" << extension.name;
+ Core::MessageManager::write(Constants::MESSAGE_MANAGER_PREFIX
+ + tr("Failed to initialize extension ") + extension.name);
}
}
- qDebug() << "Number of Python extensions loaded:" << m_loadedExtensions.size();
+ qDebug() << "Number of Python extensions loaded:" << loadedCount;
}
} // namespace Internal
diff --git a/plugins/pythonextensions/pythonextensionsplugin.h b/plugins/pythonextensions/pythonextensionsplugin.h
index 29010d4..1a4bce3 100644
--- a/plugins/pythonextensions/pythonextensionsplugin.h
+++ b/plugins/pythonextensions/pythonextensionsplugin.h
@@ -33,6 +33,13 @@
#include <QStringList>
namespace PythonExtensions {
+
+class Extension {
+public:
+ QString name;
+ bool loaded;
+};
+
namespace Internal {
class PythonExtensionsPlugin : public ExtensionSystem::IPlugin
@@ -50,15 +57,16 @@ public:
ShutdownFlag aboutToShutdown() final;
QDir extensionDir();
- QStringList extensionList(const bool loadedOnly = false);
- void flagAsLoaded(const QString &extension);
+ QVector<Extension> extensionList();
QString pythonPackagePath();
+
private:
- QStringList m_loadedExtensions;
void initializePythonBindings();
void initializeOptionalBindings();
void installRequirements();
void initializePythonExtensions();
+ QVector<Extension> &extensionListRef();
+ QVector<Extension> m_extensions;
};
// Util functions
diff --git a/plugins/pythonextensions/pyutil.cpp b/plugins/pythonextensions/pyutil.cpp
index b563c55..b992e36 100644
--- a/plugins/pythonextensions/pyutil.cpp
+++ b/plugins/pythonextensions/pyutil.cpp
@@ -56,10 +56,10 @@ extern "C" void initQtCreator();
// These variables store all Python types exported by QtCreators bindings,
// as well as the types exported for QtWidgets.
-extern PyTypeObject **SbkPythonExtension_QtCreatorTypes;
+extern PyTypeObject **SbkQtCreatorTypes;
// This variable stores the Python module generated by Shiboken
-extern PyObject *SbkPythonExtension_QtCreatorModuleObject;
+extern PyObject *SbkQtCreatorModuleObject;
namespace PyUtil {
@@ -157,7 +157,7 @@ bool bindObject(const QString &moduleName, const QString &name, int index, void
return false;
// Generate the type
- PyTypeObject *typeObject = SbkPythonExtension_QtCreatorTypes[index];
+ PyTypeObject *typeObject = SbkQtCreatorTypes[index];
PyObject *po = Shiboken::Conversions::pointerToPython(reinterpret_cast<SbkObjectType *>(typeObject), o);
if (!po) {
@@ -169,9 +169,10 @@ bool bindObject(const QString &moduleName, const QString &name, int index, void
return bindPyObject(moduleName, name, po);
}
-bool bindShibokenModuleObject(const QString &moduleName, const QString &name)
+bool bindCoreModules()
{
- return bindPyObject(moduleName, name, SbkPythonExtension_QtCreatorModuleObject);
+ return bindSubPyObject("QtCreator", "Utils", SbkQtCreatorModuleObject)
+ && bindSubPyObject("QtCreator", "Core", SbkQtCreatorModuleObject);
}
bool bindPyObject(const QString &moduleName, const QString &name, void *obj)
diff --git a/plugins/pythonextensions/pyutil.h b/plugins/pythonextensions/pyutil.h
index 62a1622..ca58f6e 100644
--- a/plugins/pythonextensions/pyutil.h
+++ b/plugins/pythonextensions/pyutil.h
@@ -37,7 +37,7 @@ namespace PyUtil {
// Note: If modifying the bindings, check these types still align
enum QtCreatorTypes
{
- PythonExtensionsPluginType = 33, // SBK_PYTHONEXTENSIONS_INTERNAL_PYTHONEXTENSIONSPLUGIN_IDX
+ PythonExtensionsPluginType = 34, // SBK_PYTHONEXTENSIONS_INTERNAL_PYTHONEXTENSIONSPLUGIN_IDX
};
enum State
@@ -53,7 +53,7 @@ PYTHONEXTENSIONSSHARED_EXPORT bool createModule(const std::string &moduleName);
bool bindObject(const QString &moduleName, const QString &name, int index, void *o);
-bool bindShibokenModuleObject(const QString &moduleName, const QString &name);
+bool bindCoreModules();
PYTHONEXTENSIONSSHARED_EXPORT bool bindPyObject(const QString &moduleName, const QString &name, void *obj);
diff --git a/plugins/pythonextensions/typesystem_qtcreator.xml b/plugins/pythonextensions/typesystem_qtcreator.xml
index 736fe44..69f051e 100644
--- a/plugins/pythonextensions/typesystem_qtcreator.xml
+++ b/plugins/pythonextensions/typesystem_qtcreator.xml
@@ -41,12 +41,13 @@
-->
<!-- Typesystem for Qt Creator Python host plugin -->
-<typesystem package="PythonExtension.QtCreator">
+<typesystem package="QtCreator">
<!-- Load PySide QtWidgets typesystem (is this correct? yup) -->
<load-typesystem name="typesystem_widgets.xml" generate="no"/>
<namespace-type name="PythonExtensions">
+ <value-type name="Extension"/>
<namespace-type name="Internal">
<object-type name="PythonExtensionsPlugin"/>
</namespace-type>
diff --git a/python/extensionmanager/__init__.py b/python/extensionmanager/__init__.py
index 7932118..f6caa37 100644
--- a/python/extensionmanager/__init__.py
+++ b/python/extensionmanager/__init__.py
@@ -40,21 +40,22 @@
# Entry point of the Python extension
-from PythonExtension import QtCreator
+from .list import *
+
+from QtCreator import Core
from PySide2.QtCore import *
from PySide2.QtWidgets import *
-from list import *
# Actions
def showExtensionList():
- dialog = ListView(QtCreator.Core.ICore.dialogParent())
+ dialog = ListView(Core.ICore.dialogParent())
dialog.exec_()
pythonExtensionsAction = QAction("About Python Extensions...")
pythonExtensionsAction.setMenuRole(QAction.ApplicationSpecificRole)
-pythonExtensionsCommand = QtCreator.Core.ActionManager.registerAction(pythonExtensionsAction,
- "PythonExtensions.About")
+pythonExtensionsCommand = Core.ActionManager.registerAction(pythonExtensionsAction,
+ "PythonExtensions.About")
QObject.connect(pythonExtensionsAction, SIGNAL("triggered()"), showExtensionList)
-helpMenu = QtCreator.Core.ActionManager.actionContainer("QtCreator.Menu.Help")
+helpMenu = Core.ActionManager.actionContainer("QtCreator.Menu.Help")
helpMenu.addAction(pythonExtensionsCommand, "QtCreator.Group.Help.About")
diff --git a/python/extensionmanager/actions.py b/python/extensionmanager/actions.py
index 29d64cc..48e5ae4 100644
--- a/python/extensionmanager/actions.py
+++ b/python/extensionmanager/actions.py
@@ -41,7 +41,7 @@
# Functions for installing and deleting extensions
import sys, zipfile
-from PythonExtension import PluginInstance as instance
+from QtCreator import PythonExtensions
from send2trash import send2trash
def install(path):
@@ -59,14 +59,14 @@ def install(path):
return "The .zip file is malformed."
# Make sure the extension manager does not overwrite
# extensions that are already installed
- for ext in instance.extensionList():
- if extName == ext:
- return "The extension \"{}\" is already installed. Uninstall it before trying again.".format(ext)
- extZip.extractall(instance.extensionDir().absolutePath())
+ for ext in PythonExtensions.extensionList():
+ if extName == ext.name:
+ return "The extension \"{}\" is already installed. Uninstall it before trying again.".format(extName)
+ extZip.extractall(PythonExtensions.extensionDir().absolutePath())
extZip.close()
except Exception as e:
return str(e)
return True
def uninstall(ext):
- send2trash(instance.extensionDir().absolutePath() + "/" + ext)
+ send2trash(PythonExtensions.extensionDir().absolutePath() + "/" + ext)
diff --git a/python/extensionmanager/list.py b/python/extensionmanager/list.py
index 2996be3..c71b4d4 100644
--- a/python/extensionmanager/list.py
+++ b/python/extensionmanager/list.py
@@ -40,9 +40,10 @@
# Ui for extension list view
+from . import actions
+
from PySide2 import QtCore, QtWidgets, QtGui
-from PythonExtension import PluginInstance as instance
-import actions
+from QtCreator import PythonExtensions
class ExtensionList(QtWidgets.QListWidget):
def __init__(self):
@@ -55,13 +56,13 @@ class ExtensionList(QtWidgets.QListWidget):
def loadExtensionList(self):
i = 0
- for ext in instance.extensionList():
+ for ext in PythonExtensions.extensionList():
item = QtWidgets.QListWidgetItem(self)
- if not ext in instance.extensionList(True):
- item.setText(ext + " [did not load]")
+ if not ext.loaded:
+ item.setText(ext.name + " [did not load]")
item.setIcon(QtGui.QIcon.fromTheme("dialog-error"))
else:
- item.setText(ext)
+ item.setText(ext.name)
item.setIcon(QtGui.QIcon.fromTheme("applications-development"))
if i % 2 == 1:
item.setBackground(QtGui.QBrush(QtGui.QColor.fromRgb(240, 240, 240)))
@@ -78,7 +79,7 @@ class ListView(QtWidgets.QDialog):
self.layout = QtWidgets.QVBoxLayout(self)
self.label = QtWidgets.QLabel()
- self.label.setText("Manage Python extensions installed to \"{0}\".".format(instance.extensionDir().absolutePath()))
+ self.label.setText("Manage Python extensions installed to \"{0}\".".format(PythonExtensions.extensionDir().absolutePath()))
self.label.setWordWrap(True)
self.layout.addWidget(self.label)
@@ -115,7 +116,7 @@ class ListView(QtWidgets.QDialog):
selected = self.list.selectedIndexes()
if len(selected) >= 1:
selected = selected[0].row()
- ext = instance.extensionList()[selected]
+ ext = PythonExtensions.extensionList()[selected]
if ext == "extensionmanager":
QtWidgets.QMessageBox.warning(self, "Can not Uninstall", "The Extension Manager can not uninstall itself.")
else:
@@ -144,7 +145,7 @@ class ListView(QtWidgets.QDialog):
"/",
"Qt Creator Python Extensions (*.zip)"
)
- oldExtensions = list(instance.extensionList())
+ oldExtensions = list(PythonExtensions.extensionList())
result = actions.install(fileName[0])
if result == True:
QtWidgets.QMessageBox.information(