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 <hjk@qt.io>
This commit is contained in:
Cristián Maureira-Fredes
2019-03-13 18:22:45 +01:00
committed by hjk
parent 1660d3301a
commit b503ea7f06
12 changed files with 189 additions and 36 deletions

View File

@@ -12,7 +12,7 @@
"options": "options":
[ [
{ "key": "MainPyFileName", "value": "main.py" }, { "key": "SrcFileName", "value": "main.py" },
{ "key": "PyProjectFile", "value": "main.pyproject" } { "key": "PyProjectFile", "value": "main.pyproject" }
], ],
@@ -42,7 +42,7 @@
}, },
{ {
"source": "../main_empty.py", "source": "../main_empty.py",
"target": "%{MainPyFileName}", "target": "%{SrcFileName}",
"openInEditor": true "openInEditor": true
} }
] ]

View File

@@ -1,3 +1,3 @@
{ {
"files": ["main.py"] "files": ["%{SrcFileName}"]
} }

View File

@@ -1,15 +1,29 @@
# This Python file uses the following encoding: utf-8 # This Python file uses the following encoding: utf-8
import sys import sys
@if '%{BaseCB}' === 'QWidget'
from PySide2.QtWidgets import QApplication, QWidget
@endif
@if '%{BaseCB}' === 'QMainWindow'
from PySide2.QtWidgets import QApplication, QMainWindow from PySide2.QtWidgets import QApplication, QMainWindow
@endif
class MainWindow(QMainWindow): @if '%{BaseCB}'
class %{Class}(%{BaseCB}):
@else
class %{Class}:
@endif
def __init__(self): def __init__(self):
@if '%{BaseCB}' === 'QWidget'
QWidget.__init__(self)
@endif
@if '%{BaseCB}' === 'QMainWindow'
QMainWindow.__init__(self) QMainWindow.__init__(self)
@endif
if __name__ == "__main__": if __name__ == "__main__":
app = QApplication([]) app = QApplication([])
window = MainWindow() window = %{Class}()
window.show() window.show()
sys.exit(app.exec_()) sys.exit(app.exec_())

View File

@@ -12,8 +12,8 @@
"options": "options":
[ [
{ "key": "MainPyFileName", "value": "main.py" }, { "key": "MainPyFileName", "value": "%{ProjectDirectory}/%{SrcFileName}" },
{ "key": "PyProjectFile", "value": "main.pyproject" } { "key": "PyProjectFile", "value": "%{ProjectDirectory}/%{ProjectFileName}" }
], ],
"pages": "pages":
@@ -21,7 +21,47 @@
{ {
"trDisplayName": "Project Location", "trDisplayName": "Project Location",
"trShortTitle": "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": "<Custom>", "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", "trDisplayName": "Project Management",

Binary file not shown.

After

Width:  |  Height:  |  Size: 464 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 915 B

View File

@@ -73,6 +73,8 @@
<file>images/fileoverlay_cpp@2x.png</file> <file>images/fileoverlay_cpp@2x.png</file>
<file>images/fileoverlay_h.png</file> <file>images/fileoverlay_h.png</file>
<file>images/fileoverlay_h@2x.png</file> <file>images/fileoverlay_h@2x.png</file>
<file>images/fileoverlay_py.png</file>
<file>images/fileoverlay_py@2x.png</file>
<file>images/fileoverlay_unknown.png</file> <file>images/fileoverlay_unknown.png</file>
<file>images/fileoverlay_unknown@2x.png</file> <file>images/fileoverlay_unknown@2x.png</file>
<file>images/cancelbuild_overlay.png</file> <file>images/cancelbuild_overlay.png</file>

View File

@@ -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_CPP[]=":/projectexplorer/images/fileoverlay_cpp.png";
const char FILEOVERLAY_H[]=":/projectexplorer/images/fileoverlay_h.png"; const char FILEOVERLAY_H[]=":/projectexplorer/images/fileoverlay_h.png";
const char FILEOVERLAY_SCXML[]=":/projectexplorer/images/fileoverlay_scxml.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 FILEOVERLAY_UNKNOWN[]=":/projectexplorer/images/fileoverlay_unknown.png";
const char ADD_FILES_DIALOG_FILTER_HISTORY_KEY[] = "ProjectExplorer.AddFilesFilterKey"; const char ADD_FILES_DIALOG_FILTER_HISTORY_KEY[] = "ProjectExplorer.AddFilesFilterKey";

View File

@@ -94,6 +94,9 @@ public:
bool needsConfiguration() const final { return false; } bool needsConfiguration() const final { return false; }
bool needsBuildConfigurations() const final { return false; } bool needsBuildConfigurations() const final { return false; }
bool writePyProjectFile(const QString &fileName, QString &content,
const QStringList &rawList, QString *errorMessage);
private: private:
RestoreResult fromMap(const QVariantMap &map, QString *errorMessage) override; RestoreResult fromMap(const QVariantMap &map, QString *errorMessage) override;
bool setupTarget(Target *t) 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) bool PythonProject::saveRawList(const QStringList &rawList, const QString &fileName)
{ {
FileChangeBlocker changeGuarg(fileName); FileChangeBlocker changeGuarg(fileName);
// Make sure we can open the file for writing bool result = false;
FileSaver saver(fileName, QIODevice::Text);
if (!saver.hasError()) { // New project file
QTextStream stream(saver.file()); if (fileName.endsWith(".pyproject")) {
foreach (const QString &filePath, rawList) FileSaver saver(fileName, QIODevice::ReadOnly | QIODevice::Text);
stream << filePath << '\n'; if (!saver.hasError()) {
saver.setResult(&stream); 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; 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) bool PythonProject::addFiles(const QStringList &filePaths)
{ {
QStringList newList = m_rawFileList; QStringList newList = m_rawFileList;
@@ -422,10 +468,7 @@ bool PythonProject::addFiles(const QStringList &filePaths)
foreach (const QString &filePath, filePaths) foreach (const QString &filePath, filePaths)
newList.append(baseDir.relativeFilePath(filePath)); newList.append(baseDir.relativeFilePath(filePath));
bool result = saveRawList(newList, projectFilePath().toString()); return saveRawFileList(newList);
refresh();
return result;
} }
bool PythonProject::removeFiles(const QStringList &filePaths) bool PythonProject::removeFiles(const QStringList &filePaths)
@@ -701,11 +744,10 @@ bool PythonEditorPlugin::initialize(const QStringList &arguments, QString *error
void PythonEditorPlugin::extensionsInitialized() void PythonEditorPlugin::extensionsInitialized()
{ {
// Initialize editor actions handler
// Add MIME overlay icons (these icons displayed at Project dock panel) // Add MIME overlay icons (these icons displayed at Project dock panel)
const QIcon icon = QIcon::fromTheme(C_PY_MIME_ICON); QString imageFile = creatorTheme()->imageFile(Theme::IconOverlayPro,
if (!icon.isNull()) ProjectExplorer::Constants::FILEOVERLAY_PY);
Core::FileIconProvider::registerIconOverlayForMimeType(icon, C_PY_MIMETYPE); FileIconProvider::registerIconOverlayForSuffix(imageFile, "py");
TaskHub::addCategory(PythonErrorTaskCategory, "Python", true); TaskHub::addCategory(PythonErrorTaskCategory, "Python", true);
} }

View File

@@ -69,6 +69,8 @@ const FileTypeDataStorage fileTypeDataStorage[] = {
ProjectExplorer::Constants::FILEOVERLAY_QRC, "*.qrc;" }, ProjectExplorer::Constants::FILEOVERLAY_QRC, "*.qrc;" },
{ FileType::QML, QT_TRANSLATE_NOOP("QmakeProjectManager::QmakePriFile", "QML"), { FileType::QML, QT_TRANSLATE_NOOP("QmakeProjectManager::QmakePriFile", "QML"),
ProjectExplorer::Constants::FILEOVERLAY_QML, "*.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"), { FileType::Unknown, QT_TRANSLATE_NOOP("QmakeProjectManager::QmakePriFile", "Other files"),
ProjectExplorer::Constants::FILEOVERLAY_UNKNOWN, "*;" } ProjectExplorer::Constants::FILEOVERLAY_UNKNOWN, "*;" }
}; };

View File

@@ -327,6 +327,8 @@ void IconLister::addProjectExplorerIcons()
""}, ""},
{QIcon(":/projectexplorer/images/fileoverlay_h.png"), "fileoverlay_h.png", prefix, {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, {QIcon(":/projectexplorer/images/fileoverlay_unknown.png"), "fileoverlay_unknown.png", prefix,
""}, ""},

View File

@@ -14,7 +14,7 @@
height="600" height="600"
id="svg2" id="svg2"
version="1.1" version="1.1"
inkscape:version="0.92.1 r15371" inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="qtcreatoricons.svg"> sodipodi:docname="qtcreatoricons.svg">
<defs <defs
id="defs4"> id="defs4">
@@ -561,19 +561,19 @@
borderopacity="1.0" borderopacity="1.0"
inkscape:pageopacity="0.0" inkscape:pageopacity="0.0"
inkscape:pageshadow="2" inkscape:pageshadow="2"
inkscape:zoom="4" inkscape:zoom="22.627417"
inkscape:cx="407.31417" inkscape:cx="237.74824"
inkscape:cy="170.08332" inkscape:cy="69.256677"
inkscape:document-units="px" inkscape:document-units="px"
inkscape:current-layer="g4718" inkscape:current-layer="g2486"
showgrid="true" showgrid="false"
showguides="true" showguides="true"
inkscape:guide-bbox="true" inkscape:guide-bbox="true"
inkscape:window-width="2880" inkscape:window-width="1900"
inkscape:window-height="1503" inkscape:window-height="1042"
inkscape:window-x="-13" inkscape:window-x="2570"
inkscape:window-y="527" inkscape:window-y="28"
inkscape:window-maximized="1" inkscape:window-maximized="0"
inkscape:snap-grids="true"> inkscape:snap-grids="true">
<inkscape:grid <inkscape:grid
type="xygrid" type="xygrid"
@@ -612,7 +612,7 @@
inkscape:locked="false" /> inkscape:locked="false" />
<sodipodi:guide <sodipodi:guide
orientation="0,1" orientation="0,1"
position="0,80" position="232,80"
id="guide4545" id="guide4545"
inkscape:locked="false" /> inkscape:locked="false" />
<sodipodi:guide <sodipodi:guide
@@ -10120,6 +10120,56 @@
x="753" x="753"
y="48" /> y="48" />
</g> </g>
<g
transform="translate(116)"
id="src/plugins/projectexplorer/images/fileoverlay_py"
inkscape:export-filename="/home/crmaurei/dev/qt-creator/src/plugins/projectexplorer/images/fileoverlay_py.png"
inkscape:export-xdpi="192"
inkscape:export-ydpi="192">
<g
id="g6226">
<g
id="g2486">
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4941-3-5-0-5-4-6"
width="16"
height="16"
x="96"
y="520"
inkscape:export-filename="/home/crmaurei/dev/qt-creator/src/plugins/projectexplorer/images/fileoverlay_py@2x.png"
inkscape:export-xdpi="192"
inkscape:export-ydpi="192" />
<path
style="opacity:0.75;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 105.5,528 c -0.28499,-0.0813 -1.57177,-0.0662 -1.87546,-0.0966 -0.93436,-0.0937 -1.86374,-0.15612 -1.85285,0.50571 l 0.0998,6.06281 c 0.6725,0.36107 1.28181,0.15078 1.8106,0.0591 0.25808,-0.0786 -0.006,-1.57127 0.42781,-1.58114 0.18464,-0.004 0.86225,-0.10358 1.56983,-0.17361 0.77225,-0.80046 0.63718,-1.17577 1.16924,-0.0679 0.47064,0.005 0.78828,0.0743 0.71439,0.27346 -0.46327,1.26186 0.081,1.53464 0.54464,1.61459 0.54739,0.0944 1.41432,0.01 1.73732,-1.05221 L 111,528.5 c -0.10018,-0.36741 -0.62147,-0.77874 -1.06629,-0.71274 L 108.5,528 H 107 Z"
id="path5937-7"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cssccscccsccsccc"
inkscape:export-filename="/home/crmaurei/dev/qt-creator/src/plugins/projectexplorer/images/fileoverlay_py@2x.png"
inkscape:export-xdpi="192"
inkscape:export-ydpi="192" />
<g
aria-label="py"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.49317265px;line-height:1.25;font-family:Titillium;-inkscape-font-specification:Titillium;letter-spacing:0px;word-spacing:0px;fill:#2e5e84;fill-opacity:1;stroke:none;stroke-width:0.02123293;stroke-miterlimit:4;stroke-dasharray:none"
id="text6220"
inkscape:export-filename="/home/crmaurei/dev/qt-creator/src/plugins/projectexplorer/images/fileoverlay_py@2x.png"
inkscape:export-xdpi="192"
inkscape:export-ydpi="192">
<path
d="m 102.23001,534.27502 h 1.13808 v -1.74959 c 0,0 0.39069,0.0679 0.70494,0.0679 1.29945,0 1.92795,-0.45014 1.92795,-2.25918 0,-1.57973 -0.55206,-2.19124 -1.67316,-2.19124 -0.41616,0 -0.96822,0.33123 -0.96822,0.33123 v -0.22931 h -1.12959 v 0.69094 z m 1.87699,-5.11289 c 0.45014,0 0.7389,0.31425 0.7389,1.17206 0,0.90028 -0.17835,1.27398 -0.85781,1.27398 -0.23781,0 -0.62,-0.051 -0.62,-0.051 v -2.22522 c 0,0 0.39069,-0.16986 0.73891,-0.16986 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:Titillium;-inkscape-font-specification:'Titillium Bold';fill:#2e5e84;fill-opacity:1;stroke-width:0.02123293"
id="path2488"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccsssccccccsscccc" />
<path
d="m 106.40108,528.24487 1.04466,4.24659 h 0.79836 l -0.46712,1.78356 h 1.1126 l 1.4948,-6.03015 h -1.1211 l -0.77288,3.27836 h -0.19534 l -0.77288,-3.27836 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:Titillium;-inkscape-font-specification:'Titillium Bold';fill:#2e5e84;fill-opacity:1;stroke-width:0.02123293"
id="path2490" />
</g>
</g>
</g>
</g>
</g> </g>
<g <g
id="src/plugins/vcsbase/images/submit_arrow"> id="src/plugins/vcsbase/images/submit_arrow">

Before

Width:  |  Height:  |  Size: 370 KiB

After

Width:  |  Height:  |  Size: 374 KiB