diff --git a/share/qtcreator/templates/wizards/classes/python/file.py b/share/qtcreator/templates/wizards/classes/python/file.py index 32be237c7a1..adcbc1ed2d0 100644 --- a/share/qtcreator/templates/wizards/classes/python/file.py +++ b/share/qtcreator/templates/wizards/classes/python/file.py @@ -1,30 +1,26 @@ -# -*- coding: utf-8 -*- - -@if '%{Imports}' -try: -@if '%{ImportQtCore}' - from PySide import QtCore -@endif -@if '%{ImportQtWidgets}' - from PySide import QtWidgets -@endif -@if '%{ImportQtQuick}' - from PySide import QtQuick -@endif -except: -@if '%{ImportQtCore}' - from PyQt5.QtCore import pyqtSlot as Slot - from PyQt5 import QtCore -@endif -@if '%{ImportQtWidgets}' - from PyQt5 import QtWidgets -@endif -@if '%{ImportQtQuick}' - from PyQt5 import QtQuick +# This Python file uses the following encoding: utf-8 +@if '%{Module}' === 'PySide2' + @if '%{ImportQtCore}' +from PySide2 import QtCore + @endif + @if '%{ImportQtWidgets}' +from PySide2 import QtWidgets + @endif + @if '%{ImportQtQuick}' +from PySide2 import QtQuick + @endif +@else + @if '%{ImportQtCore}' +from PyQt5 import QtCore + @endif + @if '%{ImportQtWidgets}' +from PyQt5 import QtWidgets + @endif + @if '%{ImportQtQuick}' +from PyQt5 import QtQuick + @endif @endif - -@endif @if '%{Base}' class %{Class}(%{Base}): @else diff --git a/share/qtcreator/templates/wizards/classes/python/wizard.json b/share/qtcreator/templates/wizards/classes/python/wizard.json index 64c8d8d435a..6d1d72c63bb 100644 --- a/share/qtcreator/templates/wizards/classes/python/wizard.json +++ b/share/qtcreator/templates/wizards/classes/python/wizard.json @@ -6,7 +6,7 @@ "trDescription": "Creates new Python class file.", "trDisplayName": "Python Class", "trDisplayCategory": "Python", - "iconText": "py", + "icon": "../../files/python/icon.png", "enabled": "%{JS: [ %{Plugins} ].indexOf('PythonEditor') >= 0}", "options": @@ -30,6 +30,15 @@ "type": "LineEdit", "data": { "validator": "^(?:[^\\d\\W]\\w*|)$" } }, + { + "name": "Module", + "trDisplayName": "Python module:", + "type": "ComboBox", + "data": + { + "items": ["PySide2", "PyQt5"] + } + }, { "name": "BaseCB", "trDisplayName": "Base class:", diff --git a/share/qtcreator/templates/wizards/files/python/file.py b/share/qtcreator/templates/wizards/files/python/file.py index faa18be5bbf..003f8414973 100644 --- a/share/qtcreator/templates/wizards/files/python/file.py +++ b/share/qtcreator/templates/wizards/files/python/file.py @@ -1,2 +1,4 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- +# This Python file uses the following encoding: utf-8 + +# if__name__ == "__main__": +# pass diff --git a/share/qtcreator/templates/wizards/files/python/icon.png b/share/qtcreator/templates/wizards/files/python/icon.png new file mode 100644 index 00000000000..8ab694fe7af Binary files /dev/null and b/share/qtcreator/templates/wizards/files/python/icon.png differ diff --git a/share/qtcreator/templates/wizards/files/python/icon@2x.png b/share/qtcreator/templates/wizards/files/python/icon@2x.png new file mode 100644 index 00000000000..8d1f2751860 Binary files /dev/null and b/share/qtcreator/templates/wizards/files/python/icon@2x.png differ diff --git a/share/qtcreator/templates/wizards/files/python/wizard.json b/share/qtcreator/templates/wizards/files/python/wizard.json index 32b720f3d40..d4a6cfd0126 100644 --- a/share/qtcreator/templates/wizards/files/python/wizard.json +++ b/share/qtcreator/templates/wizards/files/python/wizard.json @@ -6,7 +6,7 @@ "trDescription": "Creates an empty Python script file using UTF-8 charset.", "trDisplayName": "Python File", "trDisplayCategory": "Python", - "iconText": "py", + "icon": "icon.png", "enabled": "%{JS: [ %{Plugins} ].indexOf('PythonEditor') >= 0}", "pages" : diff --git a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/empty/icon.png b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/empty/icon.png new file mode 100644 index 00000000000..483f71196d3 Binary files /dev/null and b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/empty/icon.png differ diff --git a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/empty/icon@2x.png b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/empty/icon@2x.png new file mode 100644 index 00000000000..81beed5e239 Binary files /dev/null and b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/empty/icon@2x.png differ diff --git a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/empty/wizard.json b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/empty/wizard.json new file mode 100644 index 00000000000..0f1ce91cf78 --- /dev/null +++ b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/empty/wizard.json @@ -0,0 +1,51 @@ +{ + "version": 1, + "supportedProjectTypes": [ "PythonProject" ], + "id": "U.QtForPythonApplicationEmpty", + "category": "F.Application", + "trDescription": "Creates a Qt for Python application that only the main code for a QApplication", + "trDisplayName": "Qt for Python - Empty", + "trDisplayCategory": "Application", + "icon": "icon.png", + "enabled": "%{JS: [ %{Plugins} ].indexOf('PythonEditor') >= 0}", + "featuresRequired": [ "QtSupport.Wizards.FeatureQt.5.6" ], + + "options": + [ + { "key": "MainPyFileName", "value": "main.py" }, + { "key": "PyProjectFile", "value": "main.pyproject" } + ], + + "pages": + [ + { + "trDisplayName": "Project Location", + "trShortTitle": "Location", + "typeId": "Project" + }, + { + "trDisplayName": "Project Management", + "trShortTitle": "Summary", + "typeId": "Summary" + } + ], + "generators": + [ + { + "typeId": "File", + "data": + [ + { + "source": "../main.pyproject", + "target": "%{PyProjectFile}", + "openAsProject": true + }, + { + "source": "../main_empty.py", + "target": "%{MainPyFileName}", + "openInEditor": true + } + ] + } + ] +} diff --git a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/main.pyproject b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/main.pyproject new file mode 100644 index 00000000000..cc7a74a3468 --- /dev/null +++ b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/main.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["main.py"] +} diff --git a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/main_empty.py b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/main_empty.py new file mode 100644 index 00000000000..6cb021403b9 --- /dev/null +++ b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/main_empty.py @@ -0,0 +1,9 @@ +# This Python file uses the following encoding: utf-8 +import sys +from PySide2.QtWidgets import QApplication + + +if __name__ == "__main__": + app = QApplication([]) + # ... + sys.exit(app.exec_()) diff --git a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/main_mainwindow.py b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/main_mainwindow.py new file mode 100644 index 00000000000..fa1f92c7477 --- /dev/null +++ b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/main_mainwindow.py @@ -0,0 +1,15 @@ +# This Python file uses the following encoding: utf-8 +import sys +from PySide2.QtWidgets import QApplication, QMainWindow + + +class MainWindow(QMainWindow): + def __init__(self): + QMainWindow.__init__(self) + + +if __name__ == "__main__": + app = QApplication([]) + window = MainWindow() + window.show() + sys.exit(app.exec_()) diff --git a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/mainwindow/icon.png b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/mainwindow/icon.png new file mode 100644 index 00000000000..ba97ffd6620 Binary files /dev/null and b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/mainwindow/icon.png differ diff --git a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/mainwindow/icon@2x.png b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/mainwindow/icon@2x.png new file mode 100644 index 00000000000..4c26be65ba4 Binary files /dev/null and b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/mainwindow/icon@2x.png differ diff --git a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/mainwindow/wizard.json b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/mainwindow/wizard.json new file mode 100644 index 00000000000..c98ebb3ed46 --- /dev/null +++ b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/mainwindow/wizard.json @@ -0,0 +1,51 @@ +{ + "version": 1, + "supportedProjectTypes": [ "Qt4ProjectManager.Qt4Project" ], + "id": "U.QtForPythonApplicationWindow", + "category": "F.Application", + "trDescription": "Creates a Qt for Python application that contains an empty window.", + "trDisplayName": "Qt for Python - Window", + "trDisplayCategory": "Application", + "icon": "icon.png", + "enabled": "%{JS: [ %{Plugins} ].indexOf('PythonEditor') >= 0}", + "featuresRequired": [ "QtSupport.Wizards.FeatureQt.5.6" ], + + "options": + [ + { "key": "MainPyFileName", "value": "main.py" }, + { "key": "PyProjectFile", "value": "main.pyproject" } + ], + + "pages": + [ + { + "trDisplayName": "Project Location", + "trShortTitle": "Location", + "typeId": "Project" + }, + { + "trDisplayName": "Project Management", + "trShortTitle": "Summary", + "typeId": "Summary" + } + ], + "generators": + [ + { + "typeId": "File", + "data": + [ + { + "source": "../main.pyproject", + "target": "%{PyProjectFile}", + "openAsProject": true + }, + { + "source": "../main_mainwindow.py", + "target": "%{MainPyFileName}", + "openInEditor": true + } + ] + } + ] +} diff --git a/src/plugins/pythoneditor/PythonEditor.json.in b/src/plugins/pythoneditor/PythonEditor.json.in index b4505d55465..89269328b3d 100644 --- a/src/plugins/pythoneditor/PythonEditor.json.in +++ b/src/plugins/pythoneditor/PythonEditor.json.in @@ -28,6 +28,7 @@ \" \", \" \", \" Qt Creator Python project file\", + \" \", \" \", \" \", \"\" diff --git a/src/plugins/pythoneditor/pythoneditorplugin.cpp b/src/plugins/pythoneditor/pythoneditorplugin.cpp index 64722ef7496..dfd9c6a50ea 100644 --- a/src/plugins/pythoneditor/pythoneditorplugin.cpp +++ b/src/plugins/pythoneditor/pythoneditorplugin.cpp @@ -59,6 +59,10 @@ #include #include #include +#include +#include +#include +#include using namespace Core; using namespace ProjectExplorer; @@ -340,6 +344,35 @@ static QStringList readLines(const Utils::FileName &projectFile) return lines; } +static QStringList readLinesJson(const Utils::FileName &projectFile) +{ + const QString projectFileName = projectFile.fileName(); + QStringList lines = { projectFileName }; + + QFile file(projectFile.toString()); + if (!file.open(QFile::ReadOnly)) + return lines; + const QByteArray content = file.readAll(); + + // This assumes te project file is formed with only one field called + // 'files' that has a list associated of the files to include in the project. + if (!content.isEmpty()) { + const QJsonDocument doc = QJsonDocument::fromJson(content); + const QJsonObject obj = doc.object(); + if (obj.contains("files")) { + QJsonValue files = obj.value("files"); + QJsonArray files_array = files.toArray(); + QSet visited; + for (const auto &file : files_array) + visited.insert(file.toString()); + + lines.append(visited.toList()); + } + } + + return lines; +} + bool PythonProject::saveRawFileList(const QStringList &rawFileList) { bool result = saveRawList(rawFileList, projectFilePath().toString()); @@ -418,7 +451,15 @@ bool PythonProject::renameFile(const QString &filePath, const QString &newFilePa void PythonProject::parseProject() { m_rawListEntries.clear(); - m_rawFileList = readLines(projectFilePath()); + const Utils::FileName filePath = projectFilePath(); + // The PySide project file is JSON based + if (filePath.endsWith(".pyproject")) + m_rawFileList = readLinesJson(filePath); + // To keep compatibility with PyQt we keep the compatibility with plain + // text files as project files. + else if (filePath.endsWith(".pyqtc")) + m_rawFileList = readLines(filePath); + m_files = processEntries(m_rawFileList, &m_rawListEntries); } @@ -449,7 +490,7 @@ void PythonProject::refresh(Target *target) auto newRoot = std::make_unique(this); for (const QString &f : m_files) { const QString displayName = baseDir.relativeFilePath(f); - FileType fileType = f.endsWith(".pyqtc") ? FileType::Project : FileType::Source; + FileType fileType = f.endsWith(".pyproject") || f.endsWith(".pyqtc") ? FileType::Project : FileType::Source; newRoot->addNestedNode(std::make_unique(FileName::fromString(f), displayName, fileType)); if (fileType == FileType::Source) { diff --git a/src/tools/icons/qtcreatoricons.svg b/src/tools/icons/qtcreatoricons.svg index 24f73e097e0..86fcbb48d00 100644 --- a/src/tools/icons/qtcreatoricons.svg +++ b/src/tools/icons/qtcreatoricons.svg @@ -2645,18 +2645,21 @@ id="path5662-0" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccc" /> - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/manual/debugger/python/README.md b/tests/manual/debugger/python/README.md index 0ed136ee403..31b9e70a18e 100644 --- a/tests/manual/debugger/python/README.md +++ b/tests/manual/debugger/python/README.md @@ -1,4 +1,4 @@ -- qtcreator -load PythonEditor ./python.pyqtc +- qtcreator -load PythonEditor ./python.pyproject (or ./python.pyqtc) - Switch active runconfiguration to main.py -