From b503ea7f06147f9e64cd03d9454aafb40997c3f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristi=C3=A1n=20Maureira-Fredes?= Date: Wed, 13 Mar 2019 18:22:45 +0100 Subject: [PATCH] Add more Python features On the wizard related to Main Windows, not there are more options to specify the name of the files and classes. It's possible to Add and Remove files on Python projects that use the new .pyproject file. Improved the empty application, to template the .pyproject file and use the proper name for the file. Added the icons for file overlay. Change-Id: Iaba7feda69e0f608260b5fb1d1b04b2a42b08c2d Reviewed-by: hjk --- .../qtforpythonapplication/empty/wizard.json | 4 +- .../qtforpythonapplication/main.pyproject | 2 +- .../qtforpythonapplication/main_mainwindow.py | 18 ++++- .../mainwindow/wizard.json | 46 ++++++++++- .../projectexplorer/images/fileoverlay_py.png | Bin 0 -> 464 bytes .../images/fileoverlay_py@2x.png | Bin 0 -> 915 bytes .../projectexplorer/projectexplorer.qrc | 2 + .../projectexplorerconstants.h | 1 + .../pythoneditor/pythoneditorplugin.cpp | 74 ++++++++++++++---- .../qmakenodetreebuilder.cpp | 2 + src/tools/iconlister/iconlister.cpp | 2 + src/tools/icons/qtcreatoricons.svg | 74 +++++++++++++++--- 12 files changed, 189 insertions(+), 36 deletions(-) create mode 100644 src/plugins/projectexplorer/images/fileoverlay_py.png create mode 100644 src/plugins/projectexplorer/images/fileoverlay_py@2x.png 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 0000000000000000000000000000000000000000..d155babfc5b89dabb09693bd4783486e4f5c50c3 GIT binary patch literal 464 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7Sc;uILpV4%IBGajIv5xj zI14-?iy0XBj({-ZRBb+K1_lPn64!{5;QX|b^2DN4hVt@qz0ADq;^f4FRK5J7^x5xh zq!<_&eLY39X(UL!%1Y6uDC?rKUZ~4N>)wItcS=aIY zfoW2UmYOLtbqZy1@LUl%v_pkurf$@W(DmU)cAQ#Zz3-q$tho5eh>604q5SKHVe5|xGK#_&~c zW)S-=!Vt4=xzUkk~PHQD0(TE1av<}rxySF>l?cMEfEAp&gFG%p%jA+4sx%(JYy6U}O&o2AN Qz`(%Z>FVdQ&MBb@0Fv^(W&i*H literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..57f74a6d31887ecb6dd78dc4472c3f2012870c64 GIT binary patch literal 915 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}EX7WqAsieW95oy%9SjT% zoCO|{#S9Fx?I6t9|MX)j0|SF(iEBhjaDG}zd16s2LwR|*US?i)adKios$PCk`s{Z$ zQVa~t0-i38ArY-_r^fqC4wpDq|2%u)mMhz~xU_6tS;9_pJX=%5 zzj^u<6`lJ$@4Kb{z3(zB7Bq2bfrx+U9YxGbro=6fyU@Thf$5Wj6UW5g{Swj->dZGC zh_HyPg2ZF5-M=DW)J%~q}7vpYG^Yo*?*ldDdf|Np@7r{q_6 z^yTN; zy~PY!M!}`289P$zKK8OE)US4ztu=ct#ee(_!{hUdua%hPn`m^|Y`Q(2fl2;#!@qq; zpRuL0IryfoX5@SO=_uo}r0#8V!UE)2l*=04&cCX@CT%jG&CL+TnKkzq5)4Dd8ThtU zhMl<@x@+0XQ;RRGDYcQ=%KYZ;!!XUVgI|_$P7r!$$G4jy=G!fqhKm^!a?eITW>EG| zf3xs}wzY%*a&tZwZ(R=Q6^$3(c>gxHkAHP8#q@EIQYzDj@~Y|Hzkf&BzPb@|rt<5x z4eJ-I*J5*>*uJ}_@Y)T2=@(4Cm#4mHirPKJV3`4`_#~e1?HC`* z5H%}CJ31@7=&Vfe0_hw%Y-3(rsVz&QDZi(BPw9DLG`gd$KpZ>XMd%ODhx<8ld z-#vQpuln)BwbfB~wG}j=6Q7-g+&O4images/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"> + + + + + + + + + + + +