diff --git a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/empty/wizard.json b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/empty/wizard.json index 16c2646ce56..a6db89cd551 100644 --- a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/empty/wizard.json +++ b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/empty/wizard.json @@ -12,7 +12,7 @@ "options": [ - { "key": "MainPyFileName", "value": "main.py" }, + { "key": "SrcFileName", "value": "main.py" }, { "key": "PyProjectFile", "value": "main.pyproject" } ], @@ -42,7 +42,7 @@ }, { "source": "../main_empty.py", - "target": "%{MainPyFileName}", + "target": "%{SrcFileName}", "openInEditor": true } ] diff --git a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/main.pyproject b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/main.pyproject index cc7a74a3468..5c790aa7453 100644 --- a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/main.pyproject +++ b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/main.pyproject @@ -1,3 +1,3 @@ { - "files": ["main.py"] + "files": ["%{SrcFileName}"] } diff --git a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/main_mainwindow.py b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/main_mainwindow.py index fa1f92c7477..d72da8a2721 100644 --- a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/main_mainwindow.py +++ b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/main_mainwindow.py @@ -1,15 +1,29 @@ # This Python file uses the following encoding: utf-8 import sys +@if '%{BaseCB}' === 'QWidget' +from PySide2.QtWidgets import QApplication, QWidget +@endif +@if '%{BaseCB}' === 'QMainWindow' from PySide2.QtWidgets import QApplication, QMainWindow +@endif -class MainWindow(QMainWindow): +@if '%{BaseCB}' +class %{Class}(%{BaseCB}): +@else +class %{Class}: +@endif def __init__(self): +@if '%{BaseCB}' === 'QWidget' + QWidget.__init__(self) +@endif +@if '%{BaseCB}' === 'QMainWindow' QMainWindow.__init__(self) +@endif if __name__ == "__main__": app = QApplication([]) - window = MainWindow() + window = %{Class}() window.show() sys.exit(app.exec_()) diff --git a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/mainwindow/wizard.json b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/mainwindow/wizard.json index c98ebb3ed46..0fad3e3fe82 100644 --- a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/mainwindow/wizard.json +++ b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/mainwindow/wizard.json @@ -12,8 +12,8 @@ "options": [ - { "key": "MainPyFileName", "value": "main.py" }, - { "key": "PyProjectFile", "value": "main.pyproject" } + { "key": "MainPyFileName", "value": "%{ProjectDirectory}/%{SrcFileName}" }, + { "key": "PyProjectFile", "value": "%{ProjectDirectory}/%{ProjectFileName}" } ], "pages": @@ -21,7 +21,47 @@ { "trDisplayName": "Project Location", "trShortTitle": "Location", - "typeId": "Project" + "typeId": "Project", + "name": "ProjectPath" + }, + { + "trDisplayName": "Define Class", + "trShortTitle": "Details", + "typeId": "Fields", + "data" : + [ + { + "name": "Class", + "trDisplayName": "Class name:", + "mandatory": true, + "type": "LineEdit", + "data": { "validator": "(?:(?:[a-zA-Z_][a-zA-Z_0-9]*::)*[a-zA-Z_][a-zA-Z_0-9]*|)" } + }, + { + "name": "BaseCB", + "trDisplayName": "Base class:", + "type": "ComboBox", + "data": + { + "items": [ { "trKey": "", "value": "" }, + "QWidget", "QMainWindow"] + } + }, + { + "name": "SrcFileName", + "type": "LineEdit", + "trDisplayName": "Source file:", + "mandatory": true, + "data": { "trText": "%{JS: Cpp.classToFileName('%{Class}', '%{JS: Util.preferredSuffix('text/x-python')}')}" } + }, + { + "name": "ProjectFileName", + "type": "LineEdit", + "trDisplayName": "Project file:", + "mandatory": true, + "data": { "trText": "%{JS: Cpp.classToFileName('%{Class}', 'pyproject')}" } + } + ] }, { "trDisplayName": "Project Management", diff --git a/src/plugins/projectexplorer/images/fileoverlay_py.png b/src/plugins/projectexplorer/images/fileoverlay_py.png new file mode 100644 index 00000000000..d155babfc5b Binary files /dev/null and b/src/plugins/projectexplorer/images/fileoverlay_py.png differ diff --git a/src/plugins/projectexplorer/images/fileoverlay_py@2x.png b/src/plugins/projectexplorer/images/fileoverlay_py@2x.png new file mode 100644 index 00000000000..57f74a6d318 Binary files /dev/null and b/src/plugins/projectexplorer/images/fileoverlay_py@2x.png differ diff --git a/src/plugins/projectexplorer/projectexplorer.qrc b/src/plugins/projectexplorer/projectexplorer.qrc index 9eb42e7ebcd..29bda00509d 100644 --- a/src/plugins/projectexplorer/projectexplorer.qrc +++ b/src/plugins/projectexplorer/projectexplorer.qrc @@ -73,6 +73,8 @@ images/fileoverlay_cpp@2x.png images/fileoverlay_h.png images/fileoverlay_h@2x.png + images/fileoverlay_py.png + images/fileoverlay_py@2x.png images/fileoverlay_unknown.png images/fileoverlay_unknown@2x.png images/cancelbuild_overlay.png diff --git a/src/plugins/projectexplorer/projectexplorerconstants.h b/src/plugins/projectexplorer/projectexplorerconstants.h index d7a657a3b76..2732fca6177 100644 --- a/src/plugins/projectexplorer/projectexplorerconstants.h +++ b/src/plugins/projectexplorer/projectexplorerconstants.h @@ -210,6 +210,7 @@ const char FILEOVERLAY_QRC[]=":/projectexplorer/images/fileoverlay_qrc.png"; const char FILEOVERLAY_CPP[]=":/projectexplorer/images/fileoverlay_cpp.png"; const char FILEOVERLAY_H[]=":/projectexplorer/images/fileoverlay_h.png"; const char FILEOVERLAY_SCXML[]=":/projectexplorer/images/fileoverlay_scxml.png"; +const char FILEOVERLAY_PY[]=":/projectexplorer/images/fileoverlay_py.png"; const char FILEOVERLAY_UNKNOWN[]=":/projectexplorer/images/fileoverlay_unknown.png"; const char ADD_FILES_DIALOG_FILTER_HISTORY_KEY[] = "ProjectExplorer.AddFilesFilterKey"; diff --git a/src/plugins/pythoneditor/pythoneditorplugin.cpp b/src/plugins/pythoneditor/pythoneditorplugin.cpp index 4d71670e7d1..dd722283e92 100644 --- a/src/plugins/pythoneditor/pythoneditorplugin.cpp +++ b/src/plugins/pythoneditor/pythoneditorplugin.cpp @@ -94,6 +94,9 @@ public: bool needsConfiguration() const final { return false; } bool needsBuildConfigurations() const final { return false; } + bool writePyProjectFile(const QString &fileName, QString &content, + const QStringList &rawList, QString *errorMessage); + private: RestoreResult fromMap(const QVariantMap &map, QString *errorMessage) override; bool setupTarget(Target *t) override @@ -402,18 +405,61 @@ bool PythonProject::saveRawFileList(const QStringList &rawFileList) bool PythonProject::saveRawList(const QStringList &rawList, const QString &fileName) { FileChangeBlocker changeGuarg(fileName); - // Make sure we can open the file for writing - FileSaver saver(fileName, QIODevice::Text); - if (!saver.hasError()) { - QTextStream stream(saver.file()); - foreach (const QString &filePath, rawList) - stream << filePath << '\n'; - saver.setResult(&stream); + bool result = false; + + // New project file + if (fileName.endsWith(".pyproject")) { + FileSaver saver(fileName, QIODevice::ReadOnly | QIODevice::Text); + if (!saver.hasError()) { + QString content = QTextStream(saver.file()).readAll(); + if (saver.finalize(ICore::mainWindow())) { + QString errorMessage; + result = writePyProjectFile(fileName, content, rawList, &errorMessage); + if (!errorMessage.isEmpty()) + Core::MessageManager::write(errorMessage); + } + } + } else { // Old project file + FileSaver saver(fileName, QIODevice::WriteOnly | QIODevice::Text); + if (!saver.hasError()) { + QTextStream stream(saver.file()); + for (const QString &filePath : rawList) + stream << filePath << '\n'; + saver.setResult(&stream); + result = saver.finalize(ICore::mainWindow()); + } } - bool result = saver.finalize(ICore::mainWindow()); + return result; } +bool PythonProject::writePyProjectFile(const QString &fileName, QString &content, + const QStringList &rawList, QString *errorMessage) +{ + QFile file(fileName); + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { + *errorMessage = PythonProject::tr("Unable to open \"%1\" for reading: %2") + .arg(fileName, file.errorString()); + return false; + } + + // Build list of files with the current rawList for the JSON file + QString files("["); + for (const QString &f : rawList) + if (!f.endsWith(".pyproject")) + files += QString("\"%1\",").arg(f); + files = files.left(files.lastIndexOf(',')); // Removing leading comma + files += ']'; + + // Removing everything inside square parenthesis + // to replace it with the new list of files for the JSON file. + QRegularExpression pattern(R"(\[.*\])"); + content.replace(pattern, files); + file.write(content.toUtf8()); + + return true; +} + bool PythonProject::addFiles(const QStringList &filePaths) { QStringList newList = m_rawFileList; @@ -422,10 +468,7 @@ bool PythonProject::addFiles(const QStringList &filePaths) foreach (const QString &filePath, filePaths) newList.append(baseDir.relativeFilePath(filePath)); - bool result = saveRawList(newList, projectFilePath().toString()); - refresh(); - - return result; + return saveRawFileList(newList); } bool PythonProject::removeFiles(const QStringList &filePaths) @@ -701,11 +744,10 @@ bool PythonEditorPlugin::initialize(const QStringList &arguments, QString *error void PythonEditorPlugin::extensionsInitialized() { - // Initialize editor actions handler // Add MIME overlay icons (these icons displayed at Project dock panel) - const QIcon icon = QIcon::fromTheme(C_PY_MIME_ICON); - if (!icon.isNull()) - Core::FileIconProvider::registerIconOverlayForMimeType(icon, C_PY_MIMETYPE); + QString imageFile = creatorTheme()->imageFile(Theme::IconOverlayPro, + ProjectExplorer::Constants::FILEOVERLAY_PY); + FileIconProvider::registerIconOverlayForSuffix(imageFile, "py"); TaskHub::addCategory(PythonErrorTaskCategory, "Python", true); } diff --git a/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.cpp b/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.cpp index 5e7f1e78803..fbd125c43de 100644 --- a/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.cpp +++ b/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.cpp @@ -69,6 +69,8 @@ const FileTypeDataStorage fileTypeDataStorage[] = { ProjectExplorer::Constants::FILEOVERLAY_QRC, "*.qrc;" }, { FileType::QML, QT_TRANSLATE_NOOP("QmakeProjectManager::QmakePriFile", "QML"), ProjectExplorer::Constants::FILEOVERLAY_QML, "*.qml;" }, + { FileType::Source, QT_TRANSLATE_NOOP("QmakeProjectManager::QmakePriFile", "Python sources"), + ProjectExplorer::Constants::FILEOVERLAY_PY, "*.py;" }, { FileType::Unknown, QT_TRANSLATE_NOOP("QmakeProjectManager::QmakePriFile", "Other files"), ProjectExplorer::Constants::FILEOVERLAY_UNKNOWN, "*;" } }; diff --git a/src/tools/iconlister/iconlister.cpp b/src/tools/iconlister/iconlister.cpp index 509214cc255..522cd1891b7 100644 --- a/src/tools/iconlister/iconlister.cpp +++ b/src/tools/iconlister/iconlister.cpp @@ -327,6 +327,8 @@ void IconLister::addProjectExplorerIcons() ""}, {QIcon(":/projectexplorer/images/fileoverlay_h.png"), "fileoverlay_h.png", prefix, ""}, + {QIcon(":/projectexplorer/images/fileoverlay_py.png"), "fileoverlay_py.png", prefix, + ""}, {QIcon(":/projectexplorer/images/fileoverlay_unknown.png"), "fileoverlay_unknown.png", prefix, ""}, diff --git a/src/tools/icons/qtcreatoricons.svg b/src/tools/icons/qtcreatoricons.svg index 0d862c0c596..867d5adb4ce 100644 --- a/src/tools/icons/qtcreatoricons.svg +++ b/src/tools/icons/qtcreatoricons.svg @@ -14,7 +14,7 @@ height="600" id="svg2" version="1.1" - inkscape:version="0.92.1 r15371" + inkscape:version="0.92.4 5da689c313, 2019-01-14" sodipodi:docname="qtcreatoricons.svg"> @@ -561,19 +561,19 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="4" - inkscape:cx="407.31417" - inkscape:cy="170.08332" + inkscape:zoom="22.627417" + inkscape:cx="237.74824" + inkscape:cy="69.256677" inkscape:document-units="px" - inkscape:current-layer="g4718" - showgrid="true" + inkscape:current-layer="g2486" + showgrid="false" showguides="true" inkscape:guide-bbox="true" - inkscape:window-width="2880" - inkscape:window-height="1503" - inkscape:window-x="-13" - inkscape:window-y="527" - inkscape:window-maximized="1" + inkscape:window-width="1900" + inkscape:window-height="1042" + inkscape:window-x="2570" + inkscape:window-y="28" + inkscape:window-maximized="0" inkscape:snap-grids="true"> + + + + + + + + + + + +