Wizards: Redo sub project handling

If the user tries to add a sub project the decision for the
parent project must happen directly on the intro page
to avoid asking for build system or kit information later on.
Any of these information are provided by the parent project
and can therefore be skipped in case of having a sub project.
So, move this decision to the first page and on the last page
only let the user decide to which sub node of the chosen
project the new project will be added to.
The old approach set the IsSubproject marker quite too late
to handle this appropriate, so explicitly set this already
on the first page.
For now there should be only qmake based projects which are
capable of adding sub projects at all, but this patch should
be a generalized preparation for having similar functionality
in other build systems.

Fixes: QTCREATORBUG-30281
Change-Id: I8f1de4fa05f46d68ac2ddec788840d473adb015e
Reviewed-by: Marcus Tillmanns <marcus.tillmanns@qt.io>
This commit is contained in:
Christian Stenger
2024-05-29 12:25:31 +02:00
parent 8cc58c90d3
commit 391e7ae34a
44 changed files with 262 additions and 128 deletions

View File

@@ -299,7 +299,13 @@
It is automatically assigned if you do not set it. It is automatically assigned if you do not set it.
\li \c enabled is set to \c true to show the page and to \li \c enabled is set to \c true to show the page and to
\c false to hide it. \c false to hide it. This is evaluated only once at
the time of creating the respective wizard.
\li \c skipForSubprojects can be used to skip a page of the
wizard. Useful for e.g. handling of build information.
This is evaluated only once at the time of creating the
respective wizard page.
\li \c data specifies the wizard pages. In the C++ wizard, \li \c data specifies the wizard pages. In the C++ wizard,
it specifies a \c Fields page and a \c Summary page. The it specifies a \c Fields page and a \c Summary page. The
@@ -482,7 +488,6 @@
"trDisplayName": "Kit Selection", "trDisplayName": "Kit Selection",
"trShortTitle": "Kits", "trShortTitle": "Kits",
"typeId": "Kits", "typeId": "Kits",
"enabled": "%{IsTopLevelProject}",
"data": { "projectFilePath": "%{ProFileName}" } "data": { "projectFilePath": "%{ProFileName}" }
}, },
\endcode \endcode
@@ -490,7 +495,9 @@
The page evaluates \c {%\{Platform\}} to set the platform selected in The page evaluates \c {%\{Platform\}} to set the platform selected in
\uicontrol File > \uicontrol {New Project} or \uicontrol {New File}. \uicontrol File > \uicontrol {New Project} or \uicontrol {New File}.
\note This page sets \c skipForSubprojects to \c true to suppress
the page in case it is not needed, as sub projects derive this information
from their parent project.
\section2 Project \section2 Project
@@ -511,6 +518,9 @@
The page evaluates \c InitialPath to set the initial project path. The page The page evaluates \c InitialPath to set the initial project path. The page
sets \c ProjectDirectory and \c TargetPath to the project directory. sets \c ProjectDirectory and \c TargetPath to the project directory.
Furthermore the page sets \c IsSubproject to true if the project is
explicitly added to another project. In this case \c BuildSystem will be set
to the build system of the parent project.
\section2 Summary \section2 Summary
@@ -525,8 +535,8 @@
} }
\endcode \endcode
The page sets \c IsSubproject to an empty string if this is a top-level The page sets \c IsSubproject to \c false if this is a top-level
project and to \c yes otherwise. It sets \c VersionControl to the ID of the project and to \c true otherwise. It sets \c VersionControl to the ID of the
version control system in use. version control system in use.
\section2 VcsCommand \section2 VcsCommand

View File

@@ -26,9 +26,6 @@
"key": "CMakeFileName", "key": "CMakeFileName",
"value": "%{ProjectDirectory}/CMakeLists.txt" "value": "%{ProjectDirectory}/CMakeLists.txt"
}, },
{ "key": "IsTopLevelProject",
"value": "%{JS: !'%{Exists:ProjectExplorer.Profile.Ids}' }"
},
{ "key": "MainCppName", { "key": "MainCppName",
"value": "%{JS: 'main.' + Util.preferredSuffix('text/x-c++src') }" "value": "%{JS: 'main.' + Util.preferredSuffix('text/x-c++src') }"
}, },
@@ -118,6 +115,7 @@
"trDisplayName": "Build system:", "trDisplayName": "Build system:",
"type": "ComboBox", "type": "ComboBox",
"persistenceKey": "BuildSystemType", "persistenceKey": "BuildSystemType",
"visible": "%{JS: !value('IsSubproject')}",
"data": "data":
{ {
"index": 1, "index": 1,
@@ -147,7 +145,6 @@
"trDisplayName": "Kit Selection", "trDisplayName": "Kit Selection",
"trShortTitle": "Kits", "trShortTitle": "Kits",
"typeId": "Kits", "typeId": "Kits",
"enabled": "%{IsTopLevelProject}",
"data": { "data": {
"projectFilePath": "%{ProjectFilePath}", "projectFilePath": "%{ProjectFilePath}",
"requiredFeatures": [ "%{JS: value('BuildSystem') === 'qmake' ? 'QtSupport.Wizards.FeatureQt' : 'DeviceType.Desktop' }" ] "requiredFeatures": [ "%{JS: value('BuildSystem') === 'qmake' ? 'QtSupport.Wizards.FeatureQt' : 'DeviceType.Desktop' }" ]
@@ -199,7 +196,7 @@
{ {
"source": "../../projects/git.ignore", "source": "../../projects/git.ignore",
"target": ".gitignore", "target": ".gitignore",
"condition": "%{JS: ( %{IsTopLevelProject} && value('VersionControl') === 'G.Git' )}" "condition": "%{JS: ( !value('IsSubproject') && value('VersionControl') === 'G.Git' )}"
} }
] ]
} }

View File

@@ -26,9 +26,6 @@
"key": "CMakeFileName", "key": "CMakeFileName",
"value": "%{ProjectDirectory}/CMakeLists.txt" "value": "%{ProjectDirectory}/CMakeLists.txt"
}, },
{ "key": "IsTopLevelProject",
"value": "%{JS: !'%{Exists:ProjectExplorer.Profile.Ids}' }"
},
{ "key": "MainCppName", { "key": "MainCppName",
"value": "%{JS: 'main.' + Util.preferredSuffix('text/x-c++src') }" "value": "%{JS: 'main.' + Util.preferredSuffix('text/x-c++src') }"
}, },
@@ -128,6 +125,7 @@
"trDisplayName": "Build system:", "trDisplayName": "Build system:",
"type": "ComboBox", "type": "ComboBox",
"persistenceKey": "BuildSystemType", "persistenceKey": "BuildSystemType",
"visible": "%{JS: !value('IsSubproject')}",
"data": "data":
{ {
"index": 1, "index": 1,
@@ -157,7 +155,6 @@
"trDisplayName": "Kit Selection", "trDisplayName": "Kit Selection",
"trShortTitle": "Kits", "trShortTitle": "Kits",
"typeId": "Kits", "typeId": "Kits",
"enabled": "%{IsTopLevelProject}",
"data": { "data": {
"projectFilePath": "%{ProjectFilePath}", "projectFilePath": "%{ProjectFilePath}",
"requiredFeatures": [ "%{JS: (value('Catch2NeedsQt') == 'true' || value('BuildSystem') === 'qmake') ? 'QtSupport.Wizards.FeatureQt' : 'DeviceType.Desktop' }" ] "requiredFeatures": [ "%{JS: (value('Catch2NeedsQt') == 'true' || value('BuildSystem') === 'qmake') ? 'QtSupport.Wizards.FeatureQt' : 'DeviceType.Desktop' }" ]
@@ -222,7 +219,7 @@
{ {
"source": "../../projects/git.ignore", "source": "../../projects/git.ignore",
"target": ".gitignore", "target": ".gitignore",
"condition": "%{JS: ( %{IsTopLevelProject} && value('VersionControl') === 'G.Git' )}" "condition": "%{JS: ( !value('IsSubproject') && value('VersionControl') === 'G.Git' )}"
} }
] ]
} }

View File

@@ -26,9 +26,6 @@
"key": "CMakeFileName", "key": "CMakeFileName",
"value": "%{ProjectDirectory}/CMakeLists.txt" "value": "%{ProjectDirectory}/CMakeLists.txt"
}, },
{ "key": "IsTopLevelProject",
"value": "%{JS: !'%{Exists:ProjectExplorer.Profile.Ids}' }"
},
{ "key": "MainCppName", { "key": "MainCppName",
"value": "%{JS: 'main.' + Util.preferredSuffix('text/x-c++src') }" "value": "%{JS: 'main.' + Util.preferredSuffix('text/x-c++src') }"
}, },
@@ -122,6 +119,7 @@
"trDisplayName": "Build system:", "trDisplayName": "Build system:",
"type": "ComboBox", "type": "ComboBox",
"persistenceKey": "BuildSystemType", "persistenceKey": "BuildSystemType",
"visible": "%{JS: !value('IsSubproject')}",
"data": "data":
{ {
"index": 1, "index": 1,
@@ -151,7 +149,6 @@
"trDisplayName": "Kit Selection", "trDisplayName": "Kit Selection",
"trShortTitle": "Kits", "trShortTitle": "Kits",
"typeId": "Kits", "typeId": "Kits",
"enabled": "%{IsTopLevelProject}",
"data": { "data": {
"projectFilePath": "%{ProjectFilePath}", "projectFilePath": "%{ProjectFilePath}",
"requiredFeatures": [ "%{JS: value('BuildSystem') === 'qmake' ? 'QtSupport.Wizards.FeatureQt' : 'DeviceType.Desktop' }" ] "requiredFeatures": [ "%{JS: value('BuildSystem') === 'qmake' ? 'QtSupport.Wizards.FeatureQt' : 'DeviceType.Desktop' }" ]
@@ -215,7 +212,7 @@
{ {
"source": "../../projects/git.ignore", "source": "../../projects/git.ignore",
"target": ".gitignore", "target": ".gitignore",
"condition": "%{JS: ( %{IsTopLevelProject} && value('VersionControl') === 'G.Git' )}" "condition": "%{JS: ( !value('IsSubproject') && value('VersionControl') === 'G.Git' )}"
} }
] ]
} }

View File

@@ -29,9 +29,6 @@
"key": "CMakeFileName", "key": "CMakeFileName",
"value": "%{ProjectDirectory}/CMakeLists.txt" "value": "%{ProjectDirectory}/CMakeLists.txt"
}, },
{ "key": "IsTopLevelProject",
"value": "%{JS: !'%{Exists:ProjectExplorer.Profile.Ids}' }"
},
{ {
"key": "GUARD", "key": "GUARD",
"value": "%{JS: value('TestCaseFileWithHeaderSuffix').toUpperCase().replace('.', '_') }" "value": "%{JS: value('TestCaseFileWithHeaderSuffix').toUpperCase().replace('.', '_') }"
@@ -95,6 +92,7 @@
"trDisplayName": "Build system:", "trDisplayName": "Build system:",
"type": "ComboBox", "type": "ComboBox",
"persistenceKey": "BuildSystemType", "persistenceKey": "BuildSystemType",
"visible": "%{JS: !value('IsSubproject')}",
"data": "data":
{ {
"index": 1, "index": 1,
@@ -124,7 +122,6 @@
"trDisplayName": "Kit Selection", "trDisplayName": "Kit Selection",
"trShortTitle": "Kits", "trShortTitle": "Kits",
"typeId": "Kits", "typeId": "Kits",
"enabled": "%{IsTopLevelProject}",
"data": { "data": {
"projectFilePath": "%{ProjectFilePath}", "projectFilePath": "%{ProjectFilePath}",
"requiredFeatures": [ "QtSupport.Wizards.FeatureQt", "DeviceType.Desktop" ] "requiredFeatures": [ "QtSupport.Wizards.FeatureQt", "DeviceType.Desktop" ]
@@ -171,7 +168,7 @@
{ {
"source": "../../projects/git.ignore", "source": "../../projects/git.ignore",
"target": ".gitignore", "target": ".gitignore",
"condition": "%{JS: ( %{IsTopLevelProject} && value('VersionControl') === 'G.Git' )}" "condition": "%{JS: ( !value('IsSubproject') && value('VersionControl') === 'G.Git' )}"
} }
] ]
} }

View File

@@ -29,9 +29,6 @@
"key": "CMakeFileName", "key": "CMakeFileName",
"value": "%{ProjectDirectory}/CMakeLists.txt" "value": "%{ProjectDirectory}/CMakeLists.txt"
}, },
{ "key": "IsTopLevelProject",
"value": "%{JS: !'%{Exists:ProjectExplorer.Profile.Ids}' }"
},
{ "key": "MainCppName", { "key": "MainCppName",
"value": "%{JS: 'main.' + Util.preferredSuffix('text/x-c++src') }" "value": "%{JS: 'main.' + Util.preferredSuffix('text/x-c++src') }"
}, },
@@ -90,6 +87,7 @@
"trDisplayName": "Build system:", "trDisplayName": "Build system:",
"type": "ComboBox", "type": "ComboBox",
"persistenceKey": "BuildSystemType", "persistenceKey": "BuildSystemType",
"visible": "%{JS: !value('IsSubproject')}",
"data": "data":
{ {
"index": 1, "index": 1,
@@ -119,7 +117,6 @@
"trDisplayName": "Kit Selection", "trDisplayName": "Kit Selection",
"trShortTitle": "Kits", "trShortTitle": "Kits",
"typeId": "Kits", "typeId": "Kits",
"enabled": "%{IsTopLevelProject}",
"data": { "data": {
"projectFilePath": "%{ProjectFilePath}", "projectFilePath": "%{ProjectFilePath}",
"requiredFeatures": [ "QtSupport.Wizards.FeatureQtQuick.2", "DeviceType.Desktop" ] "requiredFeatures": [ "QtSupport.Wizards.FeatureQtQuick.2", "DeviceType.Desktop" ]
@@ -183,7 +180,7 @@
{ {
"source": "../../projects/git.ignore", "source": "../../projects/git.ignore",
"target": ".gitignore", "target": ".gitignore",
"condition": "%{JS: ( %{IsTopLevelProject} && value('VersionControl') === 'G.Git' )}" "condition": "%{JS: ( !value('IsSubproject') && value('VersionControl') === 'G.Git' )}"
} }
] ]
} }

View File

@@ -78,7 +78,6 @@
"trDisplayName": "Kit Selection", "trDisplayName": "Kit Selection",
"trShortTitle": "Kits", "trShortTitle": "Kits",
"typeId": "Kits", "typeId": "Kits",
"enabled": "%{JS: !value('IsSubproject')}",
"data": "data":
{ {
"projectFilePath": "%{ProjectFile}" "projectFilePath": "%{ProjectFile}"

View File

@@ -34,7 +34,7 @@
"trDisplayName": "Define Build System", "trDisplayName": "Define Build System",
"trShortTitle": "Build System", "trShortTitle": "Build System",
"typeId": "Fields", "typeId": "Fields",
"enabled": "%{JS: !value('IsSubproject')}", "skipForSubprojects": true,
"data": "data":
[ [
{ {
@@ -81,7 +81,6 @@
"trDisplayName": "Kit Selection", "trDisplayName": "Kit Selection",
"trShortTitle": "Kits", "trShortTitle": "Kits",
"typeId": "Kits", "typeId": "Kits",
"enabled": "%{JS: !value('IsSubproject')}",
"data": { "projectFilePath": "%{ProjectFile}" } "data": { "projectFilePath": "%{ProjectFile}" }
}, },
{ {

View File

@@ -49,7 +49,7 @@
"trDisplayName": "Define Build System", "trDisplayName": "Define Build System",
"trShortTitle": "Build System", "trShortTitle": "Build System",
"typeId": "Fields", "typeId": "Fields",
"enabled": "%{JS: !value('IsSubproject')}", "skipForSubprojects": true,
"data": "data":
[ [
{ {
@@ -290,7 +290,6 @@
"trDisplayName": "Kit Selection", "trDisplayName": "Kit Selection",
"trShortTitle": "Kits", "trShortTitle": "Kits",
"typeId": "Kits", "typeId": "Kits",
"enabled": "%{JS: !value('IsSubproject')}",
"data": { "projectFilePath": "%{ProjectFile}" } "data": { "projectFilePath": "%{ProjectFile}" }
}, },
{ {

View File

@@ -29,7 +29,6 @@
"trDisplayName": "Kit Selection", "trDisplayName": "Kit Selection",
"trShortTitle": "Kits", "trShortTitle": "Kits",
"typeId": "Kits", "typeId": "Kits",
"enabled": "%{JS: !value('IsSubproject')}",
"data": { "projectFilePath": "%{ProjectFile}" } "data": { "projectFilePath": "%{ProjectFile}" }
}, },
{ {

View File

@@ -177,7 +177,6 @@
"trDisplayName":"Kit Selection", "trDisplayName":"Kit Selection",
"trShortTitle":"Kits", "trShortTitle":"Kits",
"typeId":"Kits", "typeId":"Kits",
"enabled":"%{JS: !value('IsSubproject')}",
"data":{ "data":{
"projectFilePath":"%{ProjectFile}" "projectFilePath":"%{ProjectFile}"
} }

View File

@@ -1,6 +1,6 @@
{ {
"version": 1, "version": 1,
"supportedProjectTypes": [ "CMakeProjectManager.CMakeProject", "Qbs.QbsProject", "Qt4ProjectManager.Qt4Project" ], "supportedProjectTypes": [ "MesonProjectManager.MesonProject", "CMakeProjectManager.CMakeProject", "Qbs.QbsProject", "Qt4ProjectManager.Qt4Project" ],
"id": "A.Plain C Application", "id": "A.Plain C Application",
"category": "I.Projects", "category": "I.Projects",
"trDescription": "Creates a simple C application with no dependencies.", "trDescription": "Creates a simple C application with no dependencies.",
@@ -31,7 +31,7 @@
"trDisplayName": "Define Build System", "trDisplayName": "Define Build System",
"trShortTitle": "Build System", "trShortTitle": "Build System",
"typeId": "Fields", "typeId": "Fields",
"enabled": "%{JS: !value('IsSubproject')}", "skipForSubprojects": true,
"data": "data":
[ [
{ {
@@ -73,7 +73,6 @@
"trDisplayName": "Kit Selection", "trDisplayName": "Kit Selection",
"trShortTitle": "Kits", "trShortTitle": "Kits",
"typeId": "Kits", "typeId": "Kits",
"enabled": "%{JS: !value('IsSubproject')}",
"data": { "projectFilePath": "%{ProjectFile}" } "data": { "projectFilePath": "%{ProjectFile}" }
}, },
{ {

View File

@@ -1,6 +1,6 @@
{ {
"version": 1, "version": 1,
"supportedProjectTypes": [ "CMakeProjectManager.CMakeProject", "Qbs.QbsProject", "Qt4ProjectManager.Qt4Project" ], "supportedProjectTypes": [ "MesonProjectManager.MesonProject", "CMakeProjectManager.CMakeProject", "Qbs.QbsProject", "Qt4ProjectManager.Qt4Project" ],
"id": "R.Plain Cpp Application", "id": "R.Plain Cpp Application",
"category": "I.Projects", "category": "I.Projects",
"trDescription": "Creates a simple C++ application with no dependencies.", "trDescription": "Creates a simple C++ application with no dependencies.",
@@ -31,7 +31,7 @@
"trDisplayName": "Define Build System", "trDisplayName": "Define Build System",
"trShortTitle": "Build System", "trShortTitle": "Build System",
"typeId": "Fields", "typeId": "Fields",
"enabled": "%{JS: ! %{IsSubproject}}", "skipForSubprojects": true,
"data": "data":
[ [
{ {
@@ -73,7 +73,6 @@
"trDisplayName": "Kit Selection", "trDisplayName": "Kit Selection",
"trShortTitle": "Kits", "trShortTitle": "Kits",
"typeId": "Kits", "typeId": "Kits",
"enabled": "%{JS: ! %{IsSubproject}}",
"data": { "projectFilePath": "%{ProjectFile}" } "data": { "projectFilePath": "%{ProjectFile}" }
}, },
{ {

View File

@@ -13,7 +13,6 @@
"options": "options":
[ [
{ "key": "ProFileName", "value": "%{JS: Util.fileName(value('ProjectDirectory') + '/' + value('ProjectName'), 'pro')}" }, { "key": "ProFileName", "value": "%{JS: Util.fileName(value('ProjectDirectory') + '/' + value('ProjectName'), 'pro')}" },
{ "key": "IsTopLevelProject", "value": "%{JS: !value('Exists:ProjectExplorer.Profile.Ids')}" }
], ],
"pages": "pages":
@@ -28,7 +27,6 @@
"trDisplayName": "Kit Selection", "trDisplayName": "Kit Selection",
"trShortTitle": "Kits", "trShortTitle": "Kits",
"typeId": "Kits", "typeId": "Kits",
"enabled": "%{IsTopLevelProject}",
"data": { "projectFilePath": "%{ProFileName}" } "data": { "projectFilePath": "%{ProFileName}" }
}, },
{ {
@@ -52,7 +50,7 @@
{ {
"source": "../../git.ignore", "source": "../../git.ignore",
"target": "%{ProjectDirectory}/.gitignore", "target": "%{ProjectDirectory}/.gitignore",
"condition": "%{JS: value('IsTopLevelProject') && value('VersionControl') === 'G.Git'}" "condition": "%{JS: !value('IsSubproject') && value('VersionControl') === 'G.Git'}"
} }
] ]
} }

View File

@@ -1,6 +1,6 @@
{ {
"version": 1, "version": 1,
"supportedProjectTypes": [ "Qt4ProjectManager.Qt4Project" ], "supportedProjectTypes": [ "Qt4ProjectManager.Qt4Project", "CMakeProjectManager.CMakeProject" ],
"id": "M.QtQuick2ExtensionPlugin", "id": "M.QtQuick2ExtensionPlugin",
"category": "G.Library", "category": "G.Library",
"trDescription": "Creates a C++ plugin to load Qt Quick extensions dynamically into applications using the QQmlEngine class.", "trDescription": "Creates a C++ plugin to load Qt Quick extensions dynamically into applications using the QQmlEngine class.",
@@ -43,7 +43,7 @@
"trDisplayName": "Define Build System", "trDisplayName": "Define Build System",
"trShortTitle": "Build System", "trShortTitle": "Build System",
"typeId": "Fields", "typeId": "Fields",
"enabled": "%{JS: !value('IsSubproject')}", "skipForSubprojects": true,
"data": "data":
[ [
{ {
@@ -173,7 +173,6 @@
"trDisplayName": "Kit Selection", "trDisplayName": "Kit Selection",
"trShortTitle": "Kits", "trShortTitle": "Kits",
"typeId": "Kits", "typeId": "Kits",
"enabled": "%{JS: !value('IsSubproject')}",
"data": { "data": {
"projectFilePath": "%{ProjectFile}", "projectFilePath": "%{ProjectFile}",
"requiredFeatures": [ "QtSupport.Wizards.FeatureQtQuick", "%{QtQuickFeature}" ] "requiredFeatures": [ "QtSupport.Wizards.FeatureQtQuick", "%{QtQuickFeature}" ]

View File

@@ -96,7 +96,6 @@
"trDisplayName": "Kit Selection", "trDisplayName": "Kit Selection",
"trShortTitle": "Kits", "trShortTitle": "Kits",
"typeId": "Kits", "typeId": "Kits",
"enabled": "%{JS: !value('IsSubproject')}",
"data": { "data": {
"projectFilePath": "%{ProjectFile}", "projectFilePath": "%{ProjectFile}",
"requiredFeatures": [ "QtSupport.Wizards.FeatureQtQmlCMakeApi", "%{FeatureQt}" ] "requiredFeatures": [ "QtSupport.Wizards.FeatureQtQmlCMakeApi", "%{FeatureQt}" ]

View File

@@ -42,7 +42,7 @@
"trDisplayName": "Define Build System", "trDisplayName": "Define Build System",
"trShortTitle": "Build System", "trShortTitle": "Build System",
"typeId": "Fields", "typeId": "Fields",
"enabled": "%{JS: !value('IsSubproject')}", "skipForSubprojects": true,
"data": "data":
[ [
{ {
@@ -165,7 +165,6 @@
"trDisplayName": "Kit Selection", "trDisplayName": "Kit Selection",
"trShortTitle": "Kits", "trShortTitle": "Kits",
"typeId": "Kits", "typeId": "Kits",
"enabled": "%{JS: !value('IsSubproject')}",
"data": { "data": {
"projectFilePath": "%{ProjectFile}", "projectFilePath": "%{ProjectFile}",
"requiredFeatures": [ "QtSupport.Wizards.FeatureQt", "%{QtQuickFeature}" ] "requiredFeatures": [ "QtSupport.Wizards.FeatureQt", "%{QtQuickFeature}" ]

View File

@@ -46,7 +46,6 @@
"trDisplayName": "Kit Selection", "trDisplayName": "Kit Selection",
"trShortTitle": "Kits", "trShortTitle": "Kits",
"typeId": "Kits", "typeId": "Kits",
"enabled": "%{JS: ! %{IsSubproject}}",
"data": { "data": {
"projectFilePath": "%{QmlProjectFileName}", "projectFilePath": "%{QmlProjectFileName}",
"requiredFeatures": [ "QtSupport.Wizards.FeatureQtQuickProject", "QtSupport.Wizards.FeatureQtQuick.6" ] "requiredFeatures": [ "QtSupport.Wizards.FeatureQtQuickProject", "QtSupport.Wizards.FeatureQtQuick.6" ]

View File

@@ -37,7 +37,7 @@
"trDisplayName": "Define Build System", "trDisplayName": "Define Build System",
"trShortTitle": "Build System", "trShortTitle": "Build System",
"typeId": "Fields", "typeId": "Fields",
"enabled": "%{JS: !value('IsSubproject')}", "skipForSubprojects": true,
"data": "data":
[ [
{ {
@@ -157,7 +157,6 @@
"trDisplayName": "Kit Selection", "trDisplayName": "Kit Selection",
"trShortTitle": "Kits", "trShortTitle": "Kits",
"typeId": "Kits", "typeId": "Kits",
"enabled": "%{JS: !value('IsSubproject')}",
"data": { "projectFilePath": "%{ProjectFile}" } "data": { "projectFilePath": "%{ProjectFile}" }
}, },
{ {

View File

@@ -1,6 +1,6 @@
{ {
"version": 1, "version": 1,
"supportedProjectTypes": [ "Qt4ProjectManager.Qt4Project" ], "supportedProjectTypes": [ "CMakeProjectManager.CMakeProject" ],
"id": "R.QtCreatorPlugin", "id": "R.QtCreatorPlugin",
"category": "G.Library", "category": "G.Library",
"trDescription": "Creates a custom Qt Creator plugin.", "trDescription": "Creates a custom Qt Creator plugin.",
@@ -135,7 +135,6 @@
"trDisplayName": "Kit Selection", "trDisplayName": "Kit Selection",
"trShortTitle": "Kits", "trShortTitle": "Kits",
"typeId": "Kits", "typeId": "Kits",
"enabled": "%{JS: !value('IsSubproject')}",
"data": { "projectFilePath": "%{ProjectFile}" } "data": { "projectFilePath": "%{ProjectFile}" }
}, },
{ {

View File

@@ -3,6 +3,7 @@
#include "projectintropage.h" #include "projectintropage.h"
#include "algorithm.h"
#include "fancylineedit.h" #include "fancylineedit.h"
#include "filenamevalidatinglineedit.h" #include "filenamevalidatinglineedit.h"
#include "fileutils.h" #include "fileutils.h"
@@ -52,7 +53,7 @@ public:
QRegularExpressionValidator m_projectNameValidator; QRegularExpressionValidator m_projectNameValidator;
QString m_projectNameValidatorUserMessage; QString m_projectNameValidatorUserMessage;
bool m_forceSubProject = false; bool m_forceSubProject = false;
FilePaths m_projectDirectories; QList<ProjectIntroPage::ProjectInfo> m_projectInfos;
QLabel *m_descriptionLabel; QLabel *m_descriptionLabel;
FancyLineEdit *m_nameLineEdit; FancyLineEdit *m_nameLineEdit;
@@ -81,12 +82,10 @@ ProjectIntroPage::ProjectIntroPage(QWidget *parent) :
d->m_pathChooser = new Utils::PathChooser(frame); d->m_pathChooser = new Utils::PathChooser(frame);
d->m_pathChooser->setObjectName("baseFolder"); // used by Squish d->m_pathChooser->setObjectName("baseFolder"); // used by Squish
d->m_pathChooser->setExpectedKind(PathChooser::Directory); d->m_pathChooser->setExpectedKind(PathChooser::Directory);
d->m_pathChooser->setDisabled(d->m_forceSubProject);
d->m_pathChooser->setAllowPathFromDevice(true); d->m_pathChooser->setAllowPathFromDevice(true);
d->m_projectsDirectoryCheckBox = new QCheckBox(Tr::tr("Use as default project location")); d->m_projectsDirectoryCheckBox = new QCheckBox(Tr::tr("Use as default project location"));
d->m_projectsDirectoryCheckBox->setObjectName("projectsDirectoryCheckBox"); d->m_projectsDirectoryCheckBox->setObjectName("projectsDirectoryCheckBox");
d->m_projectsDirectoryCheckBox->setDisabled(d->m_forceSubProject);
d->m_projectComboBox = new QComboBox; d->m_projectComboBox = new QComboBox;
d->m_projectComboBox->setVisible(d->m_forceSubProject); d->m_projectComboBox->setVisible(d->m_forceSubProject);
@@ -104,7 +103,7 @@ ProjectIntroPage::ProjectIntroPage(QWidget *parent) :
return validateProjectName(edit->text(), errorString); return validateProjectName(edit->text(), errorString);
}); });
d->m_projectLabel = new QLabel("Project:"); d->m_projectLabel = new QLabel(Tr::tr("Add to project:"));
d->m_projectLabel->setVisible(d->m_forceSubProject); d->m_projectLabel->setVisible(d->m_forceSubProject);
using namespace Layouting; using namespace Layouting;
@@ -200,6 +199,21 @@ bool ProjectIntroPage::validate()
return false; return false;
} }
// build system valid?
const QVariant bsVariant = property("BuildSystem");
if (bsVariant.isValid()) {
const QStringList supportedProjectTypes = wizard()->property("SupportedProjectTypes").toStringList();
if (!supportedProjectTypes.isEmpty()) {
const QVariant currentProjectsId = wizard()->property("NodeProjectId");
if (currentProjectsId.isValid()
&& !supportedProjectTypes.contains(currentProjectsId.toString())) {
displayStatusMessage(InfoLabel::Error, Tr::tr("Chosen project wizard does not "
"support the build system."));
return false;
}
}
}
// Name valid? // Name valid?
switch (d->m_nameLineEdit->state()) { switch (d->m_nameLineEdit->state()) {
case FancyLineEdit::Invalid: case FancyLineEdit::Invalid:
@@ -257,22 +271,30 @@ void ProjectIntroPage::slotActivated()
void ProjectIntroPage::onCurrentProjectIndexChanged(int index) void ProjectIntroPage::onCurrentProjectIndexChanged(int index)
{ {
if (d->m_forceSubProject) { const int available = d->m_projectInfos.size();
const int available = d->m_projectDirectories.size();
if (available == 0) if (available == 0)
return; return;
QTC_ASSERT(index < available, return); QTC_ASSERT(index < available, return);
if (index < 0) if (index < 0)
return; return;
const FilePath current = d->m_projectDirectories.at(index); d->m_forceSubProject = (index > 0);
const ProjectInfo info = d->m_projectInfos.at(index);
const FilePath current = info.projectDirectory;
const FilePath visible = d->m_pathChooser->filePath(); const FilePath visible = d->m_pathChooser->filePath();
if (visible != current && !visible.isChildOf(current)) if (visible != current && !visible.isChildOf(current))
d->m_pathChooser->setFilePath(current); d->m_pathChooser->setFilePath(current);
if (info.buildSystem.isEmpty())
setProperty("BuildSystem", QVariant());
else
setProperty("BuildSystem", info.buildSystem);
if (info.projectId.isValid())
setProperty("NodeProjectId", info.projectId.toString());
else
setProperty("NodeProjectId", QVariant());
fieldsUpdated(); fieldsUpdated();
} }
}
bool ProjectIntroPage::forceSubProject() const bool ProjectIntroPage::forceSubProject() const
{ {
@@ -284,24 +306,28 @@ void ProjectIntroPage::setForceSubProject(bool force)
d->m_forceSubProject = force; d->m_forceSubProject = force;
d->m_projectLabel->setVisible(d->m_forceSubProject); d->m_projectLabel->setVisible(d->m_forceSubProject);
d->m_projectComboBox->setVisible(d->m_forceSubProject); d->m_projectComboBox->setVisible(d->m_forceSubProject);
d->m_pathChooser->setDisabled(d->m_forceSubProject);
d->m_projectsDirectoryCheckBox->setDisabled(d->m_forceSubProject);
} }
void ProjectIntroPage::setProjectList(const QStringList &projectList) void ProjectIntroPage::setProjectInfos(const QList<ProjectInfo> &projectInfos)
{ {
// FIXME the current impl assumes a None item as first project info
d->m_projectInfos = projectInfos;
d->m_projectComboBox->clear(); d->m_projectComboBox->clear();
d->m_projectComboBox->addItems(projectList); d->m_projectComboBox->addItems(Utils::transform(projectInfos, &ProjectInfo::display));
} }
void ProjectIntroPage::setProjectDirectories(const FilePaths &directoryList) void ProjectIntroPage::setProjectIndex(int index)
{ {
d->m_projectDirectories = directoryList; d->m_projectComboBox->setCurrentIndex(
(index > d->m_projectComboBox->count() || index < 0) ? -1 : index);
} }
int ProjectIntroPage::projectIndex() const ProjectIntroPage::ProjectInfo ProjectIntroPage::currentProjectInfo() const
{ {
return d->m_projectComboBox->currentIndex(); const int index = d->m_projectComboBox->currentIndex();
if (index < 0 || index > d->m_projectInfos.size())
return {};
return d->m_projectInfos.at(index);
} }
bool ProjectIntroPage::validateProjectName(const QString &name, QString *errorMessage) bool ProjectIntroPage::validateProjectName(const QString &name, QString *errorMessage)

View File

@@ -6,6 +6,7 @@
#include "utils_global.h" #include "utils_global.h"
#include "filepath.h" #include "filepath.h"
#include "id.h"
#include "infolabel.h" #include "infolabel.h"
#include "wizardpage.h" #include "wizardpage.h"
@@ -33,9 +34,18 @@ public:
bool forceSubProject() const; bool forceSubProject() const;
void setForceSubProject(bool force); void setForceSubProject(bool force);
void setProjectList(const QStringList &projectList);
void setProjectDirectories(const FilePaths &directoryList); struct ProjectInfo
int projectIndex() const; {
QString display;
FilePath projectDirectory;
FilePath projectFile;
QString buildSystem;
Utils::Id projectId;
};
void setProjectInfos(const QList<ProjectInfo> &projectInfos);
void setProjectIndex(int index);
ProjectInfo currentProjectInfo() const;
bool validateProjectName(const QString &name, QString *errorMessage); bool validateProjectName(const QString &name, QString *errorMessage);

View File

@@ -550,7 +550,6 @@ int Wizard::nextId() const
return index; return index;
} }
} }
QTC_CHECK(false); // should not happen
return QWizard::nextId(); return QWizard::nextId();
} }

View File

@@ -109,7 +109,6 @@
"trDisplayName": "Kit Selection", "trDisplayName": "Kit Selection",
"trShortTitle": "Kits", "trShortTitle": "Kits",
"typeId": "Kits", "typeId": "Kits",
"enabled": "%{JS: !value('IsSubproject')}",
"data": { "data": {
"projectFilePath": "%{ProjectFile}" "projectFilePath": "%{ProjectFile}"
} }

View File

@@ -29,7 +29,6 @@
"trDisplayName": "Kit Selection", "trDisplayName": "Kit Selection",
"trShortTitle": "Kits", "trShortTitle": "Kits",
"typeId": "Kits", "typeId": "Kits",
"enabled": "%{JS: !value('IsSubproject')}",
"data": { "data": {
"projectFilePath": "%{CMakeFile}" "projectFilePath": "%{CMakeFile}"
} }

View File

@@ -29,7 +29,6 @@
"trDisplayName": "Kit Selection", "trDisplayName": "Kit Selection",
"trShortTitle": "Kits", "trShortTitle": "Kits",
"typeId": "Kits", "typeId": "Kits",
"enabled": "%{JS: !value('IsSubproject')}",
"data": { "data": {
"projectFilePath": "%{CMakeFile}" "projectFilePath": "%{CMakeFile}"
} }

View File

@@ -35,7 +35,6 @@
"trDisplayName": "Kit Selection", "trDisplayName": "Kit Selection",
"trShortTitle": "Kits", "trShortTitle": "Kits",
"typeId": "Kits", "typeId": "Kits",
"enabled": "%{JS: !value('IsSubproject')}",
"data": { "data": {
"projectFilePath": "%{CMakeFile}" "projectFilePath": "%{CMakeFile}"
} }

View File

@@ -101,21 +101,6 @@ void BaseProjectWizardDialog::setProjectName(const QString &name)
d->introPage->setProjectName(name); d->introPage->setProjectName(name);
} }
void BaseProjectWizardDialog::setProjectList(const QStringList &projectList)
{
d->introPage->setProjectList(projectList);
}
void BaseProjectWizardDialog::setProjectDirectories(const FilePaths &directories)
{
d->introPage->setProjectDirectories(directories);
}
void BaseProjectWizardDialog::setForceSubProject(bool force)
{
introPage()->setForceSubProject(force);
}
void BaseProjectWizardDialog::slotAccepted() void BaseProjectWizardDialog::slotAccepted()
{ {
if (d->introPage->useAsDefaultPath()) { if (d->introPage->useAsDefaultPath()) {

View File

@@ -44,9 +44,6 @@ public:
void setIntroDescription(const QString &d); void setIntroDescription(const QString &d);
void setFilePath(const Utils::FilePath &path); void setFilePath(const Utils::FilePath &path);
void setProjectName(const QString &name); void setProjectName(const QString &name);
void setProjectList(const QStringList &projectList);
void setProjectDirectories(const Utils::FilePaths &directories);
void setForceSubProject(bool force);
signals: signals:
void projectParametersChanged(const QString &projectName, const Utils::FilePath &path); void projectParametersChanged(const QString &projectName, const Utils::FilePath &path);

View File

@@ -4,10 +4,18 @@
#include "jsonprojectpage.h" #include "jsonprojectpage.h"
#include "jsonwizard.h" #include "jsonwizard.h"
#include "../buildsystem.h"
#include "../project.h"
#include "../projectexplorerconstants.h"
#include "../projectexplorertr.h" #include "../projectexplorertr.h"
#include "../projectnodes.h"
#include "../projectmanager.h"
#include "../projecttree.h"
#include "../target.h"
#include <coreplugin/documentmanager.h> #include <coreplugin/documentmanager.h>
#include <utils/algorithm.h>
#include <utils/fileutils.h> #include <utils/fileutils.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
@@ -18,6 +26,11 @@ using namespace Utils;
namespace ProjectExplorer { namespace ProjectExplorer {
namespace {
constexpr char UserPreferredPath[] = "UserPreferredPath";
constexpr char UserPreferredNode[] = "UserPreferredNode";
} // anon namespace
JsonProjectPage::JsonProjectPage(QWidget *parent) : ProjectIntroPage(parent) JsonProjectPage::JsonProjectPage(QWidget *parent) : ProjectIntroPage(parent)
{ } { }
@@ -26,7 +39,11 @@ void JsonProjectPage::initializePage()
auto wiz = qobject_cast<JsonWizard *>(wizard()); auto wiz = qobject_cast<JsonWizard *>(wizard());
QTC_ASSERT(wiz, return); QTC_ASSERT(wiz, return);
setFilePath(FilePath::fromString(wiz->stringValue(QLatin1String("InitialPath")))); setFilePath(FilePath::fromString(wiz->stringValue(QLatin1String("InitialPath"))));
if (wiz->value(QLatin1String(Constants::PROJECT_ENABLESUBPROJECT)).toBool()) {
initUiForSubProject();
connect(ProjectTree::instance(), &ProjectTree::treeChanged,
this, &JsonProjectPage::initUiForSubProject);
}
setProjectName(uniqueProjectName(filePath().toString())); setProjectName(uniqueProjectName(filePath().toString()));
} }
@@ -38,10 +55,40 @@ bool JsonProjectPage::validatePage()
Core::DocumentManager::setUseProjectsDirectory(true); Core::DocumentManager::setUseProjectsDirectory(true);
} }
Wizard *wiz = qobject_cast<JsonWizard *>(wizard());
QTC_ASSERT(wiz, return ProjectIntroPage::validatePage());
if (!forceSubProject()) {
wiz->setProperty(Constants::PROJECT_ISSUBPROJECT, false);
wiz->setProperty("BuildSystem", QVariant());
wiz->setProperty(Constants::PROJECT_POINTER, QVariant());
wiz->setProperty(Constants::PREFERRED_PROJECT_NODE, QVariant());
wiz->setProperty(Constants::PREFERRED_PROJECT_NODE_PATH, QVariant());
wiz->setSkipForSubprojects(false);
} else {
wiz->setProperty(Constants::PROJECT_ISSUBPROJECT, true);
const FilePath preferred = FilePath::fromVariant(property(UserPreferredPath));
ProjectIntroPage::ProjectInfo info = currentProjectInfo();
Project *project = ProjectManager::projectWithProjectFilePath(info.projectFile);
wiz->setProperty("BuildSystem", info.buildSystem);
wiz->setProperty(Constants::PROJECT_POINTER, QVariant::fromValue(static_cast<void *>(project)));
// only if destination path and parent project hasn't changed keep original preferred
if (!preferred.isEmpty() && preferred == filePath()) {
wiz->setProperty(Constants::PREFERRED_PROJECT_NODE, property(UserPreferredNode));
wiz->setProperty(Constants::PREFERRED_PROJECT_NODE_PATH, preferred.toVariant());
} else {
wiz->setProperty(Constants::PREFERRED_PROJECT_NODE,
project ? QVariant::fromValue(static_cast<void *>(project->rootProjectNode()))
: QVariant());
wiz->setProperty(Constants::PREFERRED_PROJECT_NODE_PATH, info.projectFile.toVariant());
}
wiz->setSkipForSubprojects(true);
}
const FilePath target = filePath().pathAppended(projectName()); const FilePath target = filePath().pathAppended(projectName());
wizard()->setProperty("ProjectDirectory", target.toString()); wiz->setProperty("ProjectDirectory", target.toString());
wizard()->setProperty("TargetPath", target.toString()); wiz->setProperty("TargetPath", target.toString());
return Utils::ProjectIntroPage::validatePage(); return Utils::ProjectIntroPage::validatePage();
} }
@@ -62,4 +109,74 @@ QString JsonProjectPage::uniqueProjectName(const QString &path)
} }
} }
// populate "Add to project" combo, gather build system info
void JsonProjectPage::initUiForSubProject()
{
auto wiz = qobject_cast<JsonWizard *>(wizard());
QTC_ASSERT(wiz, return);
Node * contextNode = nullptr;
if (void *storedNode = property(UserPreferredNode).value<void *>()) {
// fixup stored contextNode / node path
Node *node = static_cast<Node *>(storedNode);
if (auto p = ProjectManager::projectWithProjectFilePath(node->filePath()))
contextNode = p->rootProjectNode();
} else {
contextNode = static_cast<Node *>(wiz->value(Constants::PREFERRED_PROJECT_NODE).value<void *>());
if (!contextNode) {
const QVariant prefProjPath = wiz->value(Constants::PREFERRED_PROJECT_NODE_PATH);
if (prefProjPath.isValid()) {
if (auto project = ProjectManager::projectWithProjectFilePath(FilePath::fromVariant(prefProjPath)))
contextNode = project->rootProjectNode();
}
}
}
if (contextNode) {
const FilePath preferredPath = contextNode->filePath().parentDir();
setProperty(UserPreferredPath, preferredPath.toVariant());
setProperty(UserPreferredNode, QVariant::fromValue(static_cast<void *>(contextNode)));
setFilePath(preferredPath);
}
const QList<Project *> currentProjects = ProjectManager::projects();
QList<ProjectInfo> projectInfos;
projectInfos.append({Tr::tr("None"), Core::DocumentManager::projectsDirectory()});
int index = -1;
int counter = 1; // we've added None already
for (const Project *proj : currentProjects) {
ProjectNode *rootNode = proj->rootProjectNode();
if (!rootNode)
continue;
const QList<Target *> targets = proj->targets();
const BuildSystem *bs = targets.isEmpty() ? nullptr : targets.first()->buildSystem();
if (!bs)
continue;
if (bs->isParsing()) {
connect(bs, &BuildSystem::parsingFinished, this, &JsonProjectPage::initUiForSubProject,
Qt::UniqueConnection);
}
if (!rootNode->supportsAction(AddSubProject, rootNode))
continue;
ProjectInfo info;
info.projectFile = proj->projectFilePath();
info.projectId = proj->id();
info.projectDirectory = proj->rootProjectDirectory();
info.display = rootNode->displayName() + " - " + proj->projectFilePath().toUserOutput();
info.buildSystem = (bs ? bs->name() : "");
if (contextNode && contextNode->getProject() == proj)
index = counter;
projectInfos.append(info);
++counter;
}
setProjectInfos(projectInfos);
if (index == -1) // if we fail to get a valid preferred parent project, avoid illegal access
index = 0;
wiz->setValue(QLatin1String("BuildSystem"), projectInfos.at(index).buildSystem);
wiz->setValue(QLatin1String("NodeProjectId"), projectInfos.at(index).projectId.toString());
setProjectIndex(index);
setForceSubProject(true);
}
} // namespace ProjectExplorer } // namespace ProjectExplorer

View File

@@ -20,6 +20,9 @@ public:
bool validatePage() override; bool validatePage() override;
static QString uniqueProjectName(const QString &path); static QString uniqueProjectName(const QString &path);
private:
void initUiForSubProject();
}; };
} // namespace ProjectExplorer } // namespace ProjectExplorer

View File

@@ -28,7 +28,6 @@ using namespace Utils;
static char KEY_SELECTED_PROJECT[] = "SelectedProject"; static char KEY_SELECTED_PROJECT[] = "SelectedProject";
static char KEY_SELECTED_NODE[] = "SelectedFolderNode"; static char KEY_SELECTED_NODE[] = "SelectedFolderNode";
static char KEY_IS_SUBPROJECT[] = "IsSubproject";
static char KEY_VERSIONCONTROL[] = "VersionControl"; static char KEY_VERSIONCONTROL[] = "VersionControl";
static char KEY_QT_KEYWORDS_ENABLED[] = "QtKeywordsEnabled"; static char KEY_QT_KEYWORDS_ENABLED[] = "QtKeywordsEnabled";
@@ -103,7 +102,6 @@ void JsonSummaryPage::initializePage()
m_wizard->setValue(QLatin1String(KEY_SELECTED_PROJECT), QVariant()); m_wizard->setValue(QLatin1String(KEY_SELECTED_PROJECT), QVariant());
m_wizard->setValue(QLatin1String(KEY_SELECTED_NODE), QVariant()); m_wizard->setValue(QLatin1String(KEY_SELECTED_NODE), QVariant());
m_wizard->setValue(QLatin1String(KEY_IS_SUBPROJECT), false);
m_wizard->setValue(QLatin1String(KEY_VERSIONCONTROL), QString()); m_wizard->setValue(QLatin1String(KEY_VERSIONCONTROL), QString());
m_wizard->setValue(QLatin1String(KEY_QT_KEYWORDS_ENABLED), false); m_wizard->setValue(QLatin1String(KEY_QT_KEYWORDS_ENABLED), false);
@@ -133,6 +131,7 @@ void JsonSummaryPage::initializePage()
const FilePath preferredNodePath = preferredNode ? preferredNode->filePath() : FilePath{}; const FilePath preferredNodePath = preferredNode ? preferredNode->filePath() : FilePath{};
auto contextNode = findWizardContextNode(preferredNode); auto contextNode = findWizardContextNode(preferredNode);
const ProjectAction currentAction = isProject ? AddSubProject : AddNewFile; const ProjectAction currentAction = isProject ? AddSubProject : AddNewFile;
const bool isSubproject = m_wizard->value(Constants::PROJECT_ISSUBPROJECT).toBool();
auto updateProjectTree = [this, files, kind, currentAction, preferredNodePath]() { auto updateProjectTree = [this, files, kind, currentAction, preferredNodePath]() {
Node *node = currentNode(); Node *node = currentNode();
@@ -140,7 +139,8 @@ void JsonSummaryPage::initializePage()
if (auto p = ProjectManager::projectWithProjectFilePath(preferredNodePath)) if (auto p = ProjectManager::projectWithProjectFilePath(preferredNodePath))
node = p->rootProjectNode(); node = p->rootProjectNode();
} }
initializeProjectTree(findWizardContextNode(node), files, kind, currentAction); initializeProjectTree(findWizardContextNode(node), files, kind, currentAction,
m_wizard->value(Constants::PROJECT_ISSUBPROJECT).toBool());
if (m_bsConnection && sender() != ProjectTree::instance()) if (m_bsConnection && sender() != ProjectTree::instance())
disconnect(m_bsConnection); disconnect(m_bsConnection);
}; };
@@ -157,16 +157,16 @@ void JsonSummaryPage::initializePage()
} }
} }
} }
initializeProjectTree(contextNode, files, kind, currentAction); initializeProjectTree(contextNode, files, kind, currentAction, isSubproject);
// Refresh combobox on project tree changes: // Refresh combobox on project tree changes:
connect(ProjectTree::instance(), &ProjectTree::treeChanged, connect(ProjectTree::instance(), &ProjectTree::treeChanged,
this, updateProjectTree); this, updateProjectTree);
bool hideProjectUi = JsonWizard::boolFromVariant(m_hideProjectUiValue, m_wizard->expander()); bool hideProjectUi = JsonWizard::boolFromVariant(m_hideProjectUiValue, m_wizard->expander());
setProjectUiVisible(!hideProjectUi); setProjectUiVisible(!hideProjectUi);
setVersionControlUiElementsVisible(!isSubproject);
initializeVersionControls(); initializeVersionControls();
// Do a new try at initialization, now that we have real values set up: // Do a new try at initialization, now that we have real values set up:
@@ -275,7 +275,7 @@ void JsonSummaryPage::updateProjectData(FolderNode *node)
m_wizard->setValue(QLatin1String(KEY_SELECTED_PROJECT), QVariant::fromValue(project)); m_wizard->setValue(QLatin1String(KEY_SELECTED_PROJECT), QVariant::fromValue(project));
m_wizard->setValue(QLatin1String(KEY_SELECTED_NODE), QVariant::fromValue(node)); m_wizard->setValue(QLatin1String(KEY_SELECTED_NODE), QVariant::fromValue(node));
m_wizard->setValue(QLatin1String(KEY_IS_SUBPROJECT), node ? true : false); m_wizard->setValue(QLatin1String(Constants::PROJECT_ISSUBPROJECT), node ? true : false);
bool qtKeyWordsEnabled = true; bool qtKeyWordsEnabled = true;
if (ProjectTree::hasNode(node)) { if (ProjectTree::hasNode(node)) {
const ProjectNode *projectNode = node->asProjectNode(); const ProjectNode *projectNode = node->asProjectNode();

View File

@@ -45,6 +45,7 @@ const char WIZARD_PATH[] = "templates/wizards";
const char VERSION_KEY[] = "version"; const char VERSION_KEY[] = "version";
const char ENABLED_EXPRESSION_KEY[] = "enabled"; const char ENABLED_EXPRESSION_KEY[] = "enabled";
const char SKIP_FOR_SUBPROJECTS_KEY[] = "skipForSubprojects";
const char KIND_KEY[] = "kind"; const char KIND_KEY[] = "kind";
const char SUPPORTED_PROJECTS[] = "supportedProjectTypes"; const char SUPPORTED_PROJECTS[] = "supportedProjectTypes";
@@ -416,6 +417,8 @@ JsonWizardFactory::Page JsonWizardFactory::parsePage(const QVariant &value, QStr
} }
QVariant enabled = getDataValue(QLatin1String(ENABLED_EXPRESSION_KEY), data, defaultData, true); QVariant enabled = getDataValue(QLatin1String(ENABLED_EXPRESSION_KEY), data, defaultData, true);
QVariant skippable = getDataValue(QLatin1String(SKIP_FOR_SUBPROJECTS_KEY), data, defaultData,
factory->defaultSkipForSubprojects());
QVariant specifiedSubData = data.value(QLatin1String(DATA_KEY)); QVariant specifiedSubData = data.value(QLatin1String(DATA_KEY));
QVariant defaultSubData = defaultData.value(QLatin1String(DATA_KEY)); QVariant defaultSubData = defaultData.value(QLatin1String(DATA_KEY));
@@ -438,6 +441,7 @@ JsonWizardFactory::Page JsonWizardFactory::parsePage(const QVariant &value, QStr
p.index = index; p.index = index;
p.data = subData; p.data = subData;
p.enabled = enabled; p.enabled = enabled;
p.skipForSubprojects = skippable;
return p; return p;
} }
@@ -703,6 +707,8 @@ Wizard *JsonWizardFactory::runWizardImpl(const FilePath &path, QWidget *parent,
page->setTitle(data.title); page->setTitle(data.title);
page->setSubTitle(data.subTitle); page->setSubTitle(data.subTitle);
page->setProperty(Utils::SHORT_TITLE_PROPERTY, data.shortTitle); page->setProperty(Utils::SHORT_TITLE_PROPERTY, data.shortTitle);
page->setSkipForSubprojects(JsonWizard::boolFromVariant(data.skipForSubprojects,
wizard->expander()));
if (data.index >= 0) { if (data.index >= 0) {
wizard->setPage(data.index, page); wizard->setPage(data.index, page);

View File

@@ -47,6 +47,7 @@ public:
int index = -1; // page index in the wizard int index = -1; // page index in the wizard
Utils::Id typeId; Utils::Id typeId;
QVariant enabled; QVariant enabled;
QVariant skipForSubprojects;
QVariant data; QVariant data;
}; };

View File

@@ -28,6 +28,7 @@ public:
// Basic syntax check for the data taken from the wizard.json file: // Basic syntax check for the data taken from the wizard.json file:
virtual bool validateData(Utils::Id typeId, const QVariant &data, QString *errorMessage) = 0; virtual bool validateData(Utils::Id typeId, const QVariant &data, QString *errorMessage) = 0;
virtual bool defaultSkipForSubprojects() const { return false; }
protected: protected:
// This will add "PE.Wizard.Page." in front of the suffixes and set those as supported typeIds // This will add "PE.Wizard.Page." in front of the suffixes and set those as supported typeIds

View File

@@ -137,6 +137,7 @@ public:
WizardPage *create(JsonWizard *wizard, Id typeId, const QVariant &data) override; WizardPage *create(JsonWizard *wizard, Id typeId, const QVariant &data) override;
bool validateData(Id typeId, const QVariant &data, QString *errorMessage) override; bool validateData(Id typeId, const QVariant &data, QString *errorMessage) override;
bool defaultSkipForSubprojects() const override { return true; }
}; };
KitsPageFactory::KitsPageFactory() KitsPageFactory::KitsPageFactory()

View File

@@ -3544,8 +3544,10 @@ void ProjectExplorerPluginPrivate::addNewSubproject()
}); });
map.insert(QLatin1String(Constants::PROJECT_KIT_IDS), profileIds); map.insert(QLatin1String(Constants::PROJECT_KIT_IDS), profileIds);
projectType = project->id(); projectType = project->id();
map.insert(Constants::PROJECT_POINTER, QVariant::fromValue(static_cast<void *>(project)));
} }
map.insert(QLatin1String(Constants::PROJECT_ENABLESUBPROJECT), true);
ICore::showNewItemDialog(Tr::tr("New Subproject", "Title of dialog"), ICore::showNewItemDialog(Tr::tr("New Subproject", "Title of dialog"),
Utils::filtered(IWizardFactory::allWizardFactories(), Utils::filtered(IWizardFactory::allWizardFactories(),
[projectType](IWizardFactory *f) { [projectType](IWizardFactory *f) {

View File

@@ -115,6 +115,8 @@ const char PREFERRED_PROJECT_NODE_PATH[] = "ProjectExplorer.PreferredProjectPath
const char PROJECT_POINTER[] = "ProjectExplorer.Project"; const char PROJECT_POINTER[] = "ProjectExplorer.Project";
const char PROJECT_KIT_IDS[] = "ProjectExplorer.Profile.Ids"; const char PROJECT_KIT_IDS[] = "ProjectExplorer.Profile.Ids";
const char QT_KEYWORDS_ENABLED[] = "ProjectExplorer.QtKeywordsEnabled"; const char QT_KEYWORDS_ENABLED[] = "ProjectExplorer.QtKeywordsEnabled";
const char PROJECT_ISSUBPROJECT[] = "IsSubproject"; // Used inside wizard, no prefix!
const char PROJECT_ENABLESUBPROJECT[] = "ProjectExplorer.EnableSubproject";
// Build step lists ids: // Build step lists ids:
const char BUILDSTEPS_CLEAN[] = "ProjectExplorer.BuildSteps.Clean"; const char BUILDSTEPS_CLEAN[] = "ProjectExplorer.BuildSteps.Clean";

View File

@@ -117,13 +117,13 @@ void ProjectFileWizardExtension::firstExtensionPageShown(
m_context->page->initializeProjectTree(findWizardContextNode(contextNode, project, path), m_context->page->initializeProjectTree(findWizardContextNode(contextNode, project, path),
filePaths, m_context->wizard->kind(), filePaths, m_context->wizard->kind(),
projectAction); projectAction, false);
// Refresh combobox on project tree changes: // Refresh combobox on project tree changes:
connect(ProjectTree::instance(), &ProjectTree::treeChanged, connect(ProjectTree::instance(), &ProjectTree::treeChanged,
m_context->page, [this, project, path, filePaths, kind, projectAction]() { m_context->page, [this, project, path, filePaths, kind, projectAction]() {
m_context->page->initializeProjectTree( m_context->page->initializeProjectTree(
findWizardContextNode(m_context->page->currentNode(), project, path), filePaths, findWizardContextNode(m_context->page->currentNode(), project, path), filePaths,
kind, projectAction); kind, projectAction, false);
}); });
m_context->page->initializeVersionControls(); m_context->page->initializeVersionControls();

View File

@@ -4,6 +4,7 @@
#include "projectwizardpage.h" #include "projectwizardpage.h"
#include "project.h" #include "project.h"
#include "projectexplorerconstants.h"
#include "projectexplorertr.h" #include "projectexplorertr.h"
#include "projectmanager.h" #include "projectmanager.h"
#include "projectmodels.h" #include "projectmodels.h"
@@ -457,14 +458,18 @@ bool ProjectWizardPage::runVersionControl(const QList<GeneratedFile> &files, QSt
void ProjectWizardPage::initializeProjectTree(Node *context, const FilePaths &paths, void ProjectWizardPage::initializeProjectTree(Node *context, const FilePaths &paths,
IWizardFactory::WizardKind kind, IWizardFactory::WizardKind kind,
ProjectAction action) ProjectAction action, bool limitToSubproject)
{ {
m_projectComboBox->disconnect(); m_projectComboBox->disconnect();
Internal::BestNodeSelector selector(m_commonDirectory, paths); Internal::BestNodeSelector selector(m_commonDirectory, paths);
Project *parentProject = static_cast<Project *>(
wizard()->property(Constants::PROJECT_POINTER).value<void *>());
TreeItem *root = m_model.rootItem(); TreeItem *root = m_model.rootItem();
root->removeChildren(); root->removeChildren();
for (Project *project : ProjectManager::projects()) { for (Project *project : ProjectManager::projects()) {
if (limitToSubproject && project != parentProject)
continue;
if (ProjectNode *pn = project->rootProjectNode()) { if (ProjectNode *pn = project->rootProjectNode()) {
if (kind == IWizardFactory::ProjectWizard) { if (kind == IWizardFactory::ProjectWizard) {
if (Internal::AddNewTree *child = buildAddProjectTree(pn, paths.first(), context, &selector)) if (Internal::AddNewTree *child = buildAddProjectTree(pn, paths.first(), context, &selector))
@@ -479,6 +484,7 @@ void ProjectWizardPage::initializeProjectTree(Node *context, const FilePaths &pa
return Internal::compareNodes(static_cast<const Internal::AddNewTree *>(ti1)->node(), return Internal::compareNodes(static_cast<const Internal::AddNewTree *>(ti1)->node(),
static_cast<const Internal::AddNewTree *>(ti2)->node()); static_cast<const Internal::AddNewTree *>(ti2)->node());
}); });
if (!limitToSubproject)
root->prependChild(createNoneNode(&selector)); root->prependChild(createNoneNode(&selector));
// Set combobox to context node if that appears in the tree: // Set combobox to context node if that appears in the tree:
@@ -491,7 +497,9 @@ void ProjectWizardPage::initializeProjectTree(Node *context, const FilePaths &pa
setBestNode(selector.bestChoice()); setBestNode(selector.bestChoice());
setAddingSubProject(action == AddSubProject); setAddingSubProject(action == AddSubProject);
m_projectComboBox->setEnabled(m_model.rowCount(QModelIndex()) > 1); const bool enabled = m_model.rowCount(QModelIndex()) > 1
|| m_model.findItemAtLevel<1>([](TreeItem *it){ return it->hasChildren(); });
m_projectComboBox->setEnabled(enabled);
connect(m_projectComboBox, &QComboBox::currentIndexChanged, connect(m_projectComboBox, &QComboBox::currentIndexChanged,
this, &ProjectWizardPage::projectChanged); this, &ProjectWizardPage::projectChanged);
} }

View File

@@ -52,7 +52,8 @@ public:
void initializeProjectTree(Node *context, const Utils::FilePaths &paths, void initializeProjectTree(Node *context, const Utils::FilePaths &paths,
Core::IWizardFactory::WizardKind kind, Core::IWizardFactory::WizardKind kind,
ProjectAction action); ProjectAction action,
bool limitToSubproject);
void initializeVersionControls(); void initializeVersionControls();
void setProjectUiVisible(bool visible); void setProjectUiVisible(bool visible);

View File

@@ -73,6 +73,7 @@ bool SubdirsProjectWizard::postGenerateFiles(const QWizard *w, const Core::Gener
map.insert(QLatin1String(ProjectExplorer::Constants::PREFERRED_PROJECT_NODE_PATH), profileName.toVariant()); map.insert(QLatin1String(ProjectExplorer::Constants::PREFERRED_PROJECT_NODE_PATH), profileName.toVariant());
map.insert(QLatin1String(ProjectExplorer::Constants::PROJECT_KIT_IDS), map.insert(QLatin1String(ProjectExplorer::Constants::PROJECT_KIT_IDS),
Utils::transform<QStringList>(wizard->selectedKits(), &Utils::Id::toString)); Utils::transform<QStringList>(wizard->selectedKits(), &Utils::Id::toString));
map.insert(QLatin1String(ProjectExplorer::Constants::PROJECT_ENABLESUBPROJECT), true);
IWizardFactory::requestNewItemDialog(Tr::tr("New Subproject", "Title of dialog"), IWizardFactory::requestNewItemDialog(Tr::tr("New Subproject", "Title of dialog"),
Utils::filtered(Core::IWizardFactory::allWizardFactories(), Utils::filtered(Core::IWizardFactory::allWizardFactories(),
[](Core::IWizardFactory *f) { [](Core::IWizardFactory *f) {

View File

@@ -31,7 +31,7 @@
"trDisplayName": "Define Build System", "trDisplayName": "Define Build System",
"trShortTitle": "Build System", "trShortTitle": "Build System",
"typeId": "Fields", "typeId": "Fields",
"enabled": "%{JS: !value('IsSubproject')}", "skipForSubprojects": true,
"data": "data":
[ [
{ {
@@ -58,7 +58,6 @@
"trDisplayName": "Kit Selection", "trDisplayName": "Kit Selection",
"trShortTitle": "Kits", "trShortTitle": "Kits",
"typeId": "Kits", "typeId": "Kits",
"enabled": "%{JS: !value('IsSubproject')}",
"data": { "projectFilePath": "%{ProjectFile}" } "data": { "projectFilePath": "%{ProjectFile}" }
}, },
{ {

View File

@@ -1,6 +1,6 @@
{ {
"version": 1, "version": 1,
"supportedProjectTypes": [ "Qt4ProjectManager.Qt4Project" ], "supportedProjectTypes": [ "Qt4ProjectManager.Qt4Project", "CMakeProjectManager.CMakeProject" ],
"id": "E.QSRApp2_1", "id": "E.QSRApp2_1",
"category": "D.QtSafeRendererApplication", "category": "D.QtSafeRendererApplication",
"trDescription": "Creates a Qt Safe Renderer 2.1 (and newer) project with a simple UI and project setup.\n\nSupports both qmake and CMake.", "trDescription": "Creates a Qt Safe Renderer 2.1 (and newer) project with a simple UI and project setup.\n\nSupports both qmake and CMake.",
@@ -33,7 +33,7 @@
"trDisplayName": "Define Build System", "trDisplayName": "Define Build System",
"trShortTitle": "Build System", "trShortTitle": "Build System",
"typeId": "Fields", "typeId": "Fields",
"enabled": "%{JS: !value('IsSubproject')}", "skipForSubprojects": true,
"data": "data":
[ [
{ {
@@ -65,7 +65,6 @@
"trDisplayName": "Kit Selection", "trDisplayName": "Kit Selection",
"trShortTitle": "Kits", "trShortTitle": "Kits",
"typeId": "Kits", "typeId": "Kits",
"enabled": "%{JS: !value('IsSubproject')}",
"data": { "projectFilePath": "%{ProjectFile}" } "data": { "projectFilePath": "%{ProjectFile}" }
}, },
{ {