Наша сборка Qt VS Tools
giy
2022-06-13 175679ae608f0b295d761588d332f635b21bdf30
Инициализация исходников QtVsTools v2.8.1
594 files added
1 files modified
98060 ■■■■■ changed files
.editorconfig 219 ●●●●● patch | view | raw | blame | history
.gitignore 177 ●●●● patch | view | raw | blame | history
Changelog 724 ●●●●● patch | view | raw | blame | history
LICENSE.GPL3-EXCEPT 704 ●●●●● patch | view | raw | blame | history
QMakeFileReader/evalhandler.cpp 54 ●●●●● patch | view | raw | blame | history
QMakeFileReader/evalhandler.h 46 ●●●●● patch | view | raw | blame | history
QMakeFileReader/evaluator/README 6 ●●●●● patch | view | raw | blame | history
QMakeFileReader/evaluator/evaluator.pri 22 ●●●●● patch | view | raw | blame | history
QMakeFileReader/evaluator/ioutils.cpp 155 ●●●●● patch | view | raw | blame | history
QMakeFileReader/evaluator/ioutils.h 70 ●●●●● patch | view | raw | blame | history
QMakeFileReader/evaluator/proitems.cpp 450 ●●●●● patch | view | raw | blame | history
QMakeFileReader/evaluator/proitems.h 384 ●●●●● patch | view | raw | blame | history
QMakeFileReader/evaluator/qmake_global.h 55 ●●●●● patch | view | raw | blame | history
QMakeFileReader/evaluator/qmakebuiltins.cpp 1635 ●●●●● patch | view | raw | blame | history
QMakeFileReader/evaluator/qmakeevaluator.cpp 2027 ●●●●● patch | view | raw | blame | history
QMakeFileReader/evaluator/qmakeevaluator.h 294 ●●●●● patch | view | raw | blame | history
QMakeFileReader/evaluator/qmakeevaluator_p.h 94 ●●●●● patch | view | raw | blame | history
QMakeFileReader/evaluator/qmakeglobals.cpp 355 ●●●●● patch | view | raw | blame | history
QMakeFileReader/evaluator/qmakeglobals.h 160 ●●●●● patch | view | raw | blame | history
QMakeFileReader/evaluator/qmakeparser.cpp 1212 ●●●●● patch | view | raw | blame | history
QMakeFileReader/evaluator/qmakeparser.h 210 ●●●●● patch | view | raw | blame | history
QMakeFileReader/main.cpp 87 ●●●●● patch | view | raw | blame | history
QMakeFileReader/qmakedataprovider.cpp 142 ●●●●● patch | view | raw | blame | history
QMakeFileReader/qmakedataprovider.h 56 ●●●●● patch | view | raw | blame | history
QMakeFileReader/qmakefilereader.ico patch | view | raw | blame | history
QMakeFileReader/qmakefilereader.rc 1 ●●●● patch | view | raw | blame | history
QMakeFileReader/qmakefilereader.vcxproj 257 ●●●●● patch | view | raw | blame | history
QMakeFileReader/qmakefilereader.vcxproj.filters 86 ●●●●● patch | view | raw | blame | history
QrcEditor/main.cpp 40 ●●●●● patch | view | raw | blame | history
QrcEditor/mainwindow.cpp 183 ●●●●● patch | view | raw | blame | history
QrcEditor/mainwindow.h 65 ●●●●● patch | view | raw | blame | history
QrcEditor/qrceditor.ico patch | view | raw | blame | history
QrcEditor/qrceditor.rc 1 ●●●● patch | view | raw | blame | history
QrcEditor/qrceditor.vcxproj 253 ●●●●● patch | view | raw | blame | history
QrcEditor/qrceditor.vcxproj.filters 80 ●●●●● patch | view | raw | blame | history
QrcEditor/shared/qrceditor.cpp 423 ●●●●● patch | view | raw | blame | history
QrcEditor/shared/qrceditor.h 105 ●●●●● patch | view | raw | blame | history
QrcEditor/shared/qrceditor.pri 19 ●●●●● patch | view | raw | blame | history
QrcEditor/shared/qrceditor.ui 127 ●●●●● patch | view | raw | blame | history
QrcEditor/shared/resourcefile.cpp 992 ●●●●● patch | view | raw | blame | history
QrcEditor/shared/resourcefile_p.h 262 ●●●●● patch | view | raw | blame | history
QrcEditor/shared/resourceview.cpp 663 ●●●●● patch | view | raw | blame | history
QrcEditor/shared/resourceview.h 180 ●●●●● patch | view | raw | blame | history
QrcEditor/shared/undocommands.cpp 185 ●●●●● patch | view | raw | blame | history
QrcEditor/shared/undocommands_p.h 160 ●●●●● patch | view | raw | blame | history
QtCppConfig.props 27 ●●●●● patch | view | raw | blame | history
QtMSBuild/ITaskLoggingHelper.cs 263 ●●●●● patch | view | raw | blame | history
QtMSBuild/Properties/AssemblyInfo.cs 68 ●●●●● patch | view | raw | blame | history
QtMSBuild/QtMSBuild.csproj 432 ●●●●● patch | view | raw | blame | history
QtMSBuild/QtMsBuild/Qt.props 59 ●●●●● patch | view | raw | blame | history
QtMSBuild/QtMsBuild/deploy/qt_import.props 46 ●●●●● patch | view | raw | blame | history
QtMSBuild/QtMsBuild/deploy/qtdeploy.props 73 ●●●●● patch | view | raw | blame | history
QtMSBuild/QtMsBuild/deploy/qtdeploy.targets 342 ●●●●● patch | view | raw | blame | history
QtMSBuild/QtMsBuild/deploy/qtdeploy.xml 366 ●●●●● patch | view | raw | blame | history
QtMSBuild/QtMsBuild/moc/qt_import.props 46 ●●●●● patch | view | raw | blame | history
QtMSBuild/QtMsBuild/moc/qtmoc.props 83 ●●●●● patch | view | raw | blame | history
QtMSBuild/QtMsBuild/moc/qtmoc.targets 510 ●●●●● patch | view | raw | blame | history
QtMSBuild/QtMsBuild/moc/qtmoc.xml 316 ●●●●● patch | view | raw | blame | history
QtMSBuild/QtMsBuild/moc/qtmoc_cl.targets_TT 157 ●●●●● patch | view | raw | blame | history
QtMSBuild/QtMsBuild/moc/qtmoc_v3.xml_TT 356 ●●●●● patch | view | raw | blame | history
QtMSBuild/QtMsBuild/qml/qt_import.props 50 ●●●●● patch | view | raw | blame | history
QtMSBuild/QtMsBuild/qml/qtqml.props 59 ●●●●● patch | view | raw | blame | history
QtMSBuild/QtMsBuild/qml/qtqml.targets 80 ●●●●● patch | view | raw | blame | history
QtMSBuild/QtMsBuild/qml/qtqml_cache.props 84 ●●●●● patch | view | raw | blame | history
QtMSBuild/QtMsBuild/qml/qtqml_cache.targets 625 ●●●●● patch | view | raw | blame | history
QtMSBuild/QtMsBuild/qml/qtqml_static.props 56 ●●●●● patch | view | raw | blame | history
QtMSBuild/QtMsBuild/qml/qtqml_static.targets 342 ●●●●● patch | view | raw | blame | history
QtMSBuild/QtMsBuild/qt.targets 77 ●●●●● patch | view | raw | blame | history
QtMSBuild/QtMsBuild/qt_defaults.props 127 ●●●●● patch | view | raw | blame | history
QtMSBuild/QtMsBuild/qt_globals.targets 636 ●●●●● patch | view | raw | blame | history
QtMSBuild/QtMsBuild/qt_private.props 233 ●●●●● patch | view | raw | blame | history
QtMSBuild/QtMsBuild/qt_settings.targets 42 ●●●●● patch | view | raw | blame | history
QtMSBuild/QtMsBuild/qt_settings.xml 148 ●●●●● patch | view | raw | blame | history
QtMSBuild/QtMsBuild/qt_tasks.targets_TT 212 ●●●●● patch | view | raw | blame | history
QtMSBuild/QtMsBuild/qt_vars.targets 594 ●●●●● patch | view | raw | blame | history
QtMSBuild/QtMsBuild/rcc/qt_import.props 46 ●●●●● patch | view | raw | blame | history
QtMSBuild/QtMsBuild/rcc/qtrcc.props 85 ●●●●● patch | view | raw | blame | history
QtMSBuild/QtMsBuild/rcc/qtrcc.targets 595 ●●●●● patch | view | raw | blame | history
QtMSBuild/QtMsBuild/rcc/qtrcc.xml 384 ●●●●● patch | view | raw | blame | history
QtMSBuild/QtMsBuild/rcc/qtrcc_cl.targets_TT 113 ●●●●● patch | view | raw | blame | history
QtMSBuild/QtMsBuild/rcc/qtrcc_v3.xml_TT 447 ●●●●● patch | view | raw | blame | history
QtMSBuild/QtMsBuild/repc/qt_import.props 46 ●●●●● patch | view | raw | blame | history
QtMSBuild/QtMsBuild/repc/qtrepc.props 73 ●●●●● patch | view | raw | blame | history
QtMSBuild/QtMsBuild/repc/qtrepc.targets 387 ●●●●● patch | view | raw | blame | history
QtMSBuild/QtMsBuild/repc/qtrepc.xml 237 ●●●●● patch | view | raw | blame | history
QtMSBuild/QtMsBuild/repc/qtrepc_cl.targets_TT 121 ●●●●● patch | view | raw | blame | history
QtMSBuild/QtMsBuild/repc/qtrepc_v3.xml_TT 282 ●●●●● patch | view | raw | blame | history
QtMSBuild/QtMsBuild/translation/qt_import.props 46 ●●●●● patch | view | raw | blame | history
QtMSBuild/QtMsBuild/translation/qttranslation.props 96 ●●●●● patch | view | raw | blame | history
QtMSBuild/QtMsBuild/translation/qttranslation.targets 626 ●●●●● patch | view | raw | blame | history
QtMSBuild/QtMsBuild/translation/qttranslation.xml 149 ●●●●● patch | view | raw | blame | history
QtMSBuild/QtMsBuild/uic/qt_import.props 46 ●●●●● patch | view | raw | blame | history
QtMSBuild/QtMsBuild/uic/qtuic.props 82 ●●●●● patch | view | raw | blame | history
QtMSBuild/QtMsBuild/uic/qtuic.targets 406 ●●●●● patch | view | raw | blame | history
QtMSBuild/QtMsBuild/uic/qtuic.xml 235 ●●●●● patch | view | raw | blame | history
QtMSBuild/QtMsBuild/uic/qtuic_v3.xml 218 ●●●●● patch | view | raw | blame | history
QtMSBuild/Tasks/CriticalSection.cs 113 ●●●●● patch | view | raw | blame | history
QtMSBuild/Tasks/DumpItems.cs 120 ●●●●● patch | view | raw | blame | history
QtMSBuild/Tasks/Expand.cs 100 ●●●●● patch | view | raw | blame | history
QtMSBuild/Tasks/Flatten.cs 118 ●●●●● patch | view | raw | blame | history
QtMSBuild/Tasks/GetItemHash.cs 76 ●●●●● patch | view | raw | blame | history
QtMSBuild/Tasks/GetVarsFromMSBuild.cs 96 ●●●●● patch | view | raw | blame | history
QtMSBuild/Tasks/GetVarsFromMakefile.cs 92 ●●●●● patch | view | raw | blame | history
QtMSBuild/Tasks/HostExec_LinuxSSL.cs 188 ●●●●● patch | view | raw | blame | history
QtMSBuild/Tasks/HostExec_LinuxWSL.cs 154 ●●●●● patch | view | raw | blame | history
QtMSBuild/Tasks/HostExec_LinuxWSL_Error.cs 60 ●●●●● patch | view | raw | blame | history
QtMSBuild/Tasks/HostExec_Windows.cs 125 ●●●●● patch | view | raw | blame | history
QtMSBuild/Tasks/HostTranslatePaths_LinuxSSL.cs 118 ●●●●● patch | view | raw | blame | history
QtMSBuild/Tasks/HostTranslatePaths_LinuxWSL.cs 107 ●●●●● patch | view | raw | blame | history
QtMSBuild/Tasks/HostTranslatePaths_LinuxWSL_Error.cs 52 ●●●●● patch | view | raw | blame | history
QtMSBuild/Tasks/HostTranslatePaths_Windows.cs 76 ●●●●● patch | view | raw | blame | history
QtMSBuild/Tasks/Join.cs 141 ●●●●● patch | view | raw | blame | history
QtMSBuild/Tasks/ListQrc.cs 79 ●●●●● patch | view | raw | blame | history
QtMSBuild/Tasks/ParseVarDefs.cs 79 ●●●●● patch | view | raw | blame | history
QtMSBuild/Tasks/QtRunWork.cs 320 ●●●●● patch | view | raw | blame | history
QtTmLanguage/qt/LICENSE 4 ●●●● patch | view | raw | blame | history
QtTmLanguage/qt/pri.pro.tmLanguage 346 ●●●●● patch | view | raw | blame | history
QtVsTest/Macro.cs 1049 ●●●●● patch | view | raw | blame | history
QtVsTest/MacroClient.h 249 ●●●●● patch | view | raw | blame | history
QtVsTest/MacroParser.cs 250 ●●●●● patch | view | raw | blame | history
QtVsTest/MacroServer.cs 137 ●●●●● patch | view | raw | blame | history
QtVsTest/Properties/AssemblyInfo.cs 65 ●●●●● patch | view | raw | blame | history
QtVsTest/QtVsTest.cs 107 ●●●●● patch | view | raw | blame | history
QtVsTest/QtVsTest.csproj 256 ●●●●● patch | view | raw | blame | history
QtVsTest/Resources/QtVsTest.ico patch | view | raw | blame | history
QtVsTest/csmacro.tmLanguage_TT 529 ●●●●● patch | view | raw | blame | history
QtVsTest/csmacro.tmTheme_TT 68 ●●●●● patch | view | raw | blame | history
QtVsTest/source.extension.vsixmanifest_TT 122 ●●●●● patch | view | raw | blame | history
QtVsTools.Core/BuildConfig.cs 49 ●●●●● patch | view | raw | blame | history
QtVsTools.Core/CommandLineParser.cs 589 ●●●●● patch | view | raw | blame | history
QtVsTools.Core/Common/EnumExt.cs 218 ●●●●● patch | view | raw | blame | history
QtVsTools.Core/CompilerToolWrapper.cs 465 ●●●●● patch | view | raw | blame | history
QtVsTools.Core/CxxStreamReader.cs 199 ●●●●● patch | view | raw | blame | history
QtVsTools.Core/ExportProjectDialog.cs 440 ●●●●● patch | view | raw | blame | history
QtVsTools.Core/ExportProjectDialog.resx 301 ●●●●● patch | view | raw | blame | history
QtVsTools.Core/Extensions.cs 62 ●●●●● patch | view | raw | blame | history
QtVsTools.Core/FakeFilter.cs 44 ●●●●● patch | view | raw | blame | history
QtVsTools.Core/FilesToList.cs 42 ●●●●● patch | view | raw | blame | history
QtVsTools.Core/Filters.cs 105 ●●●●● patch | view | raw | blame | history
QtVsTools.Core/HelperFunctions.cs 1918 ●●●●● patch | view | raw | blame | history
QtVsTools.Core/ImageButton.cs 75 ●●●●● patch | view | raw | blame | history
QtVsTools.Core/LinkerToolWrapper.cs 173 ●●●●● patch | view | raw | blame | history
QtVsTools.Core/MainWinWrapper.cs 57 ●●●●● patch | view | raw | blame | history
QtVsTools.Core/Messages.cs 241 ●●●●● patch | view | raw | blame | history
QtVsTools.Core/MocCmdChecker.cs 170 ●●●●● patch | view | raw | blame | history
QtVsTools.Core/MsBuildProject.cs 1800 ●●●●● patch | view | raw | blame | history
QtVsTools.Core/Observable.cs 77 ●●●●● patch | view | raw | blame | history
QtVsTools.Core/ProFileContent.cs 80 ●●●●● patch | view | raw | blame | history
QtVsTools.Core/ProFileOption.cs 143 ●●●●● patch | view | raw | blame | history
QtVsTools.Core/ProSolution.cs 61 ●●●●● patch | view | raw | blame | history
QtVsTools.Core/ProjectExporter.cs 853 ●●●●● patch | view | raw | blame | history
QtVsTools.Core/ProjectImporter.cs 285 ●●●●● patch | view | raw | blame | history
QtVsTools.Core/ProjectMacros.cs 37 ●●●●● patch | view | raw | blame | history
QtVsTools.Core/Properties/AssemblyInfo.cs 67 ●●●●● patch | view | raw | blame | history
QtVsTools.Core/QMake.cs 251 ●●●●● patch | view | raw | blame | history
QtVsTools.Core/QMakeConf.cs 166 ●●●●● patch | view | raw | blame | history
QtVsTools.Core/QMakeQuery.cs 122 ●●●●● patch | view | raw | blame | history
QtVsTools.Core/QrcItem.cs 36 ●●●●● patch | view | raw | blame | history
QtVsTools.Core/QrcParser.cs 96 ●●●●● patch | view | raw | blame | history
QtVsTools.Core/QrcPrefix.cs 49 ●●●●● patch | view | raw | blame | history
QtVsTools.Core/QtConfig.cs 127 ●●●●● patch | view | raw | blame | history
QtVsTools.Core/QtModule.cs 110 ●●●●● patch | view | raw | blame | history
QtVsTools.Core/QtModules.cs 113 ●●●●● patch | view | raw | blame | history
QtVsTools.Core/QtMsBuild.cs 1567 ●●●●● patch | view | raw | blame | history
QtVsTools.Core/QtProject.cs 4126 ●●●●● patch | view | raw | blame | history
QtVsTools.Core/QtVSException.cs 46 ●●●●● patch | view | raw | blame | history
QtVsTools.Core/QtVSIPSettings.cs 566 ●●●●● patch | view | raw | blame | history
QtVsTools.Core/QtVersionManager.cs 558 ●●●●● patch | view | raw | blame | history
QtVsTools.Core/QtVsTools.Core.csproj 191 ●●●●● patch | view | raw | blame | history
QtVsTools.Core/QtVsTools.Core.ico patch | view | raw | blame | history
QtVsTools.Core/RccOptions.cs 108 ●●●●● patch | view | raw | blame | history
QtVsTools.Core/Resources.cs 141 ●●●●● patch | view | raw | blame | history
QtVsTools.Core/Resources.resx 306 ●●●●● patch | view | raw | blame | history
QtVsTools.Core/Resources/delete.png patch | view | raw | blame | history
QtVsTools.Core/Resources/delete_d.png patch | view | raw | blame | history
QtVsTools.Core/Resources/newitem.png patch | view | raw | blame | history
QtVsTools.Core/Resources/newitem_d.png patch | view | raw | blame | history
QtVsTools.Core/SR.cs 91 ●●●●● patch | view | raw | blame | history
QtVsTools.Core/TemplateType.cs 45 ●●●●● patch | view | raw | blame | history
QtVsTools.Core/VersionInformation.cs 304 ●●●●● patch | view | raw | blame | history
QtVsTools.Core/VisualStudio/IProjectTracker.cs 35 ●●●●● patch | view | raw | blame | history
QtVsTools.Core/VisualStudio/VsServiceProvider.cs 95 ●●●●● patch | view | raw | blame | history
QtVsTools.Core/WaitDialog.cs 184 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Common/Concurrent.cs 222 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Common/ConcurrentStopwatch.cs 61 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Common/Disposable.cs 149 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Common/Json/DeferredObject.cs 114 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Common/Json/Serializable.cs 339 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Common/Json/SerializableEnum.cs 116 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Common/Json/Serializer.cs 334 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Common/NativeAPI.cs 179 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Common/PriorityQueue.cs 177 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Common/Prototyped.cs 222 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Common/PunisherQueue.cs 53 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Common/Timestamp.cs 55 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Common/VsToolsDialogWindow.cs 35 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Editors/Editor.QtDesigner.cs 88 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Editors/Editor.QtLinguist.cs 56 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Editors/Editor.QtResourceEditor.cs 62 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Editors/Editor.cs 525 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Language/LICENSE.APACHE 13 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Language/qml.qmlproject.tmLanguage 317 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Marketplace/Overview.html_TT 162 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Options/QtLegacyOptionsPage.cs 162 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Options/QtOptionsPage.cs 346 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Options/QtVersionsPage.cs 143 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Options/QtVersionsTable.cs 526 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Options/QtVersionsTable.xaml 286 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Package/AddTranslationDialog.cs 213 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Package/AddTranslationDialog.resx 120 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Package/ChangeFor.cs 32 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Package/DteEventsHandler.cs 586 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Package/ExtLoader.cs 192 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Package/FormChangeQtVersion.Designer.cs 87 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Package/FormChangeQtVersion.cs 103 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Package/FormChangeQtVersion.resx 120 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Package/FormProjectQtSettings.Designer.cs 157 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Package/FormProjectQtSettings.cs 180 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Package/FormProjectQtSettings.resx 120 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Package/ProjectQtSettings.cs 324 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Package/QMakeWrapper.cs 111 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Package/QtHelp.cs 287 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Package/QtHelpLinkChooser.xaml 107 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Package/QtHelpLinkChooser.xaml.cs 93 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Package/QtItemContextMenu.cs 143 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Package/QtMainMenu.cs 283 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Package/QtMsBuildConverter.cs 217 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Package/QtProjectContextMenu.cs 324 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Package/QtSolutionContextMenu.cs 182 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Package/SR.cs 101 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Package/Translation.cs 282 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Package/TranslationItem.cs 73 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Package/Version.cs 41 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Properties/AssemblyInfo.cs 67 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QML/Classification/QmlAsyncClassifier.cs 651 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QML/Classification/QmlClassificationFormat.cs 108 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QML/Classification/QmlErrorClassifier.cs 87 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QML/Classification/QmlExpressionEvalClassifier.cs 257 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QML/Classification/QmlSyntaxClassifier.cs 116 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QML/Classification/QmlTag.cs 313 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7BoilerPlate.cs 547 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7Breakpoint.cs 346 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7CodeContext.cs 206 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7Engine.cs 334 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7Enums.cs 237 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7Events.cs 274 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7Expression.cs 103 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7InfoHelpers.cs 198 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7Program.cs 602 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7Property.cs 304 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7StackFrame.cs 308 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QML/Debugging/QmlDebugLauncher.cs 313 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QML/Debugging/QmlDebugger.cs 545 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QML/Debugging/QmlFileSystem.cs 217 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QML/Debugging/V4/Messages/QmlDebugV4Backtrace.cs 103 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QML/Debugging/V4/Messages/QmlDebugV4Break.cs 83 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QML/Debugging/V4/Messages/QmlDebugV4ClearBreakpoint.cs 66 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QML/Debugging/V4/Messages/QmlDebugV4Connect.cs 52 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QML/Debugging/V4/Messages/QmlDebugV4Continue.cs 97 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QML/Debugging/V4/Messages/QmlDebugV4Disconnect.cs 65 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QML/Debugging/V4/Messages/QmlDebugV4Evaluate.cs 91 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QML/Debugging/V4/Messages/QmlDebugV4Exception.cs 78 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QML/Debugging/V4/Messages/QmlDebugV4Frame.cs 180 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QML/Debugging/V4/Messages/QmlDebugV4JsObject.cs 218 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QML/Debugging/V4/Messages/QmlDebugV4JsValue.cs 289 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QML/Debugging/V4/Messages/QmlDebugV4Lookup.cs 85 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QML/Debugging/V4/Messages/QmlDebugV4Message.cs 363 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QML/Debugging/V4/Messages/QmlDebugV4Scope.cs 139 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QML/Debugging/V4/Messages/QmlDebugV4SetBreakpoint.cs 136 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QML/Debugging/V4/Messages/QmlDebugV4SetExceptionBreak.cs 96 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QML/Debugging/V4/Messages/QmlDebugV4Version.cs 82 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QML/Debugging/V4/QmlDebugV4Client.cs 421 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QML/Debugging/V4/QmlDebugV4Protocol.cs 269 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QML/Parser/QmlParserDiagnostics.cs 52 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QML/Parser/QmlParserInterop.cs 567 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QML/Syntax/QmlAst.cs 239 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QML/Syntax/QmlSyntax.cs 283 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QtMenus.vsct_TT 725 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QtMsBuild/QtModulesEditor.cs 84 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QtMsBuild/QtModulesPopup.xaml 111 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QtMsBuild/QtModulesPopup.xaml.cs 102 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QtMsBuild/QtProjectBuild.cs 384 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QtMsBuild/QtProjectIntelliSense.cs 93 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QtMsBuild/QtProjectLogger.cs 128 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QtMsBuild/QtProjectTracker.cs 344 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QtMsBuild/QtVersionProvider.cs 84 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QtVsTools.Package.csproj 631 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QtVsTools.Qml.Debug.pkgdef 21 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/QtVsTools.ico patch | view | raw | blame | history
QtVsTools.Package/QtVsToolsPackage.cs 473 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Resources.resx 211 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/Resources/menuimages.png patch | view | raw | blame | history
QtVsTools.Package/Resources/qt.ico patch | view | raw | blame | history
QtVsTools.Package/VSPackage.resx 174 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/VisualStudio/VsShell.cs 88 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/preview.png patch | view | raw | blame | history
QtVsTools.Package/qt.ico patch | view | raw | blame | history
QtVsTools.Package/qt5.natvis.xml 808 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/qt6.natvis.xml 379 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/qtmodules.xml 600 ●●●●● patch | view | raw | blame | history
QtVsTools.Package/source.extension.vsixmanifest_TT 200 ●●●●● patch | view | raw | blame | history
QtVsTools.RegExpr/Properties/AssemblyInfo.cs 36 ●●●●● patch | view | raw | blame | history
QtVsTools.RegExpr/QtVsTools.RegExpr.csproj 117 ●●●●● patch | view | raw | blame | history
QtVsTools.RegExpr/README 317 ●●●●● patch | view | raw | blame | history
QtVsTools.RegExpr/expression/CharClassLiteral.cs 88 ●●●●● patch | view | raw | blame | history
QtVsTools.RegExpr/expression/CharClassRange.cs 98 ●●●●● patch | view | raw | blame | history
QtVsTools.RegExpr/expression/CharClassSet.cs 352 ●●●●● patch | view | raw | blame | history
QtVsTools.RegExpr/expression/RegExpr.cs 114 ●●●●● patch | view | raw | blame | history
QtVsTools.RegExpr/expression/RegExprAssert.cs 192 ●●●●● patch | view | raw | blame | history
QtVsTools.RegExpr/expression/RegExprChoice.cs 87 ●●●●● patch | view | raw | blame | history
QtVsTools.RegExpr/expression/RegExprLiteral.cs 72 ●●●●● patch | view | raw | blame | history
QtVsTools.RegExpr/expression/RegExprRepeat.cs 120 ●●●●● patch | view | raw | blame | history
QtVsTools.RegExpr/expression/RegExprSequence.cs 67 ●●●●● patch | view | raw | blame | history
QtVsTools.RegExpr/expression/RegExprToken.cs 388 ●●●●● patch | view | raw | blame | history
QtVsTools.RegExpr/expression/Renderer.cs 132 ●●●●● patch | view | raw | blame | history
QtVsTools.RegExpr/parser/ParseTree.cs 240 ●●●●● patch | view | raw | blame | history
QtVsTools.RegExpr/parser/Parser.cs 148 ●●●●● patch | view | raw | blame | history
QtVsTools.RegExpr/production/Production.cs 312 ●●●●● patch | view | raw | blame | history
QtVsTools.RegExpr/production/ProductionRule.cs 409 ●●●●● patch | view | raw | blame | history
QtVsTools.RegExpr/production/ProductionRuleAction.cs 345 ●●●●● patch | view | raw | blame | history
QtVsTools.RegExpr/utils/Consts.cs 202 ●●●●● patch | view | raw | blame | history
QtVsTools.RegExpr/utils/Utils.cs 97 ●●●●● patch | view | raw | blame | history
QtVsTools.Wizards/Properties/AssemblyInfo.cs 67 ●●●●● patch | view | raw | blame | history
QtVsTools.Wizards/QtVsTools.Wizards.csproj 250 ●●●●● patch | view | raw | blame | history
QtVsTools.Wizards/Resources/ExpanderStyle.xaml 173 ●●●●● patch | view | raw | blame | history
QtVsTools.Wizards/Resources/Qt-logo-small.png patch | view | raw | blame | history
QtVsTools.Wizards/Resources/QtProjectWizard.ico patch | view | raw | blame | history
QtVsTools.Wizards/Resources/medium.png patch | view | raw | blame | history
QtVsTools.Wizards/Resources/small.png patch | view | raw | blame | history
QtVsTools.Wizards/Wizards/ClassWizard/AddClassPage.xaml 356 ●●●●● patch | view | raw | blame | history
QtVsTools.Wizards/Wizards/ClassWizard/AddClassPage.xaml.cs 253 ●●●●● patch | view | raw | blame | history
QtVsTools.Wizards/Wizards/ClassWizard/AddClassWizard.cs 108 ●●●●● patch | view | raw | blame | history
QtVsTools.Wizards/Wizards/ClassWizard/Class.cs 63 ●●●●● patch | view | raw | blame | history
QtVsTools.Wizards/Wizards/ClassWizard/ClassKind.cs 36 ●●●●● patch | view | raw | blame | history
QtVsTools.Wizards/Wizards/ClassWizard/Core/CoreClassPage.xaml 298 ●●●●● patch | view | raw | blame | history
QtVsTools.Wizards/Wizards/ClassWizard/Core/CoreClassPage.xaml.cs 66 ●●●●● patch | view | raw | blame | history
QtVsTools.Wizards/Wizards/ClassWizard/Core/CoreClassWizard.cs 225 ●●●●● patch | view | raw | blame | history
QtVsTools.Wizards/Wizards/ClassWizard/Gui/GuiClassPage.xaml 301 ●●●●● patch | view | raw | blame | history
QtVsTools.Wizards/Wizards/ClassWizard/Gui/GuiClassPage.xaml.cs 82 ●●●●● patch | view | raw | blame | history
QtVsTools.Wizards/Wizards/ClassWizard/Gui/GuiClassWizard.cs 383 ●●●●● patch | view | raw | blame | history
QtVsTools.Wizards/Wizards/ClassWizard/IClassWizard.cs 35 ●●●●● patch | view | raw | blame | history
QtVsTools.Wizards/Wizards/ClassWizard/UiClassInclusion.cs 37 ●●●●● patch | view | raw | blame | history
QtVsTools.Wizards/Wizards/ProjectWizard/ConfigPage.xaml 298 ●●●●● patch | view | raw | blame | history
QtVsTools.Wizards/Wizards/ProjectWizard/ConfigPage.xaml.cs 478 ●●●●● patch | view | raw | blame | history
QtVsTools.Wizards/Wizards/ProjectWizard/Console/ConsoleWizard.cs 88 ●●●●● patch | view | raw | blame | history
QtVsTools.Wizards/Wizards/ProjectWizard/Designer/DesignerPage.xaml 310 ●●●●● patch | view | raw | blame | history
QtVsTools.Wizards/Wizards/ProjectWizard/Designer/DesignerPage.xaml.cs 68 ●●●●● patch | view | raw | blame | history
QtVsTools.Wizards/Wizards/ProjectWizard/Designer/DesignerWizard.cs 182 ●●●●● patch | view | raw | blame | history
QtVsTools.Wizards/Wizards/ProjectWizard/Empty/EmptyWizard.cs 73 ●●●●● patch | view | raw | blame | history
QtVsTools.Wizards/Wizards/ProjectWizard/Gui/GuiPage.xaml 261 ●●●●● patch | view | raw | blame | history
QtVsTools.Wizards/Wizards/ProjectWizard/Gui/GuiPage.xaml.cs 64 ●●●●● patch | view | raw | blame | history
QtVsTools.Wizards/Wizards/ProjectWizard/Gui/GuiWizard.cs 300 ●●●●● patch | view | raw | blame | history
QtVsTools.Wizards/Wizards/ProjectWizard/Library/LibraryClassPage.xaml 238 ●●●●● patch | view | raw | blame | history
QtVsTools.Wizards/Wizards/ProjectWizard/Library/LibraryClassPage.xaml.cs 62 ●●●●● patch | view | raw | blame | history
QtVsTools.Wizards/Wizards/ProjectWizard/Library/LibraryWizard.cs 142 ●●●●● patch | view | raw | blame | history
QtVsTools.Wizards/Wizards/ProjectWizard/ProjectTemplateWizard.cs 723 ●●●●● patch | view | raw | blame | history
QtVsTools.Wizards/Wizards/ProjectWizard/Quick/QuickWizard.cs 73 ●●●●● patch | view | raw | blame | history
QtVsTools.Wizards/Wizards/ProjectWizard/Server/ServerPage.xaml 259 ●●●●● patch | view | raw | blame | history
QtVsTools.Wizards/Wizards/ProjectWizard/Server/ServerPage.xaml.cs 62 ●●●●● patch | view | raw | blame | history
QtVsTools.Wizards/Wizards/ProjectWizard/Server/ServerWizard.cs 167 ●●●●● patch | view | raw | blame | history
QtVsTools.Wizards/Wizards/Util/ClassNameValidationRule.cs 67 ●●●●● patch | view | raw | blame | history
QtVsTools.Wizards/Wizards/Util/FileExistsInFilterValidationRule.cs 67 ●●●●● patch | view | raw | blame | history
QtVsTools.Wizards/Wizards/Util/FileNameValidationRule.cs 55 ●●●●● patch | view | raw | blame | history
QtVsTools.Wizards/Wizards/Util/NativeMethods.cs 41 ●●●●● patch | view | raw | blame | history
QtVsTools.Wizards/Wizards/Util/SortComboBoxItem.cs 41 ●●●●● patch | view | raw | blame | history
QtVsTools.Wizards/Wizards/Util/UnsafeNativeMethods.cs 41 ●●●●● patch | view | raw | blame | history
QtVsTools.Wizards/Wizards/Util/VCLanguageManagerValidationRule.cs 50 ●●●●● patch | view | raw | blame | history
QtVsTools.Wizards/Wizards/WizardData.cs 69 ●●●●● patch | view | raw | blame | history
QtVsTools.Wizards/Wizards/WizardIntroPage.xaml 102 ●●●●● patch | view | raw | blame | history
QtVsTools.Wizards/Wizards/WizardIntroPage.xaml.cs 39 ●●●●● patch | view | raw | blame | history
QtVsTools.Wizards/Wizards/WizardPage.cs 115 ●●●●● patch | view | raw | blame | history
QtVsTools.Wizards/Wizards/WizardResult.cs 37 ●●●●● patch | view | raw | blame | history
QtVsTools.Wizards/Wizards/WizardWindow.xaml 44 ●●●●● patch | view | raw | blame | history
QtVsTools.Wizards/Wizards/WizardWindow.xaml.cs 134 ●●●●● patch | view | raw | blame | history
README.md 156 ●●●●● patch | view | raw | blame | history
Templates/console/Properties/AssemblyInfo.cs 67 ●●●●● patch | view | raw | blame | history
Templates/console/QtTemplate.Project.Console.csproj 131 ●●●●● patch | view | raw | blame | history
Templates/console/console.ico patch | view | raw | blame | history
Templates/console/console.vcxproj 41 ●●●●● patch | view | raw | blame | history
Templates/console/console.vcxproj.filters 26 ●●●●● patch | view | raw | blame | history
Templates/console/console.vstemplate_TT 74 ●●●●● patch | view | raw | blame | history
Templates/console/main.cpp 8 ●●●●● patch | view | raw | blame | history
Templates/designer/Properties/AssemblyInfo.cs 67 ●●●●● patch | view | raw | blame | history
Templates/designer/QtTemplate.Project.Designer.csproj 138 ●●●●● patch | view | raw | blame | history
Templates/designer/designer.ico patch | view | raw | blame | history
Templates/designer/designer.vcxproj 46 ●●●●● patch | view | raw | blame | history
Templates/designer/designer.vcxproj.filters 39 ●●●●● patch | view | raw | blame | history
Templates/designer/designer.vstemplate_TT 84 ●●●●● patch | view | raw | blame | history
Templates/designer/plugin.cpp 77 ●●●●● patch | view | raw | blame | history
Templates/designer/plugin.h 28 ●●●●● patch | view | raw | blame | history
Templates/designer/plugin.json 1 ●●●● patch | view | raw | blame | history
Templates/designer/stdafx.cpp 1 ●●●● patch | view | raw | blame | history
Templates/designer/stdafx.h 1 ●●●● patch | view | raw | blame | history
Templates/designer/widget.cpp 6 ●●●●● patch | view | raw | blame | history
Templates/designer/widget.h 11 ●●●●● patch | view | raw | blame | history
Templates/dialogbuttonbottom/Properties/AssemblyInfo.cs 67 ●●●●● patch | view | raw | blame | history
Templates/dialogbuttonbottom/QtTemplate.Item.DialogButtonBottom.csproj 115 ●●●●● patch | view | raw | blame | history
Templates/dialogbuttonbottom/dialogbuttonbottom.ico patch | view | raw | blame | history
Templates/dialogbuttonbottom/dialogbuttonbottom.ui 100 ●●●●● patch | view | raw | blame | history
Templates/dialogbuttonbottom/dialogbuttonbottom.vstemplate 49 ●●●●● patch | view | raw | blame | history
Templates/dialogbuttonright/Properties/AssemblyInfo.cs 67 ●●●●● patch | view | raw | blame | history
Templates/dialogbuttonright/QtTemplate.Item.DialogButtonRight.csproj 114 ●●●●● patch | view | raw | blame | history
Templates/dialogbuttonright/dialogbuttonright.ico patch | view | raw | blame | history
Templates/dialogbuttonright/dialogbuttonright.ui 100 ●●●●● patch | view | raw | blame | history
Templates/dialogbuttonright/dialogbuttonright.vstemplate 49 ●●●●● patch | view | raw | blame | history
Templates/empty/Properties/AssemblyInfo.cs 67 ●●●●● patch | view | raw | blame | history
Templates/empty/QtTemplate.Project.Empty.csproj 129 ●●●●● patch | view | raw | blame | history
Templates/empty/empty.ico patch | view | raw | blame | history
Templates/empty/empty.vcxproj 41 ●●●●● patch | view | raw | blame | history
Templates/empty/empty.vcxproj.filters 25 ●●●●● patch | view | raw | blame | history
Templates/empty/empty.vstemplate_TT 71 ●●●●● patch | view | raw | blame | history
Templates/gui/Properties/AssemblyInfo.cs 67 ●●●●● patch | view | raw | blame | history
Templates/gui/QtTemplate.Project.Gui.csproj 142 ●●●●● patch | view | raw | blame | history
Templates/gui/gui.ico patch | view | raw | blame | history
Templates/gui/gui.vcxproj 46 ●●●●● patch | view | raw | blame | history
Templates/gui/gui.vcxproj.filters 48 ●●●●● patch | view | raw | blame | history
Templates/gui/gui.vstemplate_TT 82 ●●●●● patch | view | raw | blame | history
Templates/gui/main.cpp 10 ●●●●● patch | view | raw | blame | history
Templates/gui/stdafx.cpp 1 ●●●● patch | view | raw | blame | history
Templates/gui/stdafx.h 1 ●●●● patch | view | raw | blame | history
Templates/gui/widget.cpp 7 ●●●●● patch | view | raw | blame | history
Templates/gui/widget.h 15 ●●●●● patch | view | raw | blame | history
Templates/gui/widget.ui 25 ●●●●● patch | view | raw | blame | history
Templates/lib/Properties/AssemblyInfo.cs 67 ●●●●● patch | view | raw | blame | history
Templates/lib/QtTemplate.Project.Lib.csproj 136 ●●●●● patch | view | raw | blame | history
Templates/lib/global.h 13 ●●●●● patch | view | raw | blame | history
Templates/lib/header.h 9 ●●●●● patch | view | raw | blame | history
Templates/lib/lib.ico patch | view | raw | blame | history
Templates/lib/lib.vcxproj 44 ●●●●● patch | view | raw | blame | history
Templates/lib/lib.vcxproj.filters 33 ●●●●● patch | view | raw | blame | history
Templates/lib/lib.vstemplate_TT 82 ●●●●● patch | view | raw | blame | history
Templates/lib/source.cpp 5 ●●●●● patch | view | raw | blame | history
Templates/lib/stdafx.cpp 1 ●●●● patch | view | raw | blame | history
Templates/lib/stdafx.h patch | view | raw | blame | history
Templates/mainwindow/Properties/AssemblyInfo.cs 67 ●●●●● patch | view | raw | blame | history
Templates/mainwindow/QtTemplate.Item.MainWindow.csproj 115 ●●●●● patch | view | raw | blame | history
Templates/mainwindow/mainwindow.ico patch | view | raw | blame | history
Templates/mainwindow/mainwindow.ui 51 ●●●●● patch | view | raw | blame | history
Templates/mainwindow/mainwindow.vstemplate 49 ●●●●● patch | view | raw | blame | history
Templates/qml/NewFile.qml 12 ●●●●● patch | view | raw | blame | history
Templates/qml/Properties/AssemblyInfo.cs 67 ●●●●● patch | view | raw | blame | history
Templates/qml/QtTemplate.Item.QMLFile.csproj 119 ●●●●● patch | view | raw | blame | history
Templates/qml/qml.ico patch | view | raw | blame | history
Templates/qml/qml.vstemplate 49 ●●●●● patch | view | raw | blame | history
Templates/qmldir/Properties/AssemblyInfo.cs 67 ●●●●● patch | view | raw | blame | history
Templates/qmldir/QtTemplate.Item.QMLDir.csproj 119 ●●●●● patch | view | raw | blame | history
Templates/qmldir/qml.ico patch | view | raw | blame | history
Templates/qmldir/qmldir 1 ●●●● patch | view | raw | blame | history
Templates/qmldir/qmldir.vstemplate 49 ●●●●● patch | view | raw | blame | history
Templates/quick/Properties/AssemblyInfo.cs 67 ●●●●● patch | view | raw | blame | history
Templates/quick/QtTemplate.Project.Quick.csproj 128 ●●●●● patch | view | raw | blame | history
Templates/quick/main.cpp 18 ●●●●● patch | view | raw | blame | history
Templates/quick/main.qml 9 ●●●●● patch | view | raw | blame | history
Templates/quick/qml.qrc 5 ●●●●● patch | view | raw | blame | history
Templates/quick/quick.ico patch | view | raw | blame | history
Templates/quick/quick.vcxproj 44 ●●●●● patch | view | raw | blame | history
Templates/quick/quick.vcxproj.filters 33 ●●●●● patch | view | raw | blame | history
Templates/quick/quick.vstemplate_TT 77 ●●●●● patch | view | raw | blame | history
Templates/resource/Properties/AssemblyInfo.cs 67 ●●●●● patch | view | raw | blame | history
Templates/resource/QtTemplate.Item.Resource.csproj 119 ●●●●● patch | view | raw | blame | history
Templates/resource/resource.ico patch | view | raw | blame | history
Templates/resource/resource.qrc 4 ●●●● patch | view | raw | blame | history
Templates/resource/resource.vstemplate 49 ●●●●● patch | view | raw | blame | history
Templates/server/Properties/AssemblyInfo.cs 67 ●●●●● patch | view | raw | blame | history
Templates/server/QtTemplate.Project.Server.csproj 138 ●●●●● patch | view | raw | blame | history
Templates/server/header.h 17 ●●●●● patch | view | raw | blame | history
Templates/server/server.def 8 ●●●●● patch | view | raw | blame | history
Templates/server/server.ico patch | view | raw | blame | history
Templates/server/server.rc 2 ●●●●● patch | view | raw | blame | history
Templates/server/server.vcxproj 47 ●●●●● patch | view | raw | blame | history
Templates/server/server.vcxproj.filters 25 ●●●●● patch | view | raw | blame | history
Templates/server/server.vstemplate_TT 86 ●●●●● patch | view | raw | blame | history
Templates/server/source.cpp 17 ●●●●● patch | view | raw | blame | history
Templates/server/stdafx.cpp 1 ●●●● patch | view | raw | blame | history
Templates/server/stdafx.h 1 ●●●● patch | view | raw | blame | history
Templates/server/widget.ui 20 ●●●●● patch | view | raw | blame | history
Templates/widget/Properties/AssemblyInfo.cs 67 ●●●●● patch | view | raw | blame | history
Templates/widget/QtTemplate.Item.Widget.csproj 114 ●●●●● patch | view | raw | blame | history
Templates/widget/widget.ico patch | view | raw | blame | history
Templates/widget/widget.ui 24 ●●●●● patch | view | raw | blame | history
Templates/widget/widget.vstemplate 49 ●●●●● patch | view | raw | blame | history
Tests/BigSolution/generator/App.config 6 ●●●●● patch | view | raw | blame | history
Tests/BigSolution/generator/Program.cs 120 ●●●●● patch | view | raw | blame | history
Tests/BigSolution/generator/Properties/AssemblyInfo.cs 36 ●●●●● patch | view | raw | blame | history
Tests/BigSolution/generator/generator.csproj 53 ●●●●● patch | view | raw | blame | history
Tests/BigSolution/generator/generator.sln 25 ●●●●● patch | view | raw | blame | history
Tests/BigSolution/template/BigProjectNNN/BigClassNNN.cpp 118 ●●●●● patch | view | raw | blame | history
Tests/BigSolution/template/BigProjectNNN/BigClassNNN.h 38 ●●●●● patch | view | raw | blame | history
Tests/BigSolution/template/BigProjectNNN/BigProjectNNN.qrc 4 ●●●● patch | view | raw | blame | history
Tests/BigSolution/template/BigProjectNNN/BigProjectNNN.ui 28 ●●●●● patch | view | raw | blame | history
Tests/BigSolution/template/BigProjectNNN/BigProjectNNN.vcxproj 104 ●●●●● patch | view | raw | blame | history
Tests/BigSolution/template/BigProjectNNN/BigProjectNNN.vcxproj.filters 48 ●●●●● patch | view | raw | blame | history
Tests/BigSolution/template/BigProjectNNN/BigProjectQtClassNNN.cpp 35 ●●●●● patch | view | raw | blame | history
Tests/BigSolution/template/BigProjectNNN/BigProjectQtClassNNN.h 43 ●●●●● patch | view | raw | blame | history
Tests/BigSolution/template/BigProjectNNN/bigprojectnnn_global.h 41 ●●●●● patch | view | raw | blame | history
Tests/BigSolution/template/BigSolution.sln 25 ●●●●● patch | view | raw | blame | history
Tests/SampleTest/Macros.qrc 9 ●●●●● patch | view | raw | blame | history
Tests/SampleTest/SampleTest.pro 10 ●●●●● patch | view | raw | blame | history
Tests/SampleTest/SampleTest.sln 25 ●●●●● patch | view | raw | blame | history
Tests/SampleTest/SampleTest.vcxproj 172 ●●●●● patch | view | raw | blame | history
Tests/SampleTest/SampleTest.vcxproj.filters 60 ●●●●● patch | view | raw | blame | history
Tests/SampleTest/Test_CreateGuiApp.csmacro 49 ●●●●● patch | view | raw | blame | history
Tests/SampleTest/Test_DebugGuiApp.csmacro 37 ●●●●● patch | view | raw | blame | history
Tests/SampleTest/Test_ImportProFile.csmacro 68 ●●●●● patch | view | raw | blame | history
Tests/SampleTest/Test_QtVsToolsLoaded.csmacro 35 ●●●●● patch | view | raw | blame | history
Tests/SampleTest/Test_RebuildSolution.csmacro 41 ●●●●● patch | view | raw | blame | history
Tests/SampleTest/main.cpp 140 ●●●●● patch | view | raw | blame | history
Tests/Test_QtMsBuild.Tasks/Properties/AssemblyInfo.cs 20 ●●●●● patch | view | raw | blame | history
Tests/Test_QtMsBuild.Tasks/TestTaskLoggingHelper.cs 364 ●●●●● patch | view | raw | blame | history
Tests/Test_QtMsBuild.Tasks/Test_Join.cs 237 ●●●●● patch | view | raw | blame | history
Tests/Test_QtMsBuild.Tasks/Test_QtMsBuild.Tasks.csproj 112 ●●●●● patch | view | raw | blame | history
Tests/Test_QtVsTools.PriorityQueue/Properties/AssemblyInfo.cs 48 ●●●●● patch | view | raw | blame | history
Tests/Test_QtVsTools.PriorityQueue/Test_PriorityQueue.cs 230 ●●●●● patch | view | raw | blame | history
Tests/Test_QtVsTools.PriorityQueue/Test_QtVsTools.PriorityQueue.csproj 107 ●●●●● patch | view | raw | blame | history
Tests/Test_QtVsTools.RegExpr/Properties/AssemblyInfo.cs 47 ●●●●● patch | view | raw | blame | history
Tests/Test_QtVsTools.RegExpr/Test_MacroParser.cs 66 ●●●●● patch | view | raw | blame | history
Tests/Test_QtVsTools.RegExpr/Test_QtVsTools.RegExpr.csproj 112 ●●●●● patch | view | raw | blame | history
Tests/Test_QtVsTools.RegExpr/Test_SubTokens.cs 60 ●●●●● patch | view | raw | blame | history
Tests/Test_QtVsTools.RegExpr/Test_XmlIntParser.cs 344 ●●●●● patch | view | raw | blame | history
Tests/concurrency/Solution1/MyPropertySheet.props 10 ●●●●● patch | view | raw | blame | history
Tests/concurrency/Solution1/QtClassLibrary1/QtClass.cpp 10 ●●●●● patch | view | raw | blame | history
Tests/concurrency/Solution1/QtClassLibrary1/QtClass.h 13 ●●●●● patch | view | raw | blame | history
Tests/concurrency/Solution1/QtClassLibrary1/QtClassLibrary1.cpp 5 ●●●●● patch | view | raw | blame | history
Tests/concurrency/Solution1/QtClassLibrary1/QtClassLibrary1.h 9 ●●●●● patch | view | raw | blame | history
Tests/concurrency/Solution1/QtClassLibrary1/QtClassLibrary1.vcxproj 119 ●●●●● patch | view | raw | blame | history
Tests/concurrency/Solution1/QtClassLibrary1/QtClassLibrary1.vcxproj.filters 42 ●●●●● patch | view | raw | blame | history
Tests/concurrency/Solution1/QtClassLibrary1/qtclasslibrary1_global.h 13 ●●●●● patch | view | raw | blame | history
Tests/concurrency/Solution1/QtWidgetsApplication1/QtWidgetsApplication1.cpp 11 ●●●●● patch | view | raw | blame | history
Tests/concurrency/Solution1/QtWidgetsApplication1/QtWidgetsApplication1.h 18 ●●●●● patch | view | raw | blame | history
Tests/concurrency/Solution1/QtWidgetsApplication1/QtWidgetsApplication1.qrc 4 ●●●● patch | view | raw | blame | history
Tests/concurrency/Solution1/QtWidgetsApplication1/QtWidgetsApplication1.ui 28 ●●●●● patch | view | raw | blame | history
Tests/concurrency/Solution1/QtWidgetsApplication1/QtWidgetsApplication1.vcxproj 115 ●●●●● patch | view | raw | blame | history
Tests/concurrency/Solution1/QtWidgetsApplication1/QtWidgetsApplication1.vcxproj.filters 44 ●●●●● patch | view | raw | blame | history
Tests/concurrency/Solution1/QtWidgetsApplication1/main.cpp 10 ●●●●● patch | view | raw | blame | history
Tests/concurrency/Solution1/QtWidgetsApplication2/QtWidgetsApplication2.cpp 9 ●●●●● patch | view | raw | blame | history
Tests/concurrency/Solution1/QtWidgetsApplication2/QtWidgetsApplication2.h 18 ●●●●● patch | view | raw | blame | history
Tests/concurrency/Solution1/QtWidgetsApplication2/QtWidgetsApplication2.qrc 4 ●●●● patch | view | raw | blame | history
Tests/concurrency/Solution1/QtWidgetsApplication2/QtWidgetsApplication2.ui 28 ●●●●● patch | view | raw | blame | history
Tests/concurrency/Solution1/QtWidgetsApplication2/QtWidgetsApplication2.vcxproj 115 ●●●●● patch | view | raw | blame | history
Tests/concurrency/Solution1/QtWidgetsApplication2/QtWidgetsApplication2.vcxproj.filters 44 ●●●●● patch | view | raw | blame | history
Tests/concurrency/Solution1/QtWidgetsApplication2/main.cpp 10 ●●●●● patch | view | raw | blame | history
Tests/concurrency/Solution1/Solution1.sln 43 ●●●●● patch | view | raw | blame | history
Tests/concurrency/Solution1/StaticLib1/Header.h 4 ●●●● patch | view | raw | blame | history
Tests/concurrency/Solution1/StaticLib1/StaticLib1.cpp 3 ●●●●● patch | view | raw | blame | history
Tests/concurrency/Solution1/StaticLib1/StaticLib1.vcxproj 93 ●●●●● patch | view | raw | blame | history
Tests/concurrency/Solution1/StaticLib1/StaticLib1.vcxproj.filters 27 ●●●●● patch | view | raw | blame | history
Tests/concurrency/loop_msbuild.bat 36 ●●●●● patch | view | raw | blame | history
VsQml/README 35 ●●●●● patch | view | raw | blame | history
VsQml/astvisitor.cpp 563 ●●●●● patch | view | raw | blame | history
VsQml/astvisitor.h 47 ●●●●● patch | view | raw | blame | history
VsQml/vsqml.cpp 369 ●●●●● patch | view | raw | blame | history
VsQml/vsqml.h 120 ●●●●● patch | view | raw | blame | history
VsQml/vsqml.vcxproj 196 ●●●●● patch | view | raw | blame | history
VsQml/vsqml.vcxproj.filters 47 ●●●●● patch | view | raw | blame | history
VsQml/vsqml_global.h 38 ●●●●● patch | view | raw | blame | history
VsQml/vsqmldebugclient.cpp 148 ●●●●● patch | view | raw | blame | history
VsQml/vsqmldebugclient.h 56 ●●●●● patch | view | raw | blame | history
common.tt 158 ●●●●● patch | view | raw | blame | history
doc/config/macros.qdocconf 4 ●●●● patch | view | raw | blame | history
doc/config/qtvstools-project.qdocconf 45 ●●●●● patch | view | raw | blame | history
doc/config/style/qt5-sidebar.html 15 ●●●●● patch | view | raw | blame | history
doc/doc.pri 42 ●●●●● patch | view | raw | blame | history
doc/images/qtvstools-addressbook-adddialog.png patch | view | raw | blame | history
doc/images/qtvstools-addressbook-mainwindow.png patch | view | raw | blame | history
doc/images/qtvstools-export-project.png patch | view | raw | blame | history
doc/images/qtvstools-minus.png patch | view | raw | blame | history
doc/images/qtvstools-plus.png patch | view | raw | blame | history
doc/images/qtvstools-qrc-editor.png patch | view | raw | blame | history
doc/images/qtvstools-qt-project-settings.png patch | view | raw | blame | history
doc/images/qtvstools-qt-versions.png patch | view | raw | blame | history
doc/images/qtvstools-qt-widget-class-wizard.png patch | view | raw | blame | history
doc/images/qtvstools-widgets-app-class.png patch | view | raw | blame | history
doc/images/qtvstools-widgets-app-modules.png patch | view | raw | blame | history
doc/qtvstools-online.qdocconf 19 ●●●●● patch | view | raw | blame | history
doc/qtvstools.qdocconf 2 ●●●●● patch | view | raw | blame | history
doc/src/externallinks.qdoc 37 ●●●●● patch | view | raw | blame | history
doc/src/qtvstools.qdoc 827 ●●●●● patch | view | raw | blame | history
doc/tutorial/AddressBook/AddressBook.ico patch | view | raw | blame | history
doc/tutorial/AddressBook/AddressBook.pro 13 ●●●●● patch | view | raw | blame | history
doc/tutorial/AddressBook/AddressBook.rc 2 ●●●●● patch | view | raw | blame | history
doc/tutorial/AddressBook/adddialog.cpp 51 ●●●●● patch | view | raw | blame | history
doc/tutorial/AddressBook/adddialog.h 53 ●●●●● patch | view | raw | blame | history
doc/tutorial/AddressBook/adddialog.ui 126 ●●●●● patch | view | raw | blame | history
doc/tutorial/AddressBook/addressbook.cpp 97 ●●●●● patch | view | raw | blame | history
doc/tutorial/AddressBook/addressbook.h 61 ●●●●● patch | view | raw | blame | history
doc/tutorial/AddressBook/addressbook.ui 86 ●●●●● patch | view | raw | blame | history
doc/tutorial/AddressBook/main.cpp 50 ●●●●● patch | view | raw | blame | history
references.props 125 ●●●●● patch | view | raw | blame | history
transform.targets 80 ●●●●● patch | view | raw | blame | history
version.targets 6 ●●●●● patch | view | raw | blame | history
version.tt 81 ●●●●● patch | view | raw | blame | history
vstools.bat 417 ●●●●● patch | view | raw | blame | history
vstools.pri_TT 39 ●●●●● patch | view | raw | blame | history
vstools.pro 4 ●●●● patch | view | raw | blame | history
vstools.sln 609 ●●●●● patch | view | raw | blame | history
.editorconfig
New file
@@ -0,0 +1,219 @@
# Remove the line below if you want to inherit .editorconfig settings from higher directories
root = true
# C# files
[*.cs]
#### Core EditorConfig Options ####
# Indentation and spacing
indent_size = 4
indent_style = space
tab_width = 4
# New line preferences
end_of_line = crlf
insert_final_newline = false
#### .NET Coding Conventions ####
# Organize usings
dotnet_separate_import_directive_groups = false
dotnet_sort_system_directives_first = false
file_header_template = unset
# this. and Me. preferences
dotnet_style_qualification_for_event = false
dotnet_style_qualification_for_field = false
dotnet_style_qualification_for_method = false
dotnet_style_qualification_for_property = false
# Language keywords vs BCL types preferences
dotnet_style_predefined_type_for_locals_parameters_members = true
dotnet_style_predefined_type_for_member_access = true
# Parentheses preferences
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity
dotnet_style_parentheses_in_other_operators = never_if_unnecessary
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity
# Modifier preferences
dotnet_style_require_accessibility_modifiers = for_non_interface_members
# Expression-level preferences
dotnet_style_coalesce_expression = true
dotnet_style_collection_initializer = true
dotnet_style_explicit_tuple_names = true
dotnet_style_namespace_match_folder = true
dotnet_style_null_propagation = true
dotnet_style_object_initializer = true
dotnet_style_operator_placement_when_wrapping = beginning_of_line
dotnet_style_prefer_auto_properties = true
dotnet_style_prefer_compound_assignment = true
dotnet_style_prefer_conditional_expression_over_assignment = true
dotnet_style_prefer_conditional_expression_over_return = true
dotnet_style_prefer_inferred_anonymous_type_member_names = true
dotnet_style_prefer_inferred_tuple_names = true
dotnet_style_prefer_is_null_check_over_reference_equality_method = true
dotnet_style_prefer_simplified_boolean_expressions = true
dotnet_style_prefer_simplified_interpolation = true
# Field preferences
dotnet_style_readonly_field = true
# Parameter preferences
dotnet_code_quality_unused_parameters = all
# Suppression preferences
dotnet_remove_unnecessary_suppression_exclusions = none
# New line preferences
dotnet_style_allow_multiple_blank_lines_experimental = true
dotnet_style_allow_statement_immediately_after_block_experimental = true
#### C# Coding Conventions ####
# var preferences
csharp_style_var_elsewhere = false
csharp_style_var_for_built_in_types = false
csharp_style_var_when_type_is_apparent = false
# Expression-bodied members
csharp_style_expression_bodied_accessors = true
csharp_style_expression_bodied_constructors = false
csharp_style_expression_bodied_indexers = true
csharp_style_expression_bodied_lambdas = true
csharp_style_expression_bodied_local_functions = false
csharp_style_expression_bodied_methods = false
csharp_style_expression_bodied_operators = false
csharp_style_expression_bodied_properties = true
# Pattern matching preferences
csharp_style_pattern_matching_over_as_with_null_check = true
csharp_style_pattern_matching_over_is_with_cast_check = true
csharp_style_prefer_not_pattern = true
csharp_style_prefer_pattern_matching = true
csharp_style_prefer_switch_expression = true
# Null-checking preferences
csharp_style_conditional_delegate_call = true
# Modifier preferences
csharp_prefer_static_local_function = true
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async
# Code-block preferences
csharp_prefer_braces = true
csharp_prefer_simple_using_statement = true
csharp_style_namespace_declarations = block_scoped
# Expression-level preferences
csharp_prefer_simple_default_expression = true
csharp_style_deconstructed_variable_declaration = true
csharp_style_implicit_object_creation_when_type_is_apparent = true
csharp_style_inlined_variable_declaration = true
csharp_style_pattern_local_over_anonymous_function = true
csharp_style_prefer_index_operator = true
csharp_style_prefer_null_check_over_type_check = true
csharp_style_prefer_range_operator = true
csharp_style_throw_expression = true
csharp_style_unused_value_assignment_preference = discard_variable
csharp_style_unused_value_expression_statement_preference = discard_variable
# 'using' directive preferences
csharp_using_directive_placement = outside_namespace
# New line preferences
csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true
csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true
csharp_style_allow_embedded_statements_on_same_line_experimental = true
#### C# Formatting Rules ####
# New line preferences
csharp_new_line_before_catch = false
csharp_new_line_before_else = false
csharp_new_line_before_finally = false
csharp_new_line_before_members_in_anonymous_types = true
csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_open_brace = accessors,anonymous_methods,anonymous_types,lambdas,methods,object_collection_array_initializers,properties,types
csharp_new_line_between_query_expression_clauses = true
# Indentation preferences
csharp_indent_block_contents = true
csharp_indent_braces = false
csharp_indent_case_contents =true
csharp_indent_case_contents_when_block =true
csharp_indent_labels = flush_left
csharp_indent_switch_labels =false
# Space preferences
csharp_space_after_cast =false
csharp_space_after_colon_in_inheritance_clause = true
csharp_space_after_comma = true
csharp_space_after_dot = false
csharp_space_after_keywords_in_control_flow_statements = true
csharp_space_after_semicolon_in_for_statement = true
csharp_space_around_binary_operators = ignore
csharp_space_around_declaration_statements = false
csharp_space_before_colon_in_inheritance_clause = true
csharp_space_before_comma = false
csharp_space_before_dot = false
csharp_space_before_open_square_brackets = false
csharp_space_before_semicolon_in_for_statement = false
csharp_space_between_empty_square_brackets = false
csharp_space_between_method_call_empty_parameter_list_parentheses = false
csharp_space_between_method_call_name_and_opening_parenthesis = false
csharp_space_between_method_call_parameter_list_parentheses = false
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
csharp_space_between_method_declaration_name_and_open_parenthesis = false
csharp_space_between_method_declaration_parameter_list_parentheses = false
csharp_space_between_parentheses = false
csharp_space_between_square_brackets = false
# Wrapping preferences
csharp_preserve_single_line_blocks = true
csharp_preserve_single_line_statements = true
#### Naming styles ####
# Naming rules
dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.types_should_be_pascal_case.symbols = types
dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
# Symbol specifications
dotnet_naming_symbols.interface.applicable_kinds = interface
dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
dotnet_naming_symbols.interface.required_modifiers =
dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
dotnet_naming_symbols.types.required_modifiers =
dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
dotnet_naming_symbols.non_field_members.required_modifiers =
# Naming styles
dotnet_naming_style.pascal_case.required_prefix =
dotnet_naming_style.pascal_case.required_suffix =
dotnet_naming_style.pascal_case.word_separator =
dotnet_naming_style.pascal_case.capitalization = pascal_case
dotnet_naming_style.begins_with_i.required_prefix = I
dotnet_naming_style.begins_with_i.required_suffix =
dotnet_naming_style.begins_with_i.word_separator =
dotnet_naming_style.begins_with_i.capitalization = pascal_case
.gitignore
@@ -1,30 +1,63 @@
*~
ui_*.h
*.swp
*.idb
*.pdb
*.ib_pdb_index
*.ncb
*.suo
*.user
Makefile
Makefile.*
debug/
Debug/
release/
Release/
GeneratedFiles/
help/test
*.UnmanagedRegistration.cache
Trolltech.Qt4VS200?Base.xml
*_wrapper.bat
*_plugin_import.cpp
qrceditor/bin/
qmakefilereader/bin/
*.metaproj*
*.binlog
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
build/
[Xx]64/
[Xx]86/
[Bb]uild/
bld/
[Bb]in/
[Oo]bj/
# Roslyn cache directories
*.ide/
# Visual Studio 2015 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
#NUNIT
# NUNIT
*.VisualState.xml
TestResult.xml
@@ -32,6 +65,10 @@
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# DNX
project.lock.json
artifacts/
*_i.c
*_p.c
@@ -65,14 +102,17 @@
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# TFS 2012 Local Workspace
$tf/
@@ -85,7 +125,7 @@
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding addin-in
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
@@ -97,6 +137,7 @@
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
@@ -124,34 +165,47 @@
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
## TODO: Comment the next line if you want to checkin your
## web deploy settings but do note that will include unencrypted
## passwords
*.pubxml
# TODO: Un-comment the next line if you do not want to checkin
# your web deploy settings because they may include unencrypted
# passwords
#*.pubxml
*.publishproj
# NuGet Packages
packages/*
*.nupkg
## TODO: If the tool you use requires repositories.config
## uncomment the next line
#!packages/repositories.config
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignoreable files
*.nuget.props
*.nuget.targets
# Enable "build/" folder in the NuGet Packages folder since
# NuGet packages use it for MSBuild targets.
# This line needs to be after the ignore of the build folder
# (and the packages folder if the line above has been uncommented)
!packages/build/
# Windows Azure Build Output
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Microsoft Azure ApplicationInsights config file
ApplicationInsights.config
# Windows Store app package directory
AppPackages/
BundleArtifacts/
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
sql/
*.Cache
ClientBin/
[Ss]tyle[Cc]op.*
~$*
@@ -161,6 +215,7 @@
*.pfx
*.publishsettings
node_modules/
orleans.codegen.cs
# RIA/Silverlight projects
Generated_Code/
@@ -184,3 +239,79 @@
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# LightSwitch generated files
GeneratedArtifacts/
ModelManifest.xml
# Paket dependency manager
.paket/paket.exe
# FAKE - F# Make
.fake/
# Generated Files
MSBuild.MetaInfo.cs
qtvstools.package/package/Version.tt.cs
qtvstools.package/Properties/AssemblyInfo.tt.cs
qtvstools.package/QtMenus.vsct
qtvstools.package/Marketplace/Overview.html
qtvstools.core/Properties/AssemblyInfo.tt.cs
qtvstools.wizards/Properties/AssemblyInfo.tt.cs
templates/qmldir/Properties/AssemblyInfo.tt.cs
templates/qml/Properties/AssemblyInfo.tt.cs
templates/console/Properties/AssemblyInfo.tt.cs
templates/designer/Properties/AssemblyInfo.tt.cs
templates/dialogbuttonbottom/Properties/AssemblyInfo.tt.cs
templates/dialogbuttonright/Properties/AssemblyInfo.tt.cs
templates/empty/Properties/AssemblyInfo.tt.cs
templates/quick/Properties/AssemblyInfo.tt.cs
templates/gui/Properties/AssemblyInfo.tt.cs
templates/lib/Properties/AssemblyInfo.tt.cs
templates/mainwindow/Properties/AssemblyInfo.tt.cs
templates/resource/Properties/AssemblyInfo.tt.cs
templates/server/Properties/AssemblyInfo.tt.cs
templates/widget/Properties/AssemblyInfo.tt.cs
templates/console/console.vstemplate
templates/designer/designer.vstemplate
templates/empty/empty.vstemplate
templates/quick/quick.vstemplate
templates/gui/gui.vstemplate
templates/lib/lib.vstemplate
templates/server/server.vstemplate
qtmsbuild/Properties/AssemblyInfo.tt.cs
qtmsbuild/QtMsBuild/moc/qtmoc_v3.xml
qtmsbuild/QtMsBuild/moc/qtmoc_cl.targets
qtmsbuild/QtMsBuild/rcc/qtrcc_v3.xml
qtmsbuild/QtMsBuild/rcc/qtrcc_cl.targets
qtmsbuild/QtMsBuild/repc/qtrepc_v3.xml
qtmsbuild/QtMsBuild/repc/qtrepc_cl.targets
qtmsbuild/QtMSBuild/qt_tasks.targets
qtvstest/csmacro.tmLanguage
qtvstest/csmacro.tmTheme
qtvstest/Properties/AssemblyInfo.tt.cs
qtvstest/source.extension.vsixmanifest
QtVsTools.Package/source.extension.vsixmanifest
QtNatvisPoC/*.txt
Tests/BigSolution/generated/
vstools.pri
Changelog
New file
@@ -0,0 +1,724 @@
Qt Visual Studio Tools version 2.8.1:
Changes
-------
 - Fixed QTVSADDINBUG-340: QML files are not updated with lupdate
 - Fixed QTVSADDINBUG-431: Difficult to find feature to change Qt Version
 - Fixed QTVSADDINBUG-801, QTVSADDINBUG-498: Error in qt5.natvis: "identifier "$T1" is undefined"
 - Fixed QTVSADDINBUG-628: Change Qt Project settings lead to an error message
 - Fixed QTVSADDINBUG-659: Missing Qurl debug visualizer
 - Fixed QTVSADDINBUG-700: In debug, a QStandardItem will not be resolved unless inside the class
 - Fixed QTVSADDINBUG-701: "Qt Project Settings" incorrect behavior
 - Fixed QTVSADDINBUG-831: Error creating new Qt project when "application icon" option is enabled
 - Fixed QTVSADDINBUG-883: Background build error when using common props file
 - Fixed QTVSADDINBUG-919: Missing QML/QtQuick plugins when using a static Qt build
 - Fixed QTVSADDINBUG-924: New Qt projects use C++14 standard by default
 - Fixed QTVSADDINBUG-926: Qt module selection can't be confirmed
 - Fixed QTVSADDINBUG-930: "Finish" button always disabled in Qt Class Wizard
 - Fixed QTVSADDINBUG-936: Generated C++ source file fails to compile with precompiled header
 - Fixed QTVSADDINBUG-941: "Translation disabled during build; skipping"
 - Fixed QTVSADDINBUG-943: Document Qt 6 Support
 - Fixed QTVSADDINBUG-950: Get Qt build settings from 'vcapp' qmake template
 - Fixed QTVSADDINBUG-952: lupdate is not run during build
Qt Visual Studio Tools version 2.8.0:
Changes
-------
 - Added support for Visual Studio 2022
 - Fixed QTVSADDINBUG-927: Post-build refresh of IntelliSense data slows down/freezes the VS IDE
Qt Visual Studio Tools version 2.7.2:
Changes
-------
  - Fixed QTVSADDINBUG-805: Q_NAMESPACE needs mocing
  - Fixed QTVSADDINBUG-871: lupdate/lrelease not working on .ts file context menu
  - Fixed QTVSADDINBUG-873: Update list of Qt modules
  - Fixed QTVSADDINBUG-874: Add option to open Designer in detached window
  - Fixed QTVSADDINBUG-875: Can't open .ui files if path has space
  - Fixed QTVSADDINBUG-887: Cannot add Qt version
  - Fixed QTVSADDINBUG-888: lupdate fails to locate source files
  - Fixed QTVSADDINBUG-890: Background build and VS2019 freeze on open solution
  - Fixed QTVSADDINBUG-898: .ts files not processed
  - Fixed QTVSADDINBUG-916: Build concurrency issues
  - Fixed QTVSADDINBUG-917: Build concurrency issues
  - Added module selection popup in Qt Settings property page
  - Optimized IntelliSense updates ("background build")
  - UI feedback of IntelliSense update, with the option to cancel background tasks
  - Context menu option to update Qt project IntelliSense information (Qt > Refresh IntelliSense)
  - Notification of available development release
Qt Visual Studio Tools version 2.7.1:
Changes
-------
  - Translation tools integrated with Qt/MSBuild
  - Qt.props property sheet accessible through the VS Property Manager window
  - Qt editors are opened in a document window inside Visual Studio
  - IntelliSense is updated on changes to .ui files
  - The Qt Options UI will be displayed as part of the standard VS 'Tools > Options' dialog
  - Added the following new fields to the Qt Options page:
      * QML debugger connection timeout
      * Path to Qt/MSBuild files
      * Enable QML debugger (overrides project settings)
      * Enable refresh of IntelliSense after build
      * Enable refresh of IntelliSense when a .ui file is changed
  - Pressing F1 will query Qt documentation
  - Fixed QTVSADDINBUG-698: Qt online help not working
  - Fixed QTVSADDINBUG-755: QML debug not working without a QRC file
  - Fixed QTVSADDINBUG-822: Incorrect generation of command line options
  - Fixed QTVSADDINBUG-825: Calls to qmake fail silently
  - Fixed QTVSADDINBUG-826: Crash in new-project wizard
  - Fixed QTVSADDINBUG-827: Command line options of Qt tools generated incorrectly
  - Fixed QTVSADDINBUG-837: Debug output cluttered with QML debugger status messages
  - Fixed QTVSADDINBUG-841: Incremental build failure
  - Fixed QTVSADDINBUG-857: Build fails due to concurrency issues
Qt Visual Studio Tools version 2.6.0:
Changes
-------
  - Support for cross-compilation with the Linux development VS workload
  - Integration of Qt for Windows deployment tool (windeployqt)
  - Fixed QTVSADDINBUG-797: Incorrect generation of command-line flags for Qt tools
Qt Visual Studio Tools version 2.5.2:
Changes
-------
  - Fixed QTVSADDINBUG-749: lupdate/lrelease options ignored
  - Fixed QTVSADDINBUG-756, QTVSADDINBUG-783: Qt tools generate files outside of project directory
  - Fixed QTVSADDINBUG-760: repc output directory not added to include path
  - Fixed QTVSADDINBUG-772, QTVSADDINBUG-777: Qt tools fail to run if path contains spaces
  - Fixed QTVSADDINBUG-780: Regression in Qt Quick compiler integration
  - Fixed QTVSADDINBUG-781: Error accessing Qt version when using non-ASCII characters in paths
  - Fixed QTVSADDINBUG-782: Incorrect build settings in the debug configuration of Qt Console apps
  - Fixed QTVSADDINBUG-785: OBJECTS_DIR ignored when importing .pro
  - Fixed QTVSADDINBUG-786: repc command line generated incorrectly
  - Fixed QTVSADDINBUG-790: Build errors when temp directory ends with .lnk
  - Fixed QTVSADDINBUG-792: Files with Q_OBJECT macro not handled correctly
  - Fixed QTVSADDINBUG-793: Backslashes in Qt version name causes error
Qt Visual Studio Tools version 2.5.1:
Changes
-------
  - Minimum supported version of VS2017 (15.8.28010.0) enforced by installer
  - Improved IntelliSense synchronization
  - Fixed QTVSADDINBUG-545: Missing support for custom installations of Qt
  - Fixed QTVSADDINBUG-771: .pro import does not replace Qt path with $(QTDIR)
  - Fixed QTVSADDINBUG-771: .pro import removes explicit reference to opengl32.lib
Qt Visual Studio Tools version 2.5.0:
Changes
-------
 - New-project wizards will now allow choice of Qt version per configuration (QTVSADDINBUG-737)
 - Added the Qt Quick Application project wizard (QTVSADDINBUG-589)
 - Renamed Qt GUI Application wizard to Qt Widgets Application (QTVSADDINBUG-589)
 - Added support for rcc two-pass mode (QTVSADDINBUG-564)
 - Fixed QTVSADDINBUG-642: Ignoring changes to VS document folder path when deploying .natvis
 - Fixed QTVSADDINBUG-643: Debug visualizer for QHash does not work with const key type
 - Fixed QTVSADDINBUG-644: Error message "Qt not configured" does not identify the project
 - Fixed QTVSADDINBUG-646: QML debugging will not work if command-line arguments are added
 - Fixed QTVSADDINBUG-647: If no Qt version is configured in VS, a generic error message is shown
 - Fixed QTVSADDINBUG-648: Importing .pro shows qmake status and error messages out-of-sync
 - Fixed QTVSADDINBUG-704: Importing .pro ignores private Qt modules
 - Fixed QTVSADDINBUG-711: Incompatibility with VS unity builds
 - Fixed QTVSADDINBUG-721: Target path for Qt properties file cannot be changed
 - Fixed QTVSADDINBUG-732: Importing .pro blindly substitutes the string 'release' in file names
 - Fixed QTVSADDINBUG-733: NDEBUG defined in Release configurations
The Qt Visual Studio Tools version 2.4.3 includes several bug fixes.
Changes
-------
 - Fixed QTVSADDINBUG-560: New Qt projects with duplicate GUID
 - Fixed QTVSADDINBUG-685: Property sheets not working with Qt projects
 - Fixed QTVSADDINBUG-690: All configs not named 'Debug' use release build settings
 - Fixed QTVSADDINBUG-702: Conversion errors when project has empty property values
 - Fixed QTVSADDINBUG-703: Pre-compiled header disabled for generated sources
 - Fixed QTVSADDINBUG-708: Link errors with projects including Windows resources (.rc file)
 - Fixed QTVSADDINBUG-709: Qt-related menu items show in non-Qt project context menu
 - Fixed QTVSADDINBUG-712: Qt INCLUDEPATH property has incorrect values
 - Fixed QTVSADDINBUG-717: Qt project build fails when multiple VS instances are launched
 - Fixed QTVSADDINBUG-722: Error getting Qt property values from generated Makefile
 - Fixed QTVSADDINBUG-723: Projects built multiple times when dependencies are defined
The Qt Visual Studio Tools version 2.4.2 includes several bug fixes.
Changes
-------
 - Fixed QTVSADDINBUG-674: Error importing .pro: "invalid character in path"
 - Fixed QTVSADDINBUG-676: Link error in project with references to other projects
 - Fixed QTVSADDINBUG-681: Error importing .pro using static build of Qt
 - Fixed QTVSADDINBUG-683: Error building with long PATH value
 - Fixed QTVSADDINBUG-684: Build error: " was unexpected
 - Fixed QTVSADDINBUG-693: Compiling sources generated by Qt tools produces unexpected .asm files
 - Fixed QTVSADDINBUG-694: Project is never up-to-date
 - Fixed QTVSADDINBUG-699: Error compiling qrc-generated sources with pre-compiled headers
The Qt Visual Studio Tools version 2.4.1 includes several bug fixes.
Rev. 12
-------
 - Fixed QTVSADDINBUG-663: Project format conversion fails due to unexpected elements in .vcxproj
 - Fixed QTVSADDINBUG-665: $(DefaultVersion) no longer works
 - Fixed QTVSADDINBUG-670: Unicode WinAPI functions called despite using multi-byte char set
 - Fixed QTVSADDINBUG-671: Error "command too long" when using static build of Qt
 - Fixed QTVSADDINBUG-672: Extension does not load in VS2019 v16.2 or earlier
 - Fixed QTVSADDINBUG-673: Intellisense is unable to locate Qt headers
 - Fixed QTVSADDINBUG-680: Build errors when using an earlier version of Qt (<= 5.7)
 - Fixed QTVSADDINBUG-682: Menu open "Qt Project Settings" opens empty dialog
Changes
-------
 - Fixed QTVSADDINBUG-391: Qt VS Tools no longer works with static builds
 - Fixed QTVSADDINBUG-496: VS crashes if no Qt version is installed
 - Fixed QTVSADDINBUG-545: No support for third-party library managers (e.g. vcpkg)
 - Fixed QTVSADDINBUG-597: Converted projects lose excluded-from-build settings
 - Fixed QTVSADDINBUG-640: Qt tools not invoked if project includes a "custom build step"
 - Fixed QTVSADDINBUG-650: Setting the QtInstall property to a path does not work
 - Fixed QTVSADDINBUG-651: The QtInstall property does not expand macros
 - Fixed QTVSADDINBUG-653: Build errors when using configuration names containing spaces
 - Fixed QTVSADDINBUG-657: Projects imported from .pro files lose reference to QtHelp module
 - Fixed QTVSADDINBUG-658: Build errors in Qt project with pre-compiled headers
 - Fixed QTVSADDINBUG-661: Selected files build: missing path to uic-generated headers
The Qt Visual Studio Tools version 2.4.0 implements Qt project settings as MSBuild properties, and
also adds support for Qt Remote Objects.
Changes
-------
 - Qt settings are now stored as fully fledged MSBuild properties (QTVSADDINBUG-575)
 - Added support for Qt Remote Objects (QTVSADDINBUG-585)
 - Fixed QTVSADDINBUG-598: Cannot export library projects to .pro files
 - Fixed QTVSADDINBUG-632: Include path out-of-sync between moc and C++ compiler
The Qt Visual Studio Tools version 2.3.2 contains several bug fixes.
Changes
-------
- Fixed QTVSADDINBUG-601: Pressing Alt-F1 crashes VS or fails to find selected documentation
- Fixed QTVSADDINBUG-608: Error in QRC compilation when paths contain spaces
- Fixed QTVSADDINBUG-609: C++ compiler output directories are not created
- Fixed QTVSADDINBUG-610: QML debug blocked when path to executable contains spaces
- Fixed QTVSADDINBUG-611: Build errors when combining RelativeDir with absolute paths in Qt tools
- Fixed QTVSADDINBUG-613: Project dependencies ignored
- Fixed QTVSADDINBUG-615: Unable to set breakpoints in .js files
- Fixed QTVSADDINBUG-618: Error when building with FIPS group policy enabled
- Will now display the version of the Qt Visual Studio Tools in the main menu (QTVSADDINBUG-607).
The Qt Visual Studio Tools version 2.3.1 adds support for Visual Studio 2019. This version also
includes fixes to bugs reported in the previous version.
Changes
-------
- Added support for Visual Studio 2019
- Extension initialization will now run in the background
- Fixed QTVSADDINBUG-583: Incorrect conversion of custom build to Qt/MSBuild
- Fixed QTVSADDINBUG-592: Custom build steps running after Qt tools and C++ compilation
- Fixed QTVSADDINBUG-593: .natvis files not installed if visualizers directory does not yet exist
- Fixed QTVSADDINBUG-594: Failed to build project with QRC files and precompiled headers
- Fixed QTVSADDINBUG-599: Debug session frozen if QML debugging is enabled
- Fixed QTVSADDINBUG-601: Pressing Alt+F1 for help on a Qt class member crashes Visual Studio
- Fixed QTVSADDINBUG-604: Conversion to Qt/MSBuild seems to freeze when errors occur
The Qt Visual Studio Tools version 2.3.0 introduces QML debugging in Visual Studio, as well as the
ahead-of-time compilation of QML files using the Qt Quick Compiler. This release also includes a
number of bug fixes.
Changes
-------
- Debug QML programs in the Visual Studio IDE
- Ahead-of-time compilation of QML files using the Qt Quick Compiler
- Fixed QTVSADDINBUG-120: Output directories (MOC_DIR, UI_DIR, RCC_DIR) in imported .pro ignored
- Fixed QTVSADDINBUG-378: Debug data visualization not working with Qt built with namespace
- Fixed QTVSADDINBUG-526: QRC not rebuilt if resources are updated
- Fixed QTVSADDINBUG-550: Standard Visual Studio macros not allowed in rcc and uic path setting
- Fixed QTVSADDINBUG-584: Compilation of selected files (i.e. 'right-click' > 'Compile') not working
The Qt Visual Studio Tools version 2.2.2 contains several bug fixes.
Changes
-------
- Fixed QTVSADDINBUG-544: Build is never up-to-date, even if no files have been changed.
- Fixed QTVSADDINBUG-551: Qt VS Tools adds a delay to Visual Studio startup.
- Fixed QTVSADDINBUG-558: Missing Qt module: Data Visualization
- Fixed QTVSADDINBUG-559: Missing Qt module: Charts
- Fixed QTVSADDINBUG-563: Error "same key already added" when converting project to Qt/MSBuild
- Fixed QTVSADDINBUG-566: Error converting to Qt/MSBuild if custom build command has a newline
- Fixed QTVSADDINBUG-569: %QTMSBUILD% environment variable always overwritten at start-up
The Qt Visual Studio Tools version 2.2.1 contains several bug fixes.
Changes
-------
- Fixed QTVSADDINBUG-509: Noticeable delays when saving any .cpp file in larger projects created
  with previous versions of the Qt VS Tools
- Fixed QTVSADDINBUG-510: Errors converting .pro files with long INCLUDEPATH definitions
- Fixed QTVSADDINBUG-511: Incorrect usage of $(IntDir) in the definition of QtWorkFilePath
- Fixed QTVSADDINBUG-512: PrecompiledHeaders.h include missing in moc after adding new class
- Fixed QTVSADDINBUG-514: Quotes removed from preprocessor definition
- Fixed QTVSADDINBUG-515: Visual Studio unresponsive while Converting custom build to Qt/MSBuild
- Fixed QTVSADDINBUG-520: Delay when starting build in solutions with many projects/configurations
- Fixed QTVSADDINBUG-521: Unable to use Qt version if it was built with -qtlibinfix
- Fixed QTVSADDINBUG-522: Duplicating defines and include paths from moc in the C++ dynamic source
- Fixed QTVSADDINBUG-523: Qt VS Tools stopped working with static builds
- Fixed QTVSADDINBUG-530: When a file includes the generated moc output for a header file as well
  as its own generated moc output then it will fail to build
- Fixed QTVSADDINBUG-531: Project not being built when a .uic or .qrc file is changed
- Fixed QTVSADDINBUG-532: Delay when continuing execution after hitting breakpoint
- Fixed QTVSADDINBUG-533: Errors in conversion to Qt/MSBuild when using MOC_DIR or the '@' option
- Fixed QTVSADDINBUG-534: Problems with inheritance of properties defined in property sheets.
- Fixed QTVSADDINBUG-535: Problems with incremental build
- Fixed QTVSADDINBUG-537: Delay after changing C++ properties in large project
- Fixed QTVSADDINBUG-538: Incorrect escaping of paths in command line strings
The Qt Visual Studio Tools version 2.2.0 is the first official release of the Visual Studio add-in
for Visual Studio 2017, 2015 and 2013.
Changes
-------
- New approach to moc, rcc and uic integration using MSBuild rules and targets
- No longer adds generated files to projects
- Creates Universal Windows projects when using a WinRT version of Qt
- Allows import of .pro files using a WinRT version of Qt
- Optimized the performance of adding header files (QTVSADDINBUG-64)
- Optimized the performance of the .pro import procedure (QTVSADDINBUG-442)
- Parallel execution of moc, rcc and uic processes (QTVSADDINBUG-124)
- Uses multi-processor compilation of C++ by default (QTVSADDINBUG-443)
- Updated list of Qt modules (QTVSADDINBUG-411)
- Fixed QTVSADDINBUG-105: moced source files are output to the same directory, prone to filename
  clashes
- Fixed QTVSADDINBUG-140: VS2012 Doesn't start-up anymore correctly after VSAddin usage.
- Fixed QTVSADDINBUG-363: When the QTDIR variable is set after the LocalDebuggerEnvironment
  variable in the users file for a project then it will not find the debugger
- Fixed QTVSADDINBUG-439: Visual Studio Addin creates bad project file if "flat" flag is removed
  from config before converting to Visual Studio project
- Fixed QTVSADDINBUG-479: Error building Qt projects in VS 2017: SDK not found
- Fixed QTVSADDINBUG-485: Microsoft.Cpp.$(Platform).user.props absent
- Fixed QTVSADDINBUG-489: When a qrc file is added to the project it is defaulting to being
  processed with -no-compress which is not the default on the command line
- Fixed QTVSADDINBUG-491: lupdate no longer works via Visual Studio Add-in
- Fixed QTVSADDINBUG-493: The application exited with an error (ExitCode 1)
- Fixed QTVSADDINBUG-504: Changing the project's Qt from Desktop to UWP causes linker errors
- Fixed QTVSADDINBUG-505: Opening a .pro file that does not contain Qt3D causes "3D module" to be
  checked in project's Qt settings
The Qt Visual Studio Tools version 2.1.2 contains support for VS 2017 and several bug fixes.
QTVSADDINBUG-459: Fix reported issues against the VS2017 beta release
QTVSADDINBUG-396: Fix new item with VS not generating the moc
QTVSADDINBUG-472: Fix opening pro file with Qt 5.9
QTVSADDINBUG-460: Fix package containing corrupted data
The Qt Visual Studio Tools version 2.1.1 contains a bug fix for QTVSADDINBUG-453
The Qt Visual Studio Tools version 2.1.0 contains improvements for QML syntax highlighting and
several bug fixes.
- Some speed improvements while importing large qmake based projects
- Better handling of $(QTDIR) environment and possible related errors
- Use TextMate language files for QML and qmake syntax highlighting (VS 2015)
- QTVSADDINBUG-445: Fix wrong usage of QT_STATIC and QT_DLL
- QTVSADDINBUG-407: Fix Environment variables are not saved/restored after VS restart
The Qt Visual Studio Tools version 2.0.0 is an update of the existing Add-In implementation
to the newer Visual Studio Package (VSIX extension) system.
Changes
-------
- Rewrite the Add-In as VSIX extension
- Known issues: Missing QML, help and localization support
The Qt Visual Studio Add-In version 1.2.5 contains an update of the Qt documentation
and some bug fixes.
Changes
-------
- Qt 5.6 help documents included.
- Fixed wrong VCProjectEngine dependency for 2012 installer, which prevented the Add-In from being
  loaded (QTVSADDINBUG-392)
- Use correct solution platform when creating projects using x64 Qt build (QTVSADDINBUG-377)
- Fixed several issues with projects' Qt modules settings (QTVSADDINBUG-344, QTVSADDINBUG-359,
  QTVSADDINBUG-388, QTVSADDINBUG-390)
- Do not overwrite debugging environment on project loading (QTVSADDINBUG-375)
- Fixed issues that prevented Qt 5.6 version from being registered to the Add-In (QTVSADDINBUG-418)
The Qt Visual Studio Add-In version 1.2.4 contains updated help
documents and a bug fixes.
Changes
-------
- Qt 5.4 help documents included.
- Fixed crash when creating new Qt5 app in VS2008 (QTVSADDINBUG-385)
The Qt Visual Studio Add-In version 1.2.3 contains support for VS2013,
updated help documents and some bug fixes.
Changes
-------
- Visual Studio 2013 support.
- Qt 5.3 help documents included.
- Handle wchar_t as builtin type, fixed. (QTVSADDINBUG-171)
- Fix for detecting wince build. (QTVSADDINBUG-176)
- Release project with debug info enabled links wrong qt dll's, fixed.(QTVSADDINBUG-350)
- Generated pri/pro files have mixed line endings (LF/CRLF), fixed.(QTVSADDINBUG-351)
- Intermediate Directory needs a trailing slash, fixed.(QTVSADDINBUG-356)
The Qt Visual Studio Add-In version 1.2.2 contains updated help documents and
two bug fixes.
Changes
-------
- Qt 5.1 help documents included.
- Incorrect overwriting of the environment setting value on every build/run
  removed. (QTVSADDINBUG-159)
- Links in Qt help not working, fixed. (QTVSADDINBUG-160)
The Qt Visual Studio Add-In version 1.2.1 contains multiple bugfixes and
improvements.
Changes
-------
- Qt 5.0.1 help documents included
- Qmake wrapper COM component removed and replaced with command line tool
  qmakefilereader to avoid need to load Qt5 library binaries to Visual Studio
  process. And to get installation of add-in easier, especially with VS2008.
- Qt4 add-in is not allowed to run same time, if found it will be closed.
  Also if Qt4 add-in is present in system, default editor values for .ts, .ui
  and .qrc file types are not permanently overwritten by Qt5 add-in. Values are
  written when Qt5 add-in loads and Qt4 values are set when Qt5 add-in unloads.
  This should make it possible to install and use both Qt4 and Qt5 versions of
  add-in. Not to use same time but in turns. Though user must be careful what he
  does.
- Recognizing Qt5 CE build. (QTVSADDINBUG-153)
- Incorrect additional directories paths set when Qt modules added/removed from
  Qt Project Settings page. (QTVSADDINBUG-151)
- Include directories search path for some Qt modules fixed (QTVSADDINBUG-150)
- Invalid Qt module names fixed (QTVSADDINBUG-142)
- Crash when importing .pri file fixed (QTVSADDINBUG-139)
- Qt default settings saving problem fixed (QTVSADDINBUG-137)
- Naming of precompiled header fixed (QTVSADDINBUG-132)
- Support for debugger visualizers in VS2012 (QTVSADDINBUG-129)
- Setting Qt libraries path for debugging session fixed (QTVSADDINBUG-125)
The Qt Visual Studio Add-In version 1.2.0 supports Qt 5.0.
Changes
-------
- Parameter passing to lupdate fixed (QTVSADDINBUG-131)
- Project creation wizards updated to follow Qt5 module structure
- Project settings form updated to follow Qt5 module structure
- Help documents updated to Qt5
- No more Qt4 project creation wizards and project settings
- Support for Visual Studio 2012
- All project files (*.sln, *.csproj etc) are renamed to Qt5
The Qt Visual Studio Add-In version 1.1.11 contains multiple bugfixes and
improvements.
Changes
-------
- Documentation updated
- Documentation support for Visual Studio 2010. (QTVSADDINBUG-15)
- Fixed always moc'ing problem. (QTVSADDINBUG-92)
- Fixed .pro file opening having include to "." path. (QTVSADDINBUG-117)
- Removed extra back slashes from qmake arg paths.
- Fixed some additional include dir handling causing same path to be added multiple times to custom
  build step.
The Qt Visual Studio Add-In version 1.1.10 contains multiple bugfixes and
improvements.
Changes
-------
- Be aware of comments when parsing qmake.conf. (QTVSADDINBUG-76)
- Fixed exception when using using unsupported lupdate parameters. (QTVSADDINGBUG-70)
- Detecting the MSVC version from qmake.conf was fixed.
- Added QtScriptTools and QtUiTools to project settings. (QTVSADDINBUG-71)
- Removed the MSVC version check when adding Qt versions. As this "feature" seems to cause more
  trouble than it solves, we decided to remove it. Checking for the makefile generator should at
  least prevent people from trying to add MinGW builds.
- Fixed creation of addin projects from 64 bit Qt qmake projects.
- Do not add the include path "$QTDIR/include/qtmain".
  This path is a relict and confuses IntelliSense. (QTVSADDINBUG-81)
- Be aware of strings when looking for Q_OBJECT macros. (QTVSADDINBUG-75)
- Fix problems with the debugging environment. (QTVSADDINBUG-93)
- Pass correct QtDesigner4.lib library name to linker. (QTVSADDINBUG-85)
- Fix cleaning of autoexp.dat on uninstallation for VS 2005. (QTVSADDINBUG-67)
- Use slashes as path separators in includes in moc files. (QTVSADDINBUG-84)
- Choose a valid Qt version if the default Qt version becomes invalid. (QTVSADDINBUG-60)
- Prevent infinite loop if QtAppWrapper cannot connect. (QTVSADDINBUG-73)
- Add and remove the correct OpenGL libraries when changing project's Qt version. (QTVSADDINBUG-80)
- Use project macro for filenames in moc step. (QTVSADDINBUG-30)
- Fixed batch builds of Qt projects for multiple platforms. (QTVSADDINBUG-51)
The Qt Visual Studio Add-In version 1.1.9 contains multiple bugfixes and
improvements.
Changes
-------
- Fix a regression when importing .pro files that was introduced in 1.1.8.
- Make the add-in work with Intel VTune projects. (QTVSADDINBUG-65)
- Check for compatibility with VS version when adding new Qt version. This will hopefully stop
  people from trying to use a MinGW Qt build with Visual Studio. (QTVSADDINBUG-58)
- Added possiblity to specifiy lupdate/lrelease options. (QTVSADDINBUG-48)
The Qt Visual Studio Add-In version 1.1.8 contains multiple bugfixes and
improvements.
Changes
-------
- Do not save the QTDIR in a property sheet for VS 2010. (QTVSADDINBUG-12)
- QtDeclarative module added to the modules page and wizards. (QTVSADDINBUG-44)
- Fix import of .pri files. (QTVSADDINBUG-38)
- Save the modified generated .vc(x)proj after .pro file import. (QTVSADDINBUG-40)
- Proper handling of moc file exclusion when saving cpp files. (QTVSADDINBUG-33)
- Remove user macro from property sheed when $(QTDIR) is used in VS2010. (QTVSADDINBUG-12)
- Documented possibility to add $(QTDIR) version. (QTVSADDINGBUG-19)
- Fix broken include paths in moc calls for VS 2010. (QTVSADDINBUG-34)
- Fix import of previously unloaded projects. (QTVSADDINBUG-31)
- Preserve line breaks in custom build steps after import. (QTVSADDINBUG-32)
- Fix exception that could be raised when changing the Qt version of solutions that contained
  non-C++ projects. (QTVSADDINBUG-50)
- Fix moc command line creation for include paths that contain whitespace
  characters. (QTVSADDINBUG-53)
- Fixed the Windows CE wizards that stopped working under certain circumstances. (QTVSADDINBUG-42)
- Several fixes for Windows CE project generation.
- Qt 4.7.2 documentation included.
The Qt Visual Studio Add-In version 1.1.7 contains multiple bugfixes and
improvements.
Changes
-------
- Fix import of .pro files with "CONFIG -= flat". (QTVSADDINBUG-10)
- Fix naming of classes in generated .ui files. (QTVSADDINBUG-9)
- Visualizers for QPolygon and QPolygonF fixed. (QTVSADDINBUG-8)
- Fix expanding filters on build.
- Fix Qt 4.7 qmake warning wrt backslash escaping on import.
- VS2010: fix AddMocStep for new header files. (QTVSADDINBUG-2)
- GUI class wizard: fix .ui file overwriting check. (QTVSADDINBUG-3)
- When adding moc step, do not assume that cpp file is present. (QTVSADDINBUG-1)
The Qt Visual Studio Add-In version 1.1.6 contains multiple bugfixes and
improvements.
Changes
-------
- Fixed collapse of Generated files after import/build on Visual Studio
2005. (QTBUG-4750)
- Support for Visual Studio 2010. (QTBUG-5374)
- Added check for invalid variables in Rcc/Uic directories in Qt (project) settings. (QTBUG-6818)
- Updated documentation for changing the target platform. (QTBUG-7262)
- Translate filter names on .pro file import or when switching from a qmake generated
  (qmake -tp vc) project to an Add-in project. (QTBUG-11325)
- Fixed regression in custom build step generation. (QTBUG-11527)
- Fixed "Change Solution's Qt version" for solutions that contain Intel Fortran
  projects. (QTBUG-11567)
- Fix output paths for custom build steps in release configuration. (QTBUG-12145)
- Fix import if CONFIG contains "silent". (QTBUG-12344)
- Phonon is added automatically if WebKit is selected. (QTBUG-10154)
- Fixed display of uninitialized QSet and QHash object. (QTBUG-12890)
The Qt Visual Studio Add-In version 1.1.5 contains multiple bugfixes and
improvements.
Changes
-------
- Fixed setting of preprocessor definitions when changing to a Windows CE Qt version. (QTBUG-10564)
- Added contribution for QMap visualization. (QTBUG-3970)
- Recursively look for includes/defines in PropertySheets. (QTBUG-10406)
- Fixed bugs affecting Q_OBJECTs in .cpp files.
- On import, the content of .qrc files is added to the Resources filter of the Visual Studio
  project. (QTBUG-10113)
- QRC Editor: The add-in will synchronize the list of resources in a .qrc file with the files in
  the Resources filter of the project.  (QTBUG-6103)
- QRC Editor: show full resource URL. (QTBUG-3801)
- Refresh moc steps when PCH options are changed. (QTBUG-7700)
- You don't have to be admin anymore to set Windows CE Qt versions. (QTBUG-9550)
- QtAppWrapper: Do not stop listening to new connections if error occurs. (QTBUG-8508)
- Handle C++ comments correctly. (QTBUG-7641)
- Support $(PlatformName) for moc, uic and rcc directories. (QTBUG-5814)
- Fixed exception when exporting non-C++ projects. (QTBUG-9234)
- Fixed module handling for static libraries. (QTBUG-8670)
- Resolve %BASECLASS% in Qt4Class template again, to keep old custom class wizard additions
  working. (QTBUG-8615)
- Fixed wrong DLL names in Windows CE deployment of Qt modules. (QTBUG-8622)
- Fixed import of .pro files with library dependency paths that contain whitespace
  characters. (QTBUG-8493)
- Added possibility to use mocDir without $(ConfigurationName). (QTBUG-7288)
- Fixed import for projects with relative moc dir settings. (QTBUG-8372)
- Fixed import for project without resources.
- Don't depend on .NET Framework 3.5 SP1. (QTBUG-8415)
- Fix moc steps for file names, that are contain substrings of variables,
  like "Config.h" (QTBUG-8218)
- Detection of invalid class names in projects wizards. (QTBUG-8154)
- Fixed creation of translation files when custom cultures are present. (QTBUG-11124)
The Qt Visual Studio Add-In version 1.1.4 contains multiple bugfixes and
improvements.
Changes
-------
- Several bugs when opening .ui and .ts files have been fixed. The qtappwrapper has been
  overhauled. (QTBUG-6857, QTBUG-7491)
- Importing .pro files with source files in subdirectories does not longer cause creation of
  invalid moc steps. (QTBUG-7603)
- The Qt Multimedia module is now available in all project wizards and the Qt modules
  dialog. (QTBUG-7487)
- The "Generated Files" filter is collapsed after .pro file import. (QTBUG-7687)
- Automatically checkout .ui, .qrc and .ts files if they are under source control. (QTBUG-7680)
- Remove .res files from the "Generated Files" filter after .pro file import as
  they are not needed. (QTBUG-7494)
- Class wizards: Take care of forbidden characters when building include guards for
  header files. (QTBUG-7811)
- Fix exception when accessing the Qt project settings for projects, that do not have
  a compiler tool. (QTBUG-7930)
- Fix bug in moc step update, which occured when there was more than one file in
  the "Outputs" property of the custom build step. (QTBUG-7937)
- Added an option to turn off the automatic moc steps update. (QTBUG-7938)
The Qt Visual Studio Add-In version 1.1.3 contains multiple bugfixes and
improvements.
Changes
-------
- Added checks to avoid unneeded access to .vcproj file when saving files
  with Q_OBJECT. (QTBUG-5813)
- When using Visual Studio 2005 the project tree is no longer expanded
  after each build. (QTBUG-6482)
- Switching between qmake and AddIn projects more robust. (QTBUG-6434)
- Set target machine explicitly when changing Qt version. (QTBUG-5206)
- Work around Visual Studio bug to support the simplified Chinese
  version of Visual Studio.  (QTBUG-6318)
- Fixed bug for Windows CE static builds. (QTBUG-3493)
- Create signature step for Windows CE projects. (QTBUG-3493)
- Fixed visualizers for QList and QMap. (very simple version for QMap as
  an appropiate visualization seems impossible in autoexp.dat) (QTBUG-660
  and QTBUG-3970)
- Fixed visualizers for QVector. (QTBUG-7121)
- Support empty base classes in Qt4Class wizard. (QTBUG-6797)
- Support namespaces when creating Qt classes. (QTBUG-5227)
The Qt Visual Studio Add-In version 1.1.2 contains multiple bugfixes and
improvements.
Changes
-------
- Fixed various problems concerning precompiled headers (stdafx as default
  (QTBUG-5226), change of settings when building...)
- Increased support for solution folders (QTBUG-4914)
- Detection of solution .pro files fixed (be aware of possible newline
  after \)
- Fixed bug, which could appear when moc steps had to be updated.
  The update caused an invalid moc commandline which made the build fail.
- Added support for Q_Gadget macro(QTBUG-5291)
- Project tree is not expanded on every build when using VS2005 (QTBUG-5291)
- Fixed conversion from AddIn project to Qmake project and vice
  versa (QTBUG5380)
- Repair moc path when importing .pro file (QTBUG-4221)
- Support of commandline builds (QTBUG-5321)
  (In VS2005 there are some issues when trying to load AddIns from the
  commandline. See http://support.microsoft.com/kb/934517)
The Qt Visual Studio Add-In version 1.1.1 contains multiple bugfixes and
improvements.
Changes
-------
- Fixed startup of Qt Designer and Qt Linguist when the application was
  not build for the current project's Qt Version. The Add-In tries to find
  the needed tool inside the directory of the other registered Qt Versions.
- "Generate basic pro file" gets disabled in project's context menu and Qt
  menu if the current project is a qmake generated project.
- When importing a solution file while a solution is opened, the user gets
  the possibility to automatically close the current solution.
- Avoid infinite recursion in inclusion which happened when moccing .cpp
  files, which used precompiled headers.
- Translation files are added when exporting project to a .pri file.
- Project is cleaned, when its Qt version is changed.
- As there is no way to avoid the expansion of generated files filter when
  the project is built the first time, the generated files are collapsed
  after the build has finished (QTBUG-4750).
- Changing the project's Qt Version after importing a .pro file does not
  longer make the build fail (QTBUG-4756)
- Exclusion of .cpp and .h files cause the mocced files to be excluded from
  build too (QTBUG-3404)
- Adding a Qt class no longer implies that precompiled headers are used.
- Fixed processing of lupdate in projects with a big amount of files
(QTBUG-4783).
The Qt Visual Studio Add-In version 1.1.0 contains multiple bugfixes and
improvements.
Changes
-------
- The custom build step generation has been changed to use a subfolder for
  every configuration. This solves the problem of heavy changes in the vcproj
  file whenever the user switches to another build configuration. (Task 251918)
- Qt Designer, Qt Linguist and the QRC Editor are started via a properly
  registered editor wrapper. Now its possible to open ui files in other
  editors, like the built-in XML editor. (Task 250601)
- Projects can be converted from Qt Add-in projects to qmake generated
  projects and back. (Task 153484)
- Fixing the behaviour of adding a file to a filter. (Task 254968)
- Opening a vcproj file that has a non-defined Qt version works now like in
  the old Qt VS integration. (Task 258704)
- The detection of Windows CE Qt builds has been fixed.
- OpenGL Desktop Windows libraries aren't added to linker options in
  Windows CE projects. (Task 260550)
- If there's no Generated Files folder, then we don't try to delete its
  content. (Task 260723)
- Fix bug for solutions that contain disabled (unloaded) projects. (Task 259807)
- Switching between static and dynamic Qt builds has been fixed.
- Add-in's documentation has been updated.
The Qt Visual Studio Add-In version 1.0.2 contains multiple bugfixes.
Changes
-------
- Platform was not set correctly when solution contains several projects.
- Repair broken QTDIR Variable when project is added to solution.
- Fix problem with dots in pro file names.
- Qt module Phonon added to wizards and dialogs.
- Don't mess around with whitespaces in every source file we add. (Task  251987)
- Prevent duplicates in additional dependencies, includes etc.
- Fix rare exception when importing solution pro file.
- Fix switching between static and dynamic Qt build.
- Enable the user to add a "$(QTDIR)" Qt version even if QTDIR is not set.
The Qt Visual Studio Add-In version 1.0.1 contains multiple bugfixes.
Changes
-------
- Qt .pro file import fixed for projects containing SUBDIRS.
- Fixed moc file build exclusion when saving a .cpp file.
- Keep user defined debugging environment when adding the Qt environment.
- Fix the display of full file paths in custom build tool descriptions.
- Documentation updated.
LICENSE.GPL3-EXCEPT
New file
@@ -0,0 +1,704 @@
This is the GNU General Public License version 3, annotated with The
Qt Company GPL Exception 1.0:
-------------------------------------------------------------------------
The Qt Company GPL Exception 1.0
Exception 1:
As a special exception you may create a larger work which contains the
output of this application and distribute that work under terms of your
choice, so long as the work is not otherwise derived from or based on
this application and so long as the work does not in itself generate
output that contains the output from this application in its original
or modified form.
Exception 2:
As a special exception, you have permission to combine this application
with Plugins licensed under the terms of your choice, to produce an
executable, and to copy and distribute the resulting executable under
the terms of your choice. However, the executable must be accompanied
by a prominent notice offering all users of the executable the entire
source code to this application, excluding the source code of the
independent modules, but including any changes you have made to this
application, under the terms of this license.
-------------------------------------------------------------------------
                    GNU GENERAL PUBLIC LICENSE
                       Version 3, 29 June 2007
 Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.
                            Preamble
  The GNU General Public License is a free, copyleft license for
software and other kinds of works.
  The licenses for most software and other practical works are designed
to take away your freedom to share and change the works.  By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.  We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors.  You can apply it to
your programs, too.
  When we speak of free software, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
  To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights.  Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
  For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received.  You must make sure that they, too, receive
or can get the source code.  And you must show them these terms so they
know their rights.
  Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
  For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software.  For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
  Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so.  This is fundamentally incompatible with the aim of
protecting users' freedom to change the software.  The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable.  Therefore, we
have designed this version of the GPL to prohibit the practice for those
products.  If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
  Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary.  To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
  The precise terms and conditions for copying, distribution and
modification follow.
                       TERMS AND CONDITIONS
  0. Definitions.
  "This License" refers to version 3 of the GNU General Public License.
  "Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
  "The Program" refers to any copyrightable work licensed under this
License.  Each licensee is addressed as "you".  "Licensees" and
"recipients" may be individuals or organizations.
  To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy.  The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
  A "covered work" means either the unmodified Program or a work based
on the Program.
  To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy.  Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
  To "convey" a work means any kind of propagation that enables other
parties to make or receive copies.  Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
  An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License.  If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
  1. Source Code.
  The "source code" for a work means the preferred form of the work
for making modifications to it.  "Object code" means any non-source
form of a work.
  A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
  The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form.  A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
  The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities.  However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work.  For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
  The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
  The Corresponding Source for a work in source code form is that
same work.
  2. Basic Permissions.
  All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met.  This License explicitly affirms your unlimited
permission to run the unmodified Program.  The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work.  This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
  You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force.  You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright.  Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
  Conveying under any other circumstances is permitted solely under
the conditions stated below.  Sublicensing is not allowed; section 10
makes it unnecessary.
  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
  No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
  When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
  4. Conveying Verbatim Copies.
  You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
  You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
  5. Conveying Modified Source Versions.
  You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
    a) The work must carry prominent notices stating that you modified
    it, and giving a relevant date.
    b) The work must carry prominent notices stating that it is
    released under this License and any conditions added under section
    7.  This requirement modifies the requirement in section 4 to
    "keep intact all notices".
    c) You must license the entire work, as a whole, under this
    License to anyone who comes into possession of a copy.  This
    License will therefore apply, along with any applicable section 7
    additional terms, to the whole of the work, and all its parts,
    regardless of how they are packaged.  This License gives no
    permission to license the work in any other way, but it does not
    invalidate such permission if you have separately received it.
    d) If the work has interactive user interfaces, each must display
    Appropriate Legal Notices; however, if the Program has interactive
    interfaces that do not display Appropriate Legal Notices, your
    work need not make them do so.
  A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit.  Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
  6. Conveying Non-Source Forms.
  You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
    a) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by the
    Corresponding Source fixed on a durable physical medium
    customarily used for software interchange.
    b) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by a
    written offer, valid for at least three years and valid for as
    long as you offer spare parts or customer support for that product
    model, to give anyone who possesses the object code either (1) a
    copy of the Corresponding Source for all the software in the
    product that is covered by this License, on a durable physical
    medium customarily used for software interchange, for a price no
    more than your reasonable cost of physically performing this
    conveying of source, or (2) access to copy the
    Corresponding Source from a network server at no charge.
    c) Convey individual copies of the object code with a copy of the
    written offer to provide the Corresponding Source.  This
    alternative is allowed only occasionally and noncommercially, and
    only if you received the object code with such an offer, in accord
    with subsection 6b.
    d) Convey the object code by offering access from a designated
    place (gratis or for a charge), and offer equivalent access to the
    Corresponding Source in the same way through the same place at no
    further charge.  You need not require recipients to copy the
    Corresponding Source along with the object code.  If the place to
    copy the object code is a network server, the Corresponding Source
    may be on a different server (operated by you or a third party)
    that supports equivalent copying facilities, provided you maintain
    clear directions next to the object code saying where to find the
    Corresponding Source.  Regardless of what server hosts the
    Corresponding Source, you remain obligated to ensure that it is
    available for as long as needed to satisfy these requirements.
    e) Convey the object code using peer-to-peer transmission, provided
    you inform other peers where the object code and Corresponding
    Source of the work are being offered to the general public at no
    charge under subsection 6d.
  A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
  A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling.  In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage.  For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product.  A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
  "Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source.  The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
  If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information.  But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
  The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed.  Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
  Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
  7. Additional Terms.
  "Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law.  If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
  When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it.  (Additional permissions may be written to require their own
removal in certain cases when you modify the work.)  You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
  Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
    a) Disclaiming warranty or limiting liability differently from the
    terms of sections 15 and 16 of this License; or
    b) Requiring preservation of specified reasonable legal notices or
    author attributions in that material or in the Appropriate Legal
    Notices displayed by works containing it; or
    c) Prohibiting misrepresentation of the origin of that material, or
    requiring that modified versions of such material be marked in
    reasonable ways as different from the original version; or
    d) Limiting the use for publicity purposes of names of licensors or
    authors of the material; or
    e) Declining to grant rights under trademark law for use of some
    trade names, trademarks, or service marks; or
    f) Requiring indemnification of licensors and authors of that
    material by anyone who conveys the material (or modified versions of
    it) with contractual assumptions of liability to the recipient, for
    any liability that these contractual assumptions directly impose on
    those licensors and authors.
  All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10.  If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term.  If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
  If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
  Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
  8. Termination.
  You may not propagate or modify a covered work except as expressly
provided under this License.  Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
  However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
  Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
  Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License.  If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
  9. Acceptance Not Required for Having Copies.
  You are not required to accept this License in order to receive or
run a copy of the Program.  Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance.  However,
nothing other than this License grants you permission to propagate or
modify any covered work.  These actions infringe copyright if you do
not accept this License.  Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
  10. Automatic Licensing of Downstream Recipients.
  Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License.  You are not responsible
for enforcing compliance by third parties with this License.
  An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations.  If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
  You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License.  For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
  11. Patents.
  A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based.  The
work thus licensed is called the contributor's "contributor version".
  A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version.  For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
  Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
  In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement).  To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
  If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients.  "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
  If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
  A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License.  You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
  Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
  12. No Surrender of Others' Freedom.
  If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License.  If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all.  For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
  13. Use with the GNU Affero General Public License.
  Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work.  The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
  14. Revised Versions of this License.
  The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time.  Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
  Each version is given a distinguishing version number.  If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation.  If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
  If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
  Later license versions may give you additional or different
permissions.  However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
  15. Disclaimer of Warranty.
  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
  16. Limitation of Liability.
  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
  17. Interpretation of Sections 15 and 16.
  If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
                     END OF TERMS AND CONDITIONS
            How to Apply These Terms to Your New Programs
  If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
  To do so, attach the following notices to the program.  It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
    <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) <year>  <name of author>
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
  If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
    <program>  Copyright (C) <year>  <name of author>
    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
    This is free software, and you are welcome to redistribute it
    under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License.  Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
  You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
  The GNU General Public License does not permit incorporating your program
into proprietary programs.  If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library.  If this is what you want to do, use the GNU Lesser General
Public License instead of this License.  But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
QMakeFileReader/evalhandler.cpp
New file
@@ -0,0 +1,54 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "evalhandler.h"
void EvalHandler::message(int type, const QString &msg, const QString &fileName, int lineNo)
{
    Q_UNUSED(type);
    Q_UNUSED(msg);
    Q_UNUSED(fileName);
    Q_UNUSED(lineNo);
}
void EvalHandler::fileMessage(const QString &msg)
{
    Q_UNUSED(msg);
}
void EvalHandler::aboutToEval(ProFile *parent, ProFile *proFile, EvalFileType type)
{
    Q_UNUSED(parent);
    Q_UNUSED(proFile);
    Q_UNUSED(type);
}
void EvalHandler::doneWithEval(ProFile *parent)
{
    Q_UNUSED(parent);
}
QMakeFileReader/evalhandler.h
New file
@@ -0,0 +1,46 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef EVALHANDLER_H
#define EVALHANDLER_H
#include <qmakeevaluator.h>
/**
 * Dummy handler to please qmake's parser.
 */
class EvalHandler : public QMakeHandler
{
public:
    void message(int type, const QString &msg, const QString &fileName, int lineNo);
    void fileMessage(const QString &msg);
    void aboutToEval(ProFile *parent, ProFile *proFile, EvalFileType type);
    void doneWithEval(ProFile *parent);
};
#endif // EVALHANDLER_H
QMakeFileReader/evaluator/README
New file
@@ -0,0 +1,6 @@
This is a copy of qmake's parser and evaluator from qmake/library
directory in the qtbase repository at git://gitorious.org/qt/qtbase.git.
It has been taken at 5e525d283d308fe462e83955996fc53d80465c1b.
If you do changes to these files, please make sure they are upstreamed!
QMakeFileReader/evaluator/evaluator.pri
New file
@@ -0,0 +1,22 @@
INCLUDEPATH *= $$PWD
DEPENDPATH *= $$PWD
INCLUDEPATH += \
    $$QMAKE_PARSER_DIR
HEADERS += \
    $$PWD/ioutils.h \
    $$PWD/proitems.h \
    $$PWD/qmakeevaluator.h \
    $$PWD/qmakeevaluator_p.h \
    $$PWD/qmakeglobals.h \
    $$PWD/qmakeparser.h \
    $$PWD/qmake_global.h
SOURCES += \
    $$PWD/ioutils.cpp \
    $$PWD/proitems.cpp \
    $$PWD/qmakebuiltins.cpp \
    $$PWD/qmakeevaluator.cpp \
    $$PWD/qmakeglobals.cpp \
    $$PWD/qmakeparser.cpp
QMakeFileReader/evaluator/ioutils.cpp
New file
@@ -0,0 +1,155 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "ioutils.h"
#include <qdir.h>
#include <qfile.h>
#ifdef Q_OS_WIN
#  include <windows.h>
#else
#  include <sys/types.h>
#  include <sys/stat.h>
#  include <unistd.h>
#endif
QT_BEGIN_NAMESPACE
using namespace QMakeInternal;
IoUtils::FileType IoUtils::fileType(const QString &fileName)
{
    Q_ASSERT(fileName.isEmpty() || isAbsolutePath(fileName));
#ifdef Q_OS_WIN
    DWORD attr = GetFileAttributesW((WCHAR*)fileName.utf16());
    if (attr == INVALID_FILE_ATTRIBUTES)
        return FileNotFound;
    return (attr & FILE_ATTRIBUTE_DIRECTORY) ? FileIsDir : FileIsRegular;
#else
    struct ::stat st;
    if (::stat(fileName.toLocal8Bit().constData(), &st))
        return FileNotFound;
    return S_ISDIR(st.st_mode) ? FileIsDir : FileIsRegular;
#endif
}
bool IoUtils::isRelativePath(const QString &path)
{
    if (path.startsWith(QLatin1Char('/')))
        return false;
#ifdef Q_OS_WIN
    if (path.startsWith(QLatin1Char('\\')))
        return false;
    // Unlike QFileInfo, this won't accept a relative path with a drive letter.
    // Such paths result in a royal mess anyway ...
    if (path.length() >= 3 && path.at(1) == QLatin1Char(':') && path.at(0).isLetter()
        && (path.at(2) == QLatin1Char('/') || path.at(2) == QLatin1Char('\\')))
        return false;
#endif
    return true;
}
QStringRef IoUtils::fileName(const QString &fileName)
{
    return fileName.midRef(fileName.lastIndexOf(QLatin1Char('/')) + 1);
}
QString IoUtils::resolvePath(const QString &baseDir, const QString &fileName)
{
    if (fileName.isEmpty())
        return QString();
    if (isAbsolutePath(fileName))
        return QDir::cleanPath(fileName);
    return QDir::cleanPath(baseDir + QLatin1Char('/') + fileName);
}
inline static
bool hasSpecialChars(const QString &arg, const uchar (&iqm)[16])
{
    for (int x = arg.length() - 1; x >= 0; --x) {
        ushort c = arg.unicode()[x].unicode();
        if ((c < sizeof(iqm) * 8) && (iqm[c / 8] & (1 << (c & 7))))
            return true;
    }
    return false;
}
QString IoUtils::shellQuoteUnix(const QString &arg)
{
    // Chars that should be quoted (TM). This includes:
    static const uchar iqm[] = {
        0xff, 0xff, 0xff, 0xff, 0xdf, 0x07, 0x00, 0xd8,
        0x00, 0x00, 0x00, 0x38, 0x01, 0x00, 0x00, 0x78
    }; // 0-32 \'"$`<>|;&(){}*?#!~[]
    if (!arg.length())
        return QString::fromLatin1("\"\"");
    QString ret(arg);
    if (hasSpecialChars(ret, iqm)) {
        ret.replace(QLatin1Char('\''), QLatin1String("'\\''"));
        ret.prepend(QLatin1Char('\''));
        ret.append(QLatin1Char('\''));
    }
    return ret;
}
QString IoUtils::shellQuoteWin(const QString &arg)
{
    // Chars that should be quoted (TM). This includes:
    // - control chars & space
    // - the shell meta chars "&()<>^|
    // - the potential separators ,;=
    static const uchar iqm[] = {
        0xff, 0xff, 0xff, 0xff, 0x45, 0x13, 0x00, 0x78,
        0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x10
    };
    if (!arg.length())
        return QString::fromLatin1("\"\"");
    QString ret(arg);
    if (hasSpecialChars(ret, iqm)) {
        // Quotes are escaped and their preceding backslashes are doubled.
        // It's impossible to escape anything inside a quoted string on cmd
        // level, so the outer quoting must be "suspended".
        ret.replace(QRegExp(QLatin1String("(\\\\*)\"")), QLatin1String("\"\\1\\1\\^\"\""));
        // The argument must not end with a \ since this would be interpreted
        // as escaping the quote -- rather put the \ behind the quote: e.g.
        // rather use "foo"\ than "foo\"
        int i = ret.length();
        while (i > 0 && ret.at(i - 1) == QLatin1Char('\\'))
            --i;
        ret.insert(i, QLatin1Char('"'));
        ret.prepend(QLatin1Char('"'));
    }
    return ret;
}
QT_END_NAMESPACE
QMakeFileReader/evaluator/ioutils.h
New file
@@ -0,0 +1,70 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef IOUTILS_H
#define IOUTILS_H
#include <qstring.h>
QT_BEGIN_NAMESPACE
namespace QMakeInternal {
/*!
  This class provides replacement functionality for QFileInfo, QFile & QDir,
  as these are abysmally slow.
*/
class IoUtils {
public:
    enum FileType {
        FileNotFound = 0,
        FileIsRegular = 1,
        FileIsDir = 2
    };
    static FileType fileType(const QString &fileName);
    static bool exists(const QString &fileName) { return fileType(fileName) != FileNotFound; }
    static bool isRelativePath(const QString &fileName);
    static bool isAbsolutePath(const QString &fileName) { return !isRelativePath(fileName); }
    static QStringRef fileName(const QString &fileName); // Requires normalized path
    static QString resolvePath(const QString &baseDir, const QString &fileName);
    static QString shellQuoteUnix(const QString &arg);
    static QString shellQuoteWin(const QString &arg);
    static QString shellQuote(const QString &arg)
#ifdef Q_OS_UNIX
        { return shellQuoteUnix(arg); }
#else
        { return shellQuoteWin(arg); }
#endif
};
} // namespace ProFileEvaluatorInternal
QT_END_NAMESPACE
#endif // IOUTILS_H
QMakeFileReader/evaluator/proitems.cpp
New file
@@ -0,0 +1,450 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "proitems.h"
#include <qfileinfo.h>
#include <qset.h>
#include <qstringlist.h>
#include <qtextstream.h>
QT_BEGIN_NAMESPACE
// from qhash.cpp
uint ProString::hash(const QChar *p, int n)
{
    uint h = 0;
    while (n--) {
        h = (h << 4) + (*p++).unicode();
        h ^= (h & 0xf0000000) >> 23;
        h &= 0x0fffffff;
    }
    return h;
}
ProString::ProString() :
    m_offset(0), m_length(0), m_file(0), m_hash(0x80000000)
{
}
ProString::ProString(const ProString &other) :
    m_string(other.m_string), m_offset(other.m_offset), m_length(other.m_length), m_file(other.m_file), m_hash(other.m_hash)
{
}
ProString::ProString(const ProString &other, OmitPreHashing) :
    m_string(other.m_string), m_offset(other.m_offset), m_length(other.m_length), m_file(other.m_file), m_hash(0x80000000)
{
}
ProString::ProString(const QString &str, DoPreHashing) :
    m_string(str), m_offset(0), m_length(str.length()), m_file(0)
{
    updatedHash();
}
ProString::ProString(const QString &str) :
    m_string(str), m_offset(0), m_length(str.length()), m_file(0), m_hash(0x80000000)
{
}
ProString::ProString(const char *str, DoPreHashing) :
    m_string(QString::fromLatin1(str)), m_offset(0), m_length(qstrlen(str)), m_file(0)
{
    updatedHash();
}
ProString::ProString(const char *str) :
    m_string(QString::fromLatin1(str)), m_offset(0), m_length(qstrlen(str)), m_file(0), m_hash(0x80000000)
{
}
ProString::ProString(const QString &str, int offset, int length, DoPreHashing) :
    m_string(str), m_offset(offset), m_length(length), m_file(0)
{
    updatedHash();
}
ProString::ProString(const QString &str, int offset, int length, uint hash) :
    m_string(str), m_offset(offset), m_length(length), m_file(0), m_hash(hash)
{
}
ProString::ProString(const QString &str, int offset, int length) :
    m_string(str), m_offset(offset), m_length(length), m_file(0), m_hash(0x80000000)
{
}
void ProString::setValue(const QString &str)
{
    m_string = str, m_offset = 0, m_length = str.length(), m_hash = 0x80000000;
}
uint ProString::updatedHash() const
{
     return (m_hash = hash(m_string.constData() + m_offset, m_length));
}
uint qHash(const ProString &str)
{
    if (!(str.m_hash & 0x80000000))
        return str.m_hash;
    return str.updatedHash();
}
ProKey::ProKey(const QString &str) :
    ProString(str, DoHash)
{
}
ProKey::ProKey(const char *str) :
    ProString(str, DoHash)
{
}
ProKey::ProKey(const QString &str, int off, int len) :
    ProString(str, off, len, DoHash)
{
}
ProKey::ProKey(const QString &str, int off, int len, uint hash) :
    ProString(str, off, len, hash)
{
}
void ProKey::setValue(const QString &str)
{
    m_string = str, m_offset = 0, m_length = str.length();
    updatedHash();
}
QString ProString::toQString() const
{
    return m_string.mid(m_offset, m_length);
}
QString &ProString::toQString(QString &tmp) const
{
    return tmp.setRawData(m_string.constData() + m_offset, m_length);
}
QChar *ProString::prepareExtend(int extraLen, int thisTarget, int extraTarget)
{
    if (m_string.isDetached() && m_length + extraLen <= m_string.capacity()) {
        m_string.reserve(0); // Prevent the resize() below from reallocating
        QChar *ptr = (QChar *)m_string.constData();
        if (m_offset != thisTarget)
            memmove(ptr + thisTarget, ptr + m_offset, m_length * 2);
        ptr += extraTarget;
        m_offset = 0;
        m_length += extraLen;
        m_string.resize(m_length);
        m_hash = 0x80000000;
        return ptr;
    } else {
        QString neu(m_length + extraLen, Qt::Uninitialized);
        QChar *ptr = (QChar *)neu.constData();
        memcpy(ptr + thisTarget, m_string.constData() + m_offset, m_length * 2);
        ptr += extraTarget;
        *this = ProString(neu);
        return ptr;
    }
}
ProString &ProString::prepend(const ProString &other)
{
    if (other.m_length) {
        if (!m_length) {
            *this = other;
        } else {
            QChar *ptr = prepareExtend(other.m_length, other.m_length, 0);
            memcpy(ptr, other.constData(), other.m_length * 2);
            if (!m_file)
                m_file = other.m_file;
        }
    }
    return *this;
}
ProString &ProString::append(const QLatin1String other)
{
    const char *latin1 = other.latin1();
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
    int size = other.size();
#else
    int size = strlen(latin1);
#endif
    if (size) {
        QChar *ptr = prepareExtend(size, 0, m_length);
        for (int i = 0; i < size; i++)
            *ptr++ = QLatin1Char(latin1[i]);
    }
    return *this;
}
ProString &ProString::append(QChar other)
{
    QChar *ptr = prepareExtend(1, 0, m_length);
    *ptr = other;
    return *this;
}
// If pending != 0, prefix with space if appending to non-empty non-pending
ProString &ProString::append(const ProString &other, bool *pending)
{
    if (other.m_length) {
        if (!m_length) {
            *this = other;
        } else {
            QChar *ptr;
            if (pending && !*pending) {
                ptr = prepareExtend(1 + other.m_length, 0, m_length);
                *ptr++ = 32;
            } else {
                ptr = prepareExtend(other.m_length, 0, m_length);
            }
            memcpy(ptr, other.m_string.constData() + other.m_offset, other.m_length * 2);
            if (other.m_file)
                m_file = other.m_file;
        }
        if (pending)
            *pending = true;
    }
    return *this;
}
ProString &ProString::append(const ProStringList &other, bool *pending, bool skipEmpty1st)
{
    if (const int sz = other.size()) {
        int startIdx = 0;
        if (pending && !*pending && skipEmpty1st && other.at(0).isEmpty()) {
            if (sz == 1)
                return *this;
            startIdx = 1;
        }
        if (!m_length && sz == startIdx + 1) {
            *this = other.at(startIdx);
        } else {
            int totalLength = sz - startIdx;
            for (int i = startIdx; i < sz; ++i)
                totalLength += other.at(i).size();
            bool putSpace = false;
            if (pending && !*pending && m_length)
                putSpace = true;
            else
                totalLength--;
            QChar *ptr = prepareExtend(totalLength, 0, m_length);
            for (int i = startIdx; i < sz; ++i) {
                if (putSpace)
                    *ptr++ = 32;
                else
                    putSpace = true;
                const ProString &str = other.at(i);
                memcpy(ptr, str.m_string.constData() + str.m_offset, str.m_length * 2);
                ptr += str.m_length;
            }
            if (other.last().m_file)
                m_file = other.last().m_file;
        }
        if (pending)
            *pending = true;
    }
    return *this;
}
QString operator+(const ProString &one, const ProString &two)
{
    if (two.m_length) {
        if (!one.m_length) {
            return two.toQString();
        } else {
            QString neu(one.m_length + two.m_length, Qt::Uninitialized);
            ushort *ptr = (ushort *)neu.constData();
            memcpy(ptr, one.m_string.constData() + one.m_offset, one.m_length * 2);
            memcpy(ptr + one.m_length, two.m_string.constData() + two.m_offset, two.m_length * 2);
            return neu;
        }
    }
    return one.toQString();
}
ProString ProString::mid(int off, int len) const
{
    ProString ret(*this, NoHash);
    if (off > m_length)
        off = m_length;
    ret.m_offset += off;
    ret.m_length -= off;
    if ((uint)ret.m_length > (uint)len)  // Unsigned comparison to interpret < 0 as infinite
        ret.m_length = len;
    return ret;
}
ProString ProString::trimmed() const
{
    ProString ret(*this, NoHash);
    int cur = m_offset;
    int end = cur + m_length;
    const QChar *data = m_string.constData();
    for (; cur < end; cur++)
        if (!data[cur].isSpace()) {
            // No underrun check - we know there is at least one non-whitespace
            while (data[end - 1].isSpace())
                end--;
            break;
        }
    ret.m_offset = cur;
    ret.m_length = end - cur;
    return ret;
}
QTextStream &operator<<(QTextStream &t, const ProString &str)
{
    t << str.toQString(); // XXX optimize ... somehow
    return t;
}
static QString ProStringList_join(const ProStringList &this_, const QChar *sep, const size_t sepSize)
{
    int totalLength = 0;
    const int sz = this_.size();
    for (int i = 0; i < sz; ++i)
        totalLength += this_.at(i).size();
    if (sz)
        totalLength += sepSize * (sz - 1);
    QString res(totalLength, Qt::Uninitialized);
    QChar *ptr = (QChar *)res.constData();
    for (int i = 0; i < sz; ++i) {
        if (i) {
            memcpy(ptr, sep, sepSize * sizeof(QChar));
            ptr += sepSize;
        }
        const ProString &str = this_.at(i);
        memcpy(ptr, str.constData(), str.size() * sizeof(QChar));
        ptr += str.size();
    }
    return res;
}
QString ProStringList::join(const QString &sep) const
{
    return ProStringList_join(*this, sep.constData(), sep.size());
}
QString ProStringList::join(QChar sep) const
{
    return ProStringList_join(*this, &sep, 1);
}
void ProStringList::removeAll(const ProString &str)
{
    for (int i = size(); --i >= 0; )
        if (at(i) == str)
            remove(i);
}
void ProStringList::removeAll(const char *str)
{
    for (int i = size(); --i >= 0; )
        if (at(i) == str)
            remove(i);
}
void ProStringList::removeDuplicates()
{
    int n = size();
    int j = 0;
    QSet<ProString> seen;
    seen.reserve(n);
    for (int i = 0; i < n; ++i) {
        const ProString &s = at(i);
        if (seen.contains(s))
            continue;
        seen.insert(s);
        if (j != i)
            (*this)[j] = s;
        ++j;
    }
    if (n != j)
        erase(begin() + j, end());
}
ProStringList::ProStringList(const QStringList &list)
{
    reserve(list.size());
    foreach (const QString &str, list)
        *this << ProString(str);
}
QStringList ProStringList::toQStringList() const
{
    QStringList ret;
    ret.reserve(size());
    foreach (const ProString &str, *this)
        ret << str.toQString();
    return ret;
}
bool ProStringList::contains(const ProString &str, Qt::CaseSensitivity cs) const
{
    for (int i = 0; i < size(); i++)
        if (!at(i).compare(str, cs))
            return true;
    return false;
}
bool ProStringList::contains(const char *str, Qt::CaseSensitivity cs) const
{
    for (int i = 0; i < size(); i++)
        if (!at(i).compare(str, cs))
            return true;
    return false;
}
ProFile::ProFile(const QString &fileName)
    : m_refCount(1),
      m_fileName(fileName),
      m_ok(true),
      m_hostBuild(false)
{
    if (!fileName.startsWith(QLatin1Char('(')))
        m_directoryName = QFileInfo( // qmake sickness: canonicalize only the directory!
                fileName.left(fileName.lastIndexOf(QLatin1Char('/')))).canonicalFilePath();
}
ProFile::~ProFile()
{
}
QT_END_NAMESPACE
QMakeFileReader/evaluator/proitems.h
New file
@@ -0,0 +1,384 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef PROITEMS_H
#define PROITEMS_H
#include "qmake_global.h"
#include <qstring.h>
#include <qvector.h>
#include <qhash.h>
QT_BEGIN_NAMESPACE
class QTextStream;
#ifdef PROPARSER_THREAD_SAFE
typedef QAtomicInt ProItemRefCount;
#else
class ProItemRefCount {
public:
    ProItemRefCount(int cnt = 0) : m_cnt(cnt) {}
    bool ref() { return ++m_cnt != 0; }
    bool deref() { return --m_cnt != 0; }
    ProItemRefCount &operator=(int value) { m_cnt = value; return *this; }
private:
    int m_cnt;
};
#endif
#ifndef QT_BUILD_QMAKE
#  define PROITEM_EXPLICIT explicit
#else
#  define PROITEM_EXPLICIT
#endif
class ProKey;
class ProStringList;
class ProFile;
class ProString {
public:
    ProString();
    ProString(const ProString &other);
    PROITEM_EXPLICIT ProString(const QString &str);
    PROITEM_EXPLICIT ProString(const char *str);
    ProString(const QString &str, int offset, int length);
    void setValue(const QString &str);
    void clear() { m_string.clear(); m_length = 0; }
    ProString &setSource(const ProString &other) { m_file = other.m_file; return *this; }
    ProString &setSource(const ProFile *pro) { m_file = pro; return *this; }
    const ProFile *sourceFile() const { return m_file; }
    ProString &prepend(const ProString &other);
    ProString &append(const ProString &other, bool *pending = 0);
    ProString &append(const QString &other) { return append(ProString(other)); }
    ProString &append(const QLatin1String other);
    ProString &append(const char *other) { return append(QLatin1String(other)); }
    ProString &append(QChar other);
    ProString &append(const ProStringList &other, bool *pending = 0, bool skipEmpty1st = false);
    ProString &operator+=(const ProString &other) { return append(other); }
    ProString &operator+=(const QString &other) { return append(other); }
    ProString &operator+=(const QLatin1String other) { return append(other); }
    ProString &operator+=(const char *other) { return append(other); }
    ProString &operator+=(QChar other) { return append(other); }
    void chop(int n) { Q_ASSERT(n <= m_length); m_length -= n; }
    void chopFront(int n) { Q_ASSERT(n <= m_length); m_offset += n; m_length -= n; }
    bool operator==(const ProString &other) const { return toQStringRef() == other.toQStringRef(); }
    bool operator==(const QString &other) const { return toQStringRef() == other; }
    bool operator==(QLatin1String other) const  { return toQStringRef() == other; }
    bool operator==(const char *other) const { return toQStringRef() == QLatin1String(other); }
    bool operator!=(const ProString &other) const { return !(*this == other); }
    bool operator!=(const QString &other) const { return !(*this == other); }
    bool operator!=(QLatin1String other) const { return !(*this == other); }
    bool operator!=(const char *other) const { return !(*this == other); }
    bool isNull() const { return m_string.isNull(); }
    bool isEmpty() const { return !m_length; }
    int length() const { return m_length; }
    int size() const { return m_length; }
    QChar at(int i) const { Q_ASSERT((uint)i < (uint)m_length); return constData()[i]; }
    const QChar *constData() const { return m_string.constData() + m_offset; }
    ProString mid(int off, int len = -1) const;
    ProString left(int len) const { return mid(0, len); }
    ProString right(int len) const { return mid(qMax(0, size() - len)); }
    ProString trimmed() const;
    int compare(const ProString &sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().compare(sub.toQStringRef(), cs); }
    int compare(const QString &sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().compare(sub, cs); }
    int compare(const char *sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().compare(QLatin1String(sub), cs); }
    bool startsWith(const ProString &sub) const { return toQStringRef().startsWith(sub.toQStringRef()); }
    bool startsWith(const QString &sub) const { return toQStringRef().startsWith(sub); }
    bool startsWith(const char *sub) const { return toQStringRef().startsWith(QLatin1String(sub)); }
    bool startsWith(QChar c) const { return toQStringRef().startsWith(c); }
    bool endsWith(const ProString &sub) const { return toQStringRef().endsWith(sub.toQStringRef()); }
    bool endsWith(const QString &sub) const { return toQStringRef().endsWith(sub); }
    bool endsWith(const char *sub) const { return toQStringRef().endsWith(QLatin1String(sub)); }
    bool endsWith(QChar c) const { return toQStringRef().endsWith(c); }
    int indexOf(const QString &s, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().indexOf(s, from, cs); }
    int indexOf(const char *s, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().indexOf(QLatin1String(s), from, cs); }
    int indexOf(QChar c, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().indexOf(c, from, cs); }
    int lastIndexOf(const QString &s, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().lastIndexOf(s, from, cs); }
    int lastIndexOf(const char *s, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().lastIndexOf(QLatin1String(s), from, cs); }
    int lastIndexOf(QChar c, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().lastIndexOf(c, from, cs); }
    bool contains(const QString &s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return indexOf(s, 0, cs) >= 0; }
    bool contains(const char *s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return indexOf(QLatin1String(s), 0, cs) >= 0; }
    bool contains(QChar c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return indexOf(c, 0, cs) >= 0; }
    int toInt(bool *ok = 0) const { return toQString().toInt(ok); } // XXX optimize
    short toShort(bool *ok = 0) const { return toQString().toShort(ok); } // XXX optimize
    static uint hash(const QChar *p, int n);
    ALWAYS_INLINE QStringRef toQStringRef() const { return QStringRef(&m_string, m_offset, m_length); }
    ALWAYS_INLINE ProKey &toKey() { return *(ProKey *)this; }
    ALWAYS_INLINE const ProKey &toKey() const { return *(const ProKey *)this; }
    QString toQString() const;
    QString &toQString(QString &tmp) const;
    QByteArray toLatin1() const { return toQStringRef().toLatin1(); }
private:
    ProString(const ProKey &other);
    ProString &operator=(const ProKey &other);
    enum OmitPreHashing { NoHash };
    ProString(const ProString &other, OmitPreHashing);
    enum DoPreHashing { DoHash };
    ALWAYS_INLINE ProString(const QString &str, DoPreHashing);
    ALWAYS_INLINE ProString(const char *str, DoPreHashing);
    ALWAYS_INLINE ProString(const QString &str, int offset, int length, DoPreHashing);
    ALWAYS_INLINE ProString(const QString &str, int offset, int length, uint hash);
    QString m_string;
    int m_offset, m_length;
    const ProFile *m_file;
    mutable uint m_hash;
    QChar *prepareExtend(int extraLen, int thisTarget, int extraTarget);
    uint updatedHash() const;
    friend uint qHash(const ProString &str);
    friend QString operator+(const ProString &one, const ProString &two);
    friend class ProKey;
};
Q_DECLARE_TYPEINFO(ProString, Q_MOVABLE_TYPE);
class ProKey : public ProString {
public:
    ALWAYS_INLINE ProKey() : ProString() {}
    explicit ProKey(const QString &str);
    PROITEM_EXPLICIT ProKey(const char *str);
    ProKey(const QString &str, int off, int len);
    ProKey(const QString &str, int off, int len, uint hash);
    void setValue(const QString &str);
#ifdef Q_CC_MSVC
    // Workaround strange MSVC behaviour when exporting classes with ProKey members.
    ALWAYS_INLINE ProKey(const ProKey &other) : ProString(other.toString()) {}
    ALWAYS_INLINE ProKey &operator=(const ProKey &other)
    {
        toString() = other.toString();
        return *this;
    }
#endif
    ALWAYS_INLINE ProString &toString() { return *(ProString *)this; }
    ALWAYS_INLINE const ProString &toString() const { return *(const ProString *)this; }
private:
    ProKey(const ProString &other);
};
Q_DECLARE_TYPEINFO(ProKey, Q_MOVABLE_TYPE);
uint qHash(const ProString &str);
QString operator+(const ProString &one, const ProString &two);
inline QString operator+(const ProString &one, const QString &two)
    { return one + ProString(two); }
inline QString operator+(const QString &one, const ProString &two)
    { return ProString(one) + two; }
inline QString operator+(const ProString &one, const char *two)
    { return one + ProString(two); } // XXX optimize
inline QString operator+(const char *one, const ProString &two)
    { return ProString(one) + two; } // XXX optimize
inline QString &operator+=(QString &that, const ProString &other)
    { return that += other.toQStringRef(); }
inline bool operator==(const QString &that, const ProString &other)
    { return other == that; }
inline bool operator!=(const QString &that, const ProString &other)
    { return !(other == that); }
QTextStream &operator<<(QTextStream &t, const ProString &str);
class ProStringList : public QVector<ProString> {
public:
    ProStringList() {}
    ProStringList(const ProString &str) { *this << str; }
    explicit ProStringList(const QStringList &list);
    QStringList toQStringList() const;
    ProStringList &operator<<(const ProString &str)
        { QVector<ProString>::operator<<(str); return *this; }
    int length() const { return size(); }
    QString join(const QString &sep) const;
    QString join(QChar sep) const;
    void removeAll(const ProString &str);
    void removeAll(const char *str);
    void removeAt(int idx) { remove(idx); }
    void removeDuplicates();
    bool contains(const ProString &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
    bool contains(const QString &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
        { return contains(ProString(str), cs); }
    bool contains(const char *str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
};
Q_DECLARE_TYPEINFO(ProStringList, Q_MOVABLE_TYPE);
inline ProStringList operator+(const ProStringList &one, const ProStringList &two)
    { ProStringList ret = one; ret += two; return ret; }
typedef QHash<ProKey, ProStringList> ProValueMap;
// These token definitions affect both ProFileEvaluator and ProWriter
enum ProToken {
    TokTerminator = 0,  // end of stream (possibly not included in length; must be zero)
    TokLine,            // line marker:
                        // - line (1)
    TokAssign,          // variable =
    TokAppend,          // variable +=
    TokAppendUnique,    // variable *=
    TokRemove,          // variable -=
    TokReplace,         // variable ~=
                        // previous literal/expansion is a variable manipulation
                        // - value expression + TokValueTerminator
    TokValueTerminator, // assignment value terminator
    TokLiteral,         // literal string (fully dequoted)
                        // - length (1)
                        // - string data (length; unterminated)
    TokHashLiteral,     // literal string with hash (fully dequoted)
                        // - hash (2)
                        // - length (1)
                        // - string data (length; unterminated)
    TokVariable,        // qmake variable expansion
                        // - hash (2)
                        // - name length (1)
                        // - name (name length; unterminated)
    TokProperty,        // qmake property expansion
                        // - hash (2)
                        // - name length (1)
                        // - name (name length; unterminated)
    TokEnvVar,          // environment variable expansion
                        // - name length (1)
                        // - name (name length; unterminated)
    TokFuncName,        // replace function expansion
                        // - hash (2)
                        // - name length (1)
                        // - name (name length; unterminated)
                        // - ((nested expansion + TokArgSeparator)* + nested expansion)?
                        // - TokFuncTerminator
    TokArgSeparator,    // function argument separator
    TokFuncTerminator,  // function argument list terminator
    TokCondition,       // previous literal/expansion is a conditional
    TokTestCall,        // previous literal/expansion is a test function call
                        // - ((nested expansion + TokArgSeparator)* + nested expansion)?
                        // - TokFuncTerminator
    TokReturn,          // previous literal/expansion is a return value
    TokBreak,           // break loop
    TokNext,            // shortcut to next loop iteration
    TokNot,             // '!' operator
    TokAnd,             // ':' operator
    TokOr,              // '|' operator
    TokBranch,          // branch point:
                        // - then block length (2)
                        // - then block + TokTerminator (then block length)
                        // - else block length (2)
                        // - else block + TokTerminator (else block length)
    TokForLoop,         // for loop:
                        // - variable name: hash (2), length (1), chars (length)
                        // - expression: length (2), bytes + TokValueTerminator (length)
                        // - body length (2)
                        // - body + TokTerminator (body length)
    TokTestDef,         // test function definition:
    TokReplaceDef,      // replace function definition:
                        // - function name: hash (2), length (1), chars (length)
                        // - body length (2)
                        // - body + TokTerminator (body length)
    TokMask = 0xff,
    TokQuoted = 0x100,  // The expression is quoted => join expanded stringlist
    TokNewStr = 0x200   // Next stringlist element
};
class QMAKE_EXPORT ProFile
{
public:
    explicit ProFile(const QString &fileName);
    ~ProFile();
    QString fileName() const { return m_fileName; }
    QString directoryName() const { return m_directoryName; }
    const QString &items() const { return m_proitems; }
    QString *itemsRef() { return &m_proitems; }
    const ushort *tokPtr() const { return (const ushort *)m_proitems.constData(); }
    void ref() { m_refCount.ref(); }
    void deref() { if (!m_refCount.deref()) delete this; }
    bool isOk() const { return m_ok; }
    void setOk(bool ok) { m_ok = ok; }
    bool isHostBuild() const { return m_hostBuild; }
    void setHostBuild(bool host_build) { m_hostBuild = host_build; }
private:
    ProItemRefCount m_refCount;
    QString m_proitems;
    QString m_fileName;
    QString m_directoryName;
    bool m_ok;
    bool m_hostBuild;
};
class ProFunctionDef {
public:
    ProFunctionDef(ProFile *pro, int offset) : m_pro(pro), m_offset(offset) { m_pro->ref(); }
    ProFunctionDef(const ProFunctionDef &o) : m_pro(o.m_pro), m_offset(o.m_offset) { m_pro->ref(); }
    ~ProFunctionDef() { m_pro->deref(); }
    ProFunctionDef &operator=(const ProFunctionDef &o)
    {
        if (this != &o) {
            m_pro->deref();
            m_pro = o.m_pro;
            m_pro->ref();
            m_offset = o.m_offset;
        }
        return *this;
    }
    ProFile *pro() const { return m_pro; }
    const ushort *tokPtr() const { return m_pro->tokPtr() + m_offset; }
private:
    ProFile *m_pro;
    int m_offset;
};
Q_DECLARE_TYPEINFO(ProFunctionDef, Q_MOVABLE_TYPE);
struct ProFunctionDefs {
    QHash<ProKey, ProFunctionDef> testFunctions;
    QHash<ProKey, ProFunctionDef> replaceFunctions;
};
QT_END_NAMESPACE
#endif // PROITEMS_H
QMakeFileReader/evaluator/qmake_global.h
New file
@@ -0,0 +1,55 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QMAKE_GLOBAL_H
#define QMAKE_GLOBAL_H
#include <qglobal.h>
#if defined(QMAKE_AS_LIBRARY)
#  if defined(QMAKE_LIBRARY)
#    define QMAKE_EXPORT Q_DECL_EXPORT
#  else
#    define QMAKE_EXPORT Q_DECL_IMPORT
#  endif
#else
#  define QMAKE_EXPORT
#endif
// Be fast even for debug builds
// MinGW GCC 4.5+ has a problem with always_inline putTok and putBlockLen
#if defined(__GNUC__) && !(defined(__MINGW32__) && __GNUC__ == 4 && __GNUC_MINOR__ >= 5)
# define ALWAYS_INLINE inline __attribute__((always_inline))
#elif defined(_MSC_VER)
# define ALWAYS_INLINE __forceinline
#else
# define ALWAYS_INLINE inline
#endif
#endif
QMakeFileReader/evaluator/qmakebuiltins.cpp
New file
@@ -0,0 +1,1635 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qmakeevaluator.h"
#include "qmakeevaluator_p.h"
#include "qmakeglobals.h"
#include "qmakeparser.h"
#include "ioutils.h"
#include <qbytearray.h>
#include <qdir.h>
#include <qfile.h>
#include <qfileinfo.h>
#include <qlist.h>
#include <qregexp.h>
#include <qset.h>
#include <qstringlist.h>
#include <qtextstream.h>
#ifdef Q_OS_UNIX
#include <time.h>
#include <utime.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/utsname.h>
#else
#include <windows.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#ifdef Q_OS_WIN32
#define QT_POPEN _popen
#define QT_PCLOSE _pclose
#else
#define QT_POPEN popen
#define QT_PCLOSE pclose
#endif
using namespace QMakeInternal;
QT_BEGIN_NAMESPACE
#define fL1S(s) QString::fromLatin1(s)
enum ExpandFunc {
    E_INVALID = 0, E_MEMBER, E_FIRST, E_LAST, E_SIZE, E_CAT, E_FROMFILE, E_EVAL, E_LIST,
    E_SPRINTF, E_FORMAT_NUMBER, E_JOIN, E_SPLIT, E_BASENAME, E_DIRNAME, E_SECTION,
    E_FIND, E_SYSTEM, E_UNIQUE, E_REVERSE, E_QUOTE, E_ESCAPE_EXPAND,
    E_UPPER, E_LOWER, E_FILES, E_PROMPT, E_RE_ESCAPE, E_VAL_ESCAPE,
    E_REPLACE, E_SORT_DEPENDS, E_RESOLVE_DEPENDS, E_ENUMERATE_VARS,
    E_SHADOWED, E_ABSOLUTE_PATH, E_RELATIVE_PATH, E_CLEAN_PATH,
    E_SYSTEM_PATH, E_SHELL_PATH, E_SYSTEM_QUOTE, E_SHELL_QUOTE
};
enum TestFunc {
    T_INVALID = 0, T_REQUIRES, T_GREATERTHAN, T_LESSTHAN, T_EQUALS,
    T_EXISTS, T_EXPORT, T_CLEAR, T_UNSET, T_EVAL, T_CONFIG, T_SYSTEM,
    T_DEFINED, T_CONTAINS, T_INFILE,
    T_COUNT, T_ISEMPTY, T_INCLUDE, T_LOAD, T_DEBUG, T_LOG, T_MESSAGE, T_WARNING, T_ERROR, T_IF,
    T_MKPATH, T_WRITE_FILE, T_TOUCH, T_CACHE
};
void QMakeEvaluator::initFunctionStatics()
{
    static const struct {
        const char * const name;
        const ExpandFunc func;
    } expandInits[] = {
        { "member", E_MEMBER },
        { "first", E_FIRST },
        { "last", E_LAST },
        { "size", E_SIZE },
        { "cat", E_CAT },
        { "fromfile", E_FROMFILE },
        { "eval", E_EVAL },
        { "list", E_LIST },
        { "sprintf", E_SPRINTF },
        { "format_number", E_FORMAT_NUMBER },
        { "join", E_JOIN },
        { "split", E_SPLIT },
        { "basename", E_BASENAME },
        { "dirname", E_DIRNAME },
        { "section", E_SECTION },
        { "find", E_FIND },
        { "system", E_SYSTEM },
        { "unique", E_UNIQUE },
        { "reverse", E_REVERSE },
        { "quote", E_QUOTE },
        { "escape_expand", E_ESCAPE_EXPAND },
        { "upper", E_UPPER },
        { "lower", E_LOWER },
        { "re_escape", E_RE_ESCAPE },
        { "val_escape", E_VAL_ESCAPE },
        { "files", E_FILES },
        { "prompt", E_PROMPT },
        { "replace", E_REPLACE },
        { "sort_depends", E_SORT_DEPENDS },
        { "resolve_depends", E_RESOLVE_DEPENDS },
        { "enumerate_vars", E_ENUMERATE_VARS },
        { "shadowed", E_SHADOWED },
        { "absolute_path", E_ABSOLUTE_PATH },
        { "relative_path", E_RELATIVE_PATH },
        { "clean_path", E_CLEAN_PATH },
        { "system_path", E_SYSTEM_PATH },
        { "shell_path", E_SHELL_PATH },
        { "system_quote", E_SYSTEM_QUOTE },
        { "shell_quote", E_SHELL_QUOTE },
    };
    for (unsigned i = 0; i < sizeof(expandInits)/sizeof(expandInits[0]); ++i)
        statics.expands.insert(ProKey(expandInits[i].name), expandInits[i].func);
    static const struct {
        const char * const name;
        const TestFunc func;
    } testInits[] = {
        { "requires", T_REQUIRES },
        { "greaterThan", T_GREATERTHAN },
        { "lessThan", T_LESSTHAN },
        { "equals", T_EQUALS },
        { "isEqual", T_EQUALS },
        { "exists", T_EXISTS },
        { "export", T_EXPORT },
        { "clear", T_CLEAR },
        { "unset", T_UNSET },
        { "eval", T_EVAL },
        { "CONFIG", T_CONFIG },
        { "if", T_IF },
        { "isActiveConfig", T_CONFIG },
        { "system", T_SYSTEM },
        { "defined", T_DEFINED },
        { "contains", T_CONTAINS },
        { "infile", T_INFILE },
        { "count", T_COUNT },
        { "isEmpty", T_ISEMPTY },
        { "load", T_LOAD },
        { "include", T_INCLUDE },
        { "debug", T_DEBUG },
        { "log", T_LOG },
        { "message", T_MESSAGE },
        { "warning", T_WARNING },
        { "error", T_ERROR },
        { "mkpath", T_MKPATH },
        { "write_file", T_WRITE_FILE },
        { "touch", T_TOUCH },
        { "cache", T_CACHE },
    };
    for (unsigned i = 0; i < sizeof(testInits)/sizeof(testInits[0]); ++i)
        statics.functions.insert(ProKey(testInits[i].name), testInits[i].func);
}
static bool isTrue(const ProString &_str, QString &tmp)
{
    const QString &str = _str.toQString(tmp);
    return !str.compare(statics.strtrue, Qt::CaseInsensitive) || str.toInt();
}
#ifdef Q_OS_WIN
static QString windowsErrorCode()
{
    wchar_t *string = 0;
    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
                  NULL,
                  GetLastError(),
                  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                  (LPWSTR)&string,
                  0,
                  NULL);
    QString ret = QString::fromWCharArray(string);
    LocalFree((HLOCAL)string);
    return ret;
}
#endif
static QString
quoteValue(const ProString &val)
{
    QString ret;
    ret.reserve(val.size());
    const QChar *chars = val.constData();
    bool quote = val.isEmpty();
    bool escaping = false;
    for (int i = 0, l = val.size(); i < l; i++) {
        QChar c = chars[i];
        ushort uc = c.unicode();
        if (uc < 32) {
            if (!escaping) {
                escaping = true;
                ret += QLatin1String("$$escape_expand(");
            }
            switch (uc) {
            case '\r':
                ret += QLatin1String("\\\\r");
                break;
            case '\n':
                ret += QLatin1String("\\\\n");
                break;
            case '\t':
                ret += QLatin1String("\\\\t");
                break;
            default:
                ret += QString::fromLatin1("\\\\x%1").arg(uc, 2, 16, QLatin1Char('0'));
                break;
            }
        } else {
            if (escaping) {
                escaping = false;
                ret += QLatin1Char(')');
            }
            switch (uc) {
            case '\\':
                ret += QLatin1String("\\\\");
                break;
            case '"':
                ret += QLatin1String("\\\"");
                break;
            case '\'':
                ret += QLatin1String("\\'");
                break;
            case '$':
                ret += QLatin1String("\\$");
                break;
            case '#':
                ret += QLatin1String("$${LITERAL_HASH}");
                break;
            case 32:
                quote = true;
                // fallthrough
            default:
                ret += c;
                break;
            }
        }
    }
    if (escaping)
        ret += QLatin1Char(')');
    if (quote) {
        ret.prepend(QLatin1Char('"'));
        ret.append(QLatin1Char('"'));
    }
    return ret;
}
static bool
doWriteFile(const QString &name, QIODevice::OpenMode mode, const QString &contents, QString *errStr)
{
    QByteArray bytes = contents.toLocal8Bit();
    QFile cfile(name);
    if (!(mode & QIODevice::Append) && cfile.open(QIODevice::ReadOnly | QIODevice::Text)) {
        if (cfile.readAll() == bytes)
            return true;
        cfile.close();
    }
    if (!cfile.open(mode | QIODevice::WriteOnly | QIODevice::Text)) {
        *errStr = cfile.errorString();
        return false;
    }
    cfile.write(bytes);
    cfile.close();
    if (cfile.error() != QFile::NoError) {
        *errStr = cfile.errorString();
        return false;
    }
    return true;
}
QMakeEvaluator::VisitReturn
QMakeEvaluator::writeFile(const QString &ctx, const QString &fn, QIODevice::OpenMode mode,
                          const QString &contents)
{
    QFileInfo qfi(fn);
    if (!QDir::current().mkpath(qfi.path())) {
        evalError(fL1S("Cannot create %1directory %2.")
                  .arg(ctx, QDir::toNativeSeparators(qfi.path())));
        return ReturnFalse;
    }
    QString errStr;
    if (!doWriteFile(qfi.filePath(), mode, contents, &errStr)) {
        evalError(fL1S("Cannot write %1file %2: %3.")
                  .arg(ctx, QDir::toNativeSeparators(qfi.filePath()), errStr));
        return ReturnFalse;
    }
    m_parser->discardFileFromCache(qfi.filePath());
    return ReturnTrue;
}
#ifndef QT_BOOTSTRAPPED
void QMakeEvaluator::runProcess(QProcess *proc, const QString &command) const
{
    proc->setWorkingDirectory(currentDirectory());
# ifdef PROEVALUATOR_SETENV
    if (!m_option->environment.isEmpty())
        proc->setProcessEnvironment(m_option->environment);
# endif
# ifdef Q_OS_WIN
    proc->setNativeArguments(QLatin1String("/v:off /s /c \"") + command + QLatin1Char('"'));
    proc->start(m_option->getEnv(QLatin1String("COMSPEC")), QStringList());
# else
    proc->start(QLatin1String("/bin/sh"), QStringList() << QLatin1String("-c") << command);
# endif
    proc->waitForFinished(-1);
}
#endif
QByteArray QMakeEvaluator::getCommandOutput(const QString &args) const
{
    QByteArray out;
#ifndef QT_BOOTSTRAPPED
    QProcess proc;
    runProcess(&proc, args);
    QByteArray errout = proc.readAllStandardError();
# ifdef PROEVALUATOR_FULL
    // FIXME: Qt really should have the option to set forwarding per channel
    fputs(errout.constData(), stderr);
# else
    if (!errout.isEmpty()) {
        if (errout.endsWith('\n'))
            errout.chop(1);
        m_handler->message(QMakeHandler::EvalError, QString::fromLocal8Bit(errout));
    }
# endif
    out = proc.readAllStandardOutput();
# ifdef Q_OS_WIN
    // FIXME: Qt's line end conversion on sequential files should really be fixed
    out.replace("\r\n", "\n");
# endif
#else
    if (FILE *proc = QT_POPEN(QString(QLatin1String("cd ")
                               + IoUtils::shellQuote(QDir::toNativeSeparators(currentDirectory()))
                               + QLatin1String(" && ") + args).toLocal8Bit().constData(), "r")) {
        while (!feof(proc)) {
            char buff[10 * 1024];
            int read_in = int(fread(buff, 1, sizeof(buff), proc));
            if (!read_in)
                break;
            out += QByteArray(buff, read_in);
        }
        QT_PCLOSE(proc);
    }
#endif
    return out;
}
void QMakeEvaluator::populateDeps(
        const ProStringList &deps, const ProString &prefix,
        QHash<ProKey, QSet<ProKey> > &dependencies, ProValueMap &dependees,
        ProStringList &rootSet) const
{
    foreach (const ProString &item, deps)
        if (!dependencies.contains(item.toKey())) {
            QSet<ProKey> &dset = dependencies[item.toKey()]; // Always create entry
            ProStringList depends = values(ProKey(prefix + item + QString::fromLatin1(".depends")));
            if (depends.isEmpty()) {
                rootSet << item;
            } else {
                foreach (const ProString &dep, depends) {
                    dset.insert(dep.toKey());
                    dependees[dep.toKey()] << item;
                }
                populateDeps(depends, prefix, dependencies, dependees, rootSet);
            }
        }
}
ProStringList QMakeEvaluator::evaluateBuiltinExpand(
        int func_t, const ProKey &func, const ProStringList &args)
{
    ProStringList ret;
    traceMsg("calling built-in $$%s(%s)", dbgKey(func), dbgSepStrList(args));
    switch (func_t) {
    case E_BASENAME:
    case E_DIRNAME:
    case E_SECTION: {
        bool regexp = false;
        QString sep;
        ProString var;
        int beg = 0;
        int end = -1;
        if (func_t == E_SECTION) {
            if (args.count() != 3 && args.count() != 4) {
                evalError(fL1S("%1(var) section(var, sep, begin, end) requires"
                               " three or four arguments.").arg(func.toQString(m_tmp1)));
            } else {
                var = args[0];
                sep = args.at(1).toQString();
                beg = args.at(2).toQString(m_tmp2).toInt();
                if (args.count() == 4)
                    end = args.at(3).toQString(m_tmp2).toInt();
            }
        } else {
            if (args.count() != 1) {
                evalError(fL1S("%1(var) requires one argument.").arg(func.toQString(m_tmp1)));
            } else {
                var = args[0];
                regexp = true;
                sep = QLatin1String("[\\\\/]");
                if (func_t == E_DIRNAME)
                    end = -2;
                else
                    beg = -1;
            }
        }
        if (!var.isEmpty()) {
            if (regexp) {
                QRegExp sepRx(sep);
                foreach (const ProString &str, values(map(var))) {
                    const QString &rstr = str.toQString(m_tmp1).section(sepRx, beg, end);
                    ret << (rstr.isSharedWith(m_tmp1) ? str : ProString(rstr).setSource(str));
                }
            } else {
                foreach (const ProString &str, values(map(var))) {
                    const QString &rstr = str.toQString(m_tmp1).section(sep, beg, end);
                    ret << (rstr.isSharedWith(m_tmp1) ? str : ProString(rstr).setSource(str));
                }
            }
        }
        break;
    }
    case E_SPRINTF:
        if (args.count() < 1) {
            evalError(fL1S("sprintf(format, ...) requires at least one argument."));
        } else {
            QString tmp = args.at(0).toQString(m_tmp1);
            for (int i = 1; i < args.count(); ++i)
                tmp = tmp.arg(args.at(i).toQString(m_tmp2));
            // Note: this depends on split_value_list() making a deep copy
            ret = split_value_list(tmp);
        }
        break;
    case E_FORMAT_NUMBER:
        if (args.count() > 2) {
            evalError(fL1S("format_number(number[, options...]) requires one or two arguments."));
        } else {
            int ibase = 10;
            int obase = 10;
            int width = 0;
            bool zeropad = false;
            bool leftalign = false;
            enum { DefaultSign, PadSign, AlwaysSign } sign = DefaultSign;
            if (args.count() >= 2) {
                foreach (const ProString &opt, split_value_list(args.at(1).toQString(m_tmp2))) {
                    opt.toQString(m_tmp3);
                    if (m_tmp3.startsWith(QLatin1String("ibase="))) {
                        ibase = m_tmp3.mid(6).toInt();
                    } else if (m_tmp3.startsWith(QLatin1String("obase="))) {
                        obase = m_tmp3.mid(6).toInt();
                    } else if (m_tmp3.startsWith(QLatin1String("width="))) {
                        width = m_tmp3.mid(6).toInt();
                    } else if (m_tmp3 == QLatin1String("zeropad")) {
                        zeropad = true;
                    } else if (m_tmp3 == QLatin1String("padsign")) {
                        sign = PadSign;
                    } else if (m_tmp3 == QLatin1String("alwayssign")) {
                        sign = AlwaysSign;
                    } else if (m_tmp3 == QLatin1String("leftalign")) {
                        leftalign = true;
                    } else {
                        evalError(fL1S("format_number(): invalid format option %1.").arg(m_tmp3));
                        goto formfail;
                    }
                }
            }
            args.at(0).toQString(m_tmp3);
            if (m_tmp3.contains(QLatin1Char('.'))) {
                evalError(fL1S("format_number(): floats are currently not supported."));
                break;
            }
            bool ok;
            qlonglong num = m_tmp3.toLongLong(&ok, ibase);
            if (!ok) {
                evalError(fL1S("format_number(): malformed number %2 for base %1.")
                          .arg(ibase).arg(m_tmp3));
                break;
            }
            QString outstr;
            if (num < 0) {
                num = -num;
                outstr = QLatin1Char('-');
            } else if (sign == AlwaysSign) {
                outstr = QLatin1Char('+');
            } else if (sign == PadSign) {
                outstr = QLatin1Char(' ');
            }
            QString numstr = QString::number(num, obase);
            int space = width - outstr.length() - numstr.length();
            if (space <= 0) {
                outstr += numstr;
            } else if (leftalign) {
                outstr += numstr + QString(space, QLatin1Char(' '));
            } else if (zeropad) {
                outstr += QString(space, QLatin1Char('0')) + numstr;
            } else {
                outstr.prepend(QString(space, QLatin1Char(' ')));
                outstr += numstr;
            }
            ret += ProString(outstr);
        }
      formfail:
        break;
    case E_JOIN: {
        if (args.count() < 1 || args.count() > 4) {
            evalError(fL1S("join(var, glue, before, after) requires one to four arguments."));
        } else {
            QString glue;
            ProString before, after;
            if (args.count() >= 2)
                glue = args.at(1).toQString(m_tmp1);
            if (args.count() >= 3)
                before = args[2];
            if (args.count() == 4)
                after = args[3];
            const ProStringList &var = values(map(args.at(0)));
            if (!var.isEmpty()) {
                const ProFile *src = currentProFile();
                foreach (const ProString &v, var)
                    if (const ProFile *s = v.sourceFile()) {
                        src = s;
                        break;
                    }
                ret = split_value_list(before + var.join(glue) + after, src);
            }
        }
        break;
    }
    case E_SPLIT:
        if (args.count() < 1 || args.count() > 2) {
            evalError(fL1S("split(var, sep) requires one or two arguments."));
        } else {
            const QString &sep = (args.count() == 2) ? args.at(1).toQString(m_tmp1) : statics.field_sep;
            foreach (const ProString &var, values(map(args.at(0))))
                foreach (const QString &splt, var.toQString(m_tmp2).split(sep))
                    ret << (splt.isSharedWith(m_tmp2) ? var : ProString(splt).setSource(var));
        }
        break;
    case E_MEMBER:
        if (args.count() < 1 || args.count() > 3) {
            evalError(fL1S("member(var, start, end) requires one to three arguments."));
        } else {
            bool ok = true;
            const ProStringList &var = values(map(args.at(0)));
            int start = 0, end = 0;
            if (args.count() >= 2) {
                const QString &start_str = args.at(1).toQString(m_tmp1);
                start = start_str.toInt(&ok);
                if (!ok) {
                    if (args.count() == 2) {
                        int dotdot = start_str.indexOf(statics.strDotDot);
                        if (dotdot != -1) {
                            start = start_str.left(dotdot).toInt(&ok);
                            if (ok)
                                end = start_str.mid(dotdot+2).toInt(&ok);
                        }
                    }
                    if (!ok)
                        evalError(fL1S("member() argument 2 (start) '%2' invalid.")
                                  .arg(start_str));
                } else {
                    end = start;
                    if (args.count() == 3)
                        end = args.at(2).toQString(m_tmp1).toInt(&ok);
                    if (!ok)
                        evalError(fL1S("member() argument 3 (end) '%2' invalid.")
                                  .arg(args.at(2).toQString(m_tmp1)));
                }
            }
            if (ok) {
                if (start < 0)
                    start += var.count();
                if (end < 0)
                    end += var.count();
                if (start < 0 || start >= var.count() || end < 0 || end >= var.count()) {
                    //nothing
                } else if (start < end) {
                    for (int i = start; i <= end && var.count() >= i; i++)
                        ret.append(var[i]);
                } else {
                    for (int i = start; i >= end && var.count() >= i && i >= 0; i--)
                        ret += var[i];
                }
            }
        }
        break;
    case E_FIRST:
    case E_LAST:
        if (args.count() != 1) {
            evalError(fL1S("%1(var) requires one argument.").arg(func.toQString(m_tmp1)));
        } else {
            const ProStringList &var = values(map(args.at(0)));
            if (!var.isEmpty()) {
                if (func_t == E_FIRST)
                    ret.append(var[0]);
                else
                    ret.append(var.last());
            }
        }
        break;
    case E_SIZE:
        if (args.count() != 1)
            evalError(fL1S("size(var) requires one argument."));
        else
            ret.append(ProString(QString::number(values(map(args.at(0))).size())));
        break;
    case E_CAT:
        if (args.count() < 1 || args.count() > 2) {
            evalError(fL1S("cat(file, singleline=true) requires one or two arguments."));
        } else {
            const QString &file = args.at(0).toQString(m_tmp1);
            bool blob = false;
            bool lines = false;
            bool singleLine = true;
            if (args.count() > 1) {
                args.at(1).toQString(m_tmp2);
                if (!m_tmp2.compare(QLatin1String("false"), Qt::CaseInsensitive))
                    singleLine = false;
                else if (!m_tmp2.compare(QLatin1String("blob"), Qt::CaseInsensitive))
                    blob = true;
                else if (!m_tmp2.compare(QLatin1String("lines"), Qt::CaseInsensitive))
                    lines = true;
            }
            QFile qfile(resolvePath(m_option->expandEnvVars(file)));
            if (qfile.open(QIODevice::ReadOnly)) {
                QTextStream stream(&qfile);
                if (blob) {
                    ret += ProString(stream.readAll());
                } else {
                    while (!stream.atEnd()) {
                        if (lines) {
                            ret += ProString(stream.readLine());
                        } else {
                            ret += split_value_list(stream.readLine().trimmed());
                            if (!singleLine)
                                ret += ProString("\n");
                        }
                    }
                }
            }
        }
        break;
    case E_FROMFILE:
        if (args.count() != 2) {
            evalError(fL1S("fromfile(file, variable) requires two arguments."));
        } else {
            ProValueMap vars;
            QString fn = resolvePath(m_option->expandEnvVars(args.at(0).toQString(m_tmp1)));
            fn.detach();
            if (evaluateFileInto(fn, &vars, LoadProOnly) == ReturnTrue)
                ret = vars.value(map(args.at(1)));
        }
        break;
    case E_EVAL:
        if (args.count() != 1) {
            evalError(fL1S("eval(variable) requires one argument."));
        } else {
            ret += values(map(args.at(0)));
        }
        break;
    case E_LIST: {
        QString tmp;
        tmp.sprintf(".QMAKE_INTERNAL_TMP_variableName_%d", m_listCount++);
        ret = ProStringList(ProString(tmp));
        ProStringList lst;
        foreach (const ProString &arg, args)
            lst += split_value_list(arg.toQString(m_tmp1), arg.sourceFile()); // Relies on deep copy
        m_valuemapStack.top()[ret.at(0).toKey()] = lst;
        break; }
    case E_FIND:
        if (args.count() != 2) {
            evalError(fL1S("find(var, str) requires two arguments."));
        } else {
            QRegExp regx(args.at(1).toQString());
            int t = 0;
            foreach (const ProString &val, values(map(args.at(0)))) {
                if (regx.indexIn(val.toQString(m_tmp[t])) != -1)
                    ret += val;
                t ^= 1;
            }
        }
        break;
    case E_SYSTEM:
        if (!m_skipLevel) {
            if (args.count() < 1 || args.count() > 2) {
                evalError(fL1S("system(execute) requires one or two arguments."));
            } else {
                bool blob = false;
                bool lines = false;
                bool singleLine = true;
                if (args.count() > 1) {
                    args.at(1).toQString(m_tmp2);
                    if (!m_tmp2.compare(QLatin1String("false"), Qt::CaseInsensitive))
                        singleLine = false;
                    else if (!m_tmp2.compare(QLatin1String("blob"), Qt::CaseInsensitive))
                        blob = true;
                    else if (!m_tmp2.compare(QLatin1String("lines"), Qt::CaseInsensitive))
                        lines = true;
                }
                QByteArray bytes = getCommandOutput(args.at(0).toQString(m_tmp2));
                if (lines) {
                    QTextStream stream(bytes);
                    while (!stream.atEnd())
                        ret += ProString(stream.readLine());
                } else {
                    QString output = QString::fromLocal8Bit(bytes);
                    if (blob) {
                        ret += ProString(output);
                    } else {
                        output.replace(QLatin1Char('\t'), QLatin1Char(' '));
                        if (singleLine)
                            output.replace(QLatin1Char('\n'), QLatin1Char(' '));
                        ret += split_value_list(output);
                    }
                }
            }
        }
        break;
    case E_UNIQUE:
        if (args.count() != 1) {
            evalError(fL1S("unique(var) requires one argument."));
        } else {
            ret = values(map(args.at(0)));
            ret.removeDuplicates();
        }
        break;
    case E_REVERSE:
        if (args.count() != 1) {
            evalError(fL1S("reverse(var) requires one argument."));
        } else {
            ProStringList var = values(args.at(0).toKey());
            for (int i = 0; i < var.size() / 2; i++)
                qSwap(var[i], var[var.size() - i - 1]);
            ret += var;
        }
        break;
    case E_QUOTE:
        ret += args;
        break;
    case E_ESCAPE_EXPAND:
        for (int i = 0; i < args.size(); ++i) {
            QString str = args.at(i).toQString();
            QChar *i_data = str.data();
            int i_len = str.length();
            for (int x = 0; x < i_len; ++x) {
                if (*(i_data+x) == QLatin1Char('\\') && x < i_len-1) {
                    if (*(i_data+x+1) == QLatin1Char('\\')) {
                        ++x;
                    } else {
                        struct {
                            char in, out;
                        } mapped_quotes[] = {
                            { 'n', '\n' },
                            { 't', '\t' },
                            { 'r', '\r' },
                            { 0, 0 }
                        };
                        for (int i = 0; mapped_quotes[i].in; ++i) {
                            if (*(i_data+x+1) == QLatin1Char(mapped_quotes[i].in)) {
                                *(i_data+x) = QLatin1Char(mapped_quotes[i].out);
                                if (x < i_len-2)
                                    memmove(i_data+x+1, i_data+x+2, (i_len-x-2)*sizeof(QChar));
                                --i_len;
                                break;
                            }
                        }
                    }
                }
            }
            ret.append(ProString(QString(i_data, i_len)).setSource(args.at(i)));
        }
        break;
    case E_RE_ESCAPE:
        for (int i = 0; i < args.size(); ++i) {
            const QString &rstr = QRegExp::escape(args.at(i).toQString(m_tmp1));
            ret << (rstr.isSharedWith(m_tmp1) ? args.at(i) : ProString(rstr).setSource(args.at(i)));
        }
        break;
    case E_VAL_ESCAPE:
        if (args.count() != 1) {
            evalError(fL1S("val_escape(var) requires one argument."));
        } else {
            const ProStringList &vals = values(args.at(0).toKey());
            ret.reserve(vals.size());
            foreach (const ProString &str, vals)
                ret += ProString(quoteValue(str));
        }
        break;
    case E_UPPER:
    case E_LOWER:
        for (int i = 0; i < args.count(); ++i) {
            QString rstr = args.at(i).toQString(m_tmp1);
            rstr = (func_t == E_UPPER) ? rstr.toUpper() : rstr.toLower();
            ret << (rstr.isSharedWith(m_tmp1) ? args.at(i) : ProString(rstr).setSource(args.at(i)));
        }
        break;
    case E_FILES:
        if (args.count() != 1 && args.count() != 2) {
            evalError(fL1S("files(pattern, recursive=false) requires one or two arguments."));
        } else {
            bool recursive = false;
            if (args.count() == 2)
                recursive = isTrue(args.at(1), m_tmp2);
            QStringList dirs;
            QString r = m_option->expandEnvVars(args.at(0).toQString(m_tmp1))
                        .replace(QLatin1Char('\\'), QLatin1Char('/'));
            QString pfx;
            if (IoUtils::isRelativePath(r)) {
                pfx = currentDirectory();
                if (!pfx.endsWith(QLatin1Char('/')))
                    pfx += QLatin1Char('/');
            }
            int slash = r.lastIndexOf(QLatin1Char('/'));
            if (slash != -1) {
                dirs.append(r.left(slash+1));
                r = r.mid(slash+1);
            } else {
                dirs.append(QString());
            }
            r.detach(); // Keep m_tmp out of QRegExp's cache
            QRegExp regex(r, Qt::CaseSensitive, QRegExp::Wildcard);
            for (int d = 0; d < dirs.count(); d++) {
                QString dir = dirs[d];
                QDir qdir(pfx + dir);
                for (int i = 0; i < (int)qdir.count(); ++i) {
                    if (qdir[i] == statics.strDot || qdir[i] == statics.strDotDot)
                        continue;
                    QString fname = dir + qdir[i];
                    if (IoUtils::fileType(pfx + fname) == IoUtils::FileIsDir) {
                        if (recursive)
                            dirs.append(fname + QLatin1Char('/'));
                    }
                    if (regex.exactMatch(qdir[i]))
                        ret += ProString(fname).setSource(currentProFile());
                }
            }
        }
        break;
#ifdef PROEVALUATOR_FULL
    case E_PROMPT: {
        if (args.count() != 1) {
            evalError(fL1S("prompt(question) requires one argument."));
//        } else if (currentFileName() == QLatin1String("-")) {
//            evalError(fL1S("prompt(question) cannot be used when '-o -' is used"));
        } else {
            QString msg = m_option->expandEnvVars(args.at(0).toQString(m_tmp1));
            if (!msg.endsWith(QLatin1Char('?')))
                msg += QLatin1Char('?');
            fprintf(stderr, "Project PROMPT: %s ", qPrintable(msg));
            QFile qfile;
            if (qfile.open(stdin, QIODevice::ReadOnly)) {
                QTextStream t(&qfile);
                ret = split_value_list(t.readLine());
            }
        }
        break; }
#endif
    case E_REPLACE:
        if (args.count() != 3 ) {
            evalError(fL1S("replace(var, before, after) requires three arguments."));
        } else {
            const QRegExp before(args.at(1).toQString());
            const QString &after(args.at(2).toQString(m_tmp2));
            foreach (const ProString &val, values(map(args.at(0)))) {
                QString rstr = val.toQString(m_tmp1);
                QString copy = rstr; // Force a detach on modify
                rstr.replace(before, after);
                ret << (rstr.isSharedWith(m_tmp1) ? val : ProString(rstr).setSource(val));
            }
        }
        break;
    case E_SORT_DEPENDS:
    case E_RESOLVE_DEPENDS:
        if (args.count() < 1 || args.count() > 2) {
            evalError(fL1S("%1(var, prefix) requires one or two arguments.").arg(func.toQString(m_tmp1)));
        } else {
            QHash<ProKey, QSet<ProKey> > dependencies;
            ProValueMap dependees;
            ProStringList rootSet;
            ProStringList orgList = values(args.at(0).toKey());
            populateDeps(orgList, (args.count() < 2 ? ProString() : args.at(1)),
                         dependencies, dependees, rootSet);
            for (int i = 0; i < rootSet.size(); ++i) {
                const ProString &item = rootSet.at(i);
                if ((func_t == E_RESOLVE_DEPENDS) || orgList.contains(item))
                    ret.prepend(item);
                foreach (const ProString &dep, dependees[item.toKey()]) {
                    QSet<ProKey> &dset = dependencies[dep.toKey()];
                    dset.remove(rootSet.at(i).toKey()); // *Don't* use 'item' - rootSet may have changed!
                    if (dset.isEmpty())
                        rootSet << dep;
                }
            }
        }
        break;
    case E_ENUMERATE_VARS: {
        QSet<ProString> keys;
        foreach (const ProValueMap &vmap, m_valuemapStack)
            for (ProValueMap::ConstIterator it = vmap.constBegin(); it != vmap.constEnd(); ++it)
                keys.insert(it.key());
        ret.reserve(keys.size());
        foreach (const ProString &key, keys)
            ret << key;
        break; }
    case E_SHADOWED:
        if (args.count() != 1) {
            evalError(fL1S("shadowed(path) requires one argument."));
        } else {
            QString rstr = m_option->shadowedPath(resolvePath(args.at(0).toQString(m_tmp1)));
            if (rstr.isEmpty())
                break;
            ret << (rstr.isSharedWith(m_tmp1) ? args.at(0) : ProString(rstr).setSource(args.at(0)));
        }
        break;
    case E_ABSOLUTE_PATH:
        if (args.count() > 2) {
            evalError(fL1S("absolute_path(path[, base]) requires one or two arguments."));
        } else {
            QString rstr = QDir::cleanPath(
                    QDir(args.count() > 1 ? args.at(1).toQString(m_tmp2) : currentDirectory())
                    .absoluteFilePath(args.at(0).toQString(m_tmp1)));
            ret << (rstr.isSharedWith(m_tmp1) ? args.at(0) : ProString(rstr).setSource(args.at(0)));
        }
        break;
    case E_RELATIVE_PATH:
        if (args.count() > 2) {
            evalError(fL1S("relative_path(path[, base]) requires one or two arguments."));
        } else {
            QDir baseDir(args.count() > 1 ? args.at(1).toQString(m_tmp2) : currentDirectory());
            QString rstr = baseDir.relativeFilePath(baseDir.absoluteFilePath(
                                args.at(0).toQString(m_tmp1)));
            ret << (rstr.isSharedWith(m_tmp1) ? args.at(0) : ProString(rstr).setSource(args.at(0)));
        }
        break;
    case E_CLEAN_PATH:
        if (args.count() != 1) {
            evalError(fL1S("clean_path(path) requires one argument."));
        } else {
            QString rstr = QDir::cleanPath(args.at(0).toQString(m_tmp1));
            ret << (rstr.isSharedWith(m_tmp1) ? args.at(0) : ProString(rstr).setSource(args.at(0)));
        }
        break;
    case E_SYSTEM_PATH:
        if (args.count() != 1) {
            evalError(fL1S("system_path(path) requires one argument."));
        } else {
            QString rstr = args.at(0).toQString(m_tmp1);
#ifdef Q_OS_WIN
            rstr.replace(QLatin1Char('/'), QLatin1Char('\\'));
#else
            rstr.replace(QLatin1Char('\\'), QLatin1Char('/'));
#endif
            ret << (rstr.isSharedWith(m_tmp1) ? args.at(0) : ProString(rstr).setSource(args.at(0)));
        }
        break;
    case E_SHELL_PATH:
        if (args.count() != 1) {
            evalError(fL1S("shell_path(path) requires one argument."));
        } else {
            QString rstr = args.at(0).toQString(m_tmp1);
            if (m_dirSep.startsWith(QLatin1Char('\\')))
                rstr.replace(QLatin1Char('/'), QLatin1Char('\\'));
            else
                rstr.replace(QLatin1Char('\\'), QLatin1Char('/'));
            ret << (rstr.isSharedWith(m_tmp1) ? args.at(0) : ProString(rstr).setSource(args.at(0)));
        }
        break;
    case E_SYSTEM_QUOTE:
        if (args.count() != 1) {
            evalError(fL1S("system_quote(arg) requires one argument."));
        } else {
            QString rstr = IoUtils::shellQuote(args.at(0).toQString(m_tmp1));
            ret << (rstr.isSharedWith(m_tmp1) ? args.at(0) : ProString(rstr).setSource(args.at(0)));
        }
        break;
    case E_SHELL_QUOTE:
        if (args.count() != 1) {
            evalError(fL1S("shell_quote(arg) requires one argument."));
        } else {
            QString rstr = args.at(0).toQString(m_tmp1);
            if (m_dirSep.startsWith(QLatin1Char('\\')))
                rstr = IoUtils::shellQuoteWin(rstr);
            else
                rstr = IoUtils::shellQuoteUnix(rstr);
            ret << (rstr.isSharedWith(m_tmp1) ? args.at(0) : ProString(rstr).setSource(args.at(0)));
        }
        break;
    default:
        evalError(fL1S("Function '%1' is not implemented.").arg(func.toQString(m_tmp1)));
        break;
    }
    return ret;
}
QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
        int func_t, const ProKey &function, const ProStringList &args)
{
    traceMsg("calling built-in %s(%s)", dbgKey(function), dbgSepStrList(args));
    switch (func_t) {
    case T_DEFINED: {
        if (args.count() < 1 || args.count() > 2) {
            evalError(fL1S("defined(function, [\"test\"|\"replace\"])"
                           " requires one or two arguments."));
            return ReturnFalse;
        }
        const ProKey &var = args.at(0).toKey();
        if (args.count() > 1) {
            if (args[1] == QLatin1String("test")) {
                return returnBool(m_functionDefs.testFunctions.contains(var));
            } else if (args[1] == QLatin1String("replace")) {
                return returnBool(m_functionDefs.replaceFunctions.contains(var));
            } else if (args[1] == QLatin1String("var")) {
                ProValueMap::Iterator it;
                return returnBool(findValues(var, &it));
            }
            evalError(fL1S("defined(function, type): unexpected type [%1].")
                      .arg(args.at(1).toQString(m_tmp1)));
            return ReturnFalse;
        }
        return returnBool(m_functionDefs.replaceFunctions.contains(var)
                          || m_functionDefs.testFunctions.contains(var));
    }
    case T_EXPORT: {
        if (args.count() != 1) {
            evalError(fL1S("export(variable) requires one argument."));
            return ReturnFalse;
        }
        const ProKey &var = map(args.at(0));
        for (ProValueMapStack::Iterator vmi = m_valuemapStack.end();
             --vmi != m_valuemapStack.begin(); ) {
            ProValueMap::Iterator it = (*vmi).find(var);
            if (it != (*vmi).end()) {
                if (it->constBegin() == statics.fakeValue.constBegin()) {
                    // This is stupid, but qmake doesn't propagate deletions
                    m_valuemapStack.first()[var] = ProStringList();
                } else {
                    m_valuemapStack.first()[var] = *it;
                }
                (*vmi).erase(it);
                while (--vmi != m_valuemapStack.begin())
                    (*vmi).remove(var);
                break;
            }
        }
        return ReturnTrue;
    }
    case T_INFILE:
        if (args.count() < 2 || args.count() > 3) {
            evalError(fL1S("infile(file, var, [values]) requires two or three arguments."));
        } else {
            ProValueMap vars;
            QString fn = resolvePath(m_option->expandEnvVars(args.at(0).toQString(m_tmp1)));
            fn.detach();
            VisitReturn ok = evaluateFileInto(fn, &vars, LoadProOnly);
            if (ok != ReturnTrue)
                return ok;
            if (args.count() == 2)
                return returnBool(vars.contains(map(args.at(1))));
            QRegExp regx;
            const QString &qry = args.at(2).toQString(m_tmp1);
            if (qry != QRegExp::escape(qry)) {
                QString copy = qry;
                copy.detach();
                regx.setPattern(copy);
            }
            int t = 0;
            foreach (const ProString &s, vars.value(map(args.at(1)))) {
                if ((!regx.isEmpty() && regx.exactMatch(s.toQString(m_tmp[t]))) || s == qry)
                    return ReturnTrue;
                t ^= 1;
            }
        }
        return ReturnFalse;
#ifdef PROEVALUATOR_FULL
    case T_REQUIRES:
        checkRequirements(args);
        return ReturnFalse; // Another qmake breakage
#endif
    case T_EVAL: {
            VisitReturn ret = ReturnFalse;
            ProFile *pro = m_parser->parsedProBlock(args.join(statics.field_sep),
                                                    m_current.pro->fileName(), m_current.line);
            if (pro) {
                if (m_cumulative || pro->isOk()) {
                    m_locationStack.push(m_current);
                    visitProBlock(pro, pro->tokPtr());
                    ret = ReturnTrue; // This return value is not too useful, but that's qmake
                    m_current = m_locationStack.pop();
                }
                pro->deref();
            }
            return ret;
        }
    case T_IF: {
        if (args.count() != 1) {
            evalError(fL1S("if(condition) requires one argument."));
            return ReturnFalse;
        }
        return returnBool(evaluateConditional(args.at(0).toQString(),
                                              m_current.pro->fileName(), m_current.line));
    }
    case T_CONFIG: {
        if (args.count() < 1 || args.count() > 2) {
            evalError(fL1S("CONFIG(config) requires one or two arguments."));
            return ReturnFalse;
        }
        if (args.count() == 1)
            return returnBool(isActiveConfig(args.at(0).toQString(m_tmp2)));
        const QStringList &mutuals = args.at(1).toQString(m_tmp2).split(QLatin1Char('|'));
        const ProStringList &configs = values(statics.strCONFIG);
        for (int i = configs.size() - 1; i >= 0; i--) {
            for (int mut = 0; mut < mutuals.count(); mut++) {
                if (configs[i] == mutuals[mut].trimmed()) {
                    return returnBool(configs[i] == args[0]);
                }
            }
        }
        return ReturnFalse;
    }
    case T_CONTAINS: {
        if (args.count() < 2 || args.count() > 3) {
            evalError(fL1S("contains(var, val) requires two or three arguments."));
            return ReturnFalse;
        }
        const QString &qry = args.at(1).toQString(m_tmp1);
        QRegExp regx;
        if (qry != QRegExp::escape(qry)) {
            QString copy = qry;
            copy.detach();
            regx.setPattern(copy);
        }
        const ProStringList &l = values(map(args.at(0)));
        if (args.count() == 2) {
            int t = 0;
            for (int i = 0; i < l.size(); ++i) {
                const ProString &val = l[i];
                if ((!regx.isEmpty() && regx.exactMatch(val.toQString(m_tmp[t]))) || val == qry)
                    return ReturnTrue;
                t ^= 1;
            }
        } else {
            const QStringList &mutuals = args.at(2).toQString(m_tmp3).split(QLatin1Char('|'));
            for (int i = l.size() - 1; i >= 0; i--) {
                const ProString val = l[i];
                for (int mut = 0; mut < mutuals.count(); mut++) {
                    if (val == mutuals[mut].trimmed()) {
                        return returnBool((!regx.isEmpty()
                                           && regx.exactMatch(val.toQString(m_tmp2)))
                                          || val == qry);
                    }
                }
            }
        }
        return ReturnFalse;
    }
    case T_COUNT: {
        if (args.count() != 2 && args.count() != 3) {
            evalError(fL1S("count(var, count, op=\"equals\") requires two or three arguments."));
            return ReturnFalse;
        }
        int cnt = values(map(args.at(0))).count();
        if (args.count() == 3) {
            const ProString &comp = args.at(2);
            const int val = args.at(1).toQString(m_tmp1).toInt();
            if (comp == QLatin1String(">") || comp == QLatin1String("greaterThan")) {
                return returnBool(cnt > val);
            } else if (comp == QLatin1String(">=")) {
                return returnBool(cnt >= val);
            } else if (comp == QLatin1String("<") || comp == QLatin1String("lessThan")) {
                return returnBool(cnt < val);
            } else if (comp == QLatin1String("<=")) {
                return returnBool(cnt <= val);
            } else if (comp == QLatin1String("equals") || comp == QLatin1String("isEqual")
                       || comp == QLatin1String("=") || comp == QLatin1String("==")) {
                return returnBool(cnt == val);
            } else {
                evalError(fL1S("Unexpected modifier to count(%2).").arg(comp.toQString(m_tmp1)));
                return ReturnFalse;
            }
        }
        return returnBool(cnt == args.at(1).toQString(m_tmp1).toInt());
    }
    case T_GREATERTHAN:
    case T_LESSTHAN: {
        if (args.count() != 2) {
            evalError(fL1S("%1(variable, value) requires two arguments.")
                      .arg(function.toQString(m_tmp1)));
            return ReturnFalse;
        }
        const QString &rhs(args.at(1).toQString(m_tmp1)),
                      &lhs(values(map(args.at(0))).join(statics.field_sep));
        bool ok;
        int rhs_int = rhs.toInt(&ok);
        if (ok) { // do integer compare
            int lhs_int = lhs.toInt(&ok);
            if (ok) {
                if (func_t == T_GREATERTHAN)
                    return returnBool(lhs_int > rhs_int);
                return returnBool(lhs_int < rhs_int);
            }
        }
        if (func_t == T_GREATERTHAN)
            return returnBool(lhs > rhs);
        return returnBool(lhs < rhs);
    }
    case T_EQUALS:
        if (args.count() != 2) {
            evalError(fL1S("%1(variable, value) requires two arguments.")
                      .arg(function.toQString(m_tmp1)));
            return ReturnFalse;
        }
        return returnBool(values(map(args.at(0))).join(statics.field_sep)
                          == args.at(1).toQString(m_tmp1));
    case T_CLEAR: {
        if (args.count() != 1) {
            evalError(fL1S("%1(variable) requires one argument.")
                      .arg(function.toQString(m_tmp1)));
            return ReturnFalse;
        }
        ProValueMap *hsh;
        ProValueMap::Iterator it;
        const ProKey &var = map(args.at(0));
        if (!(hsh = findValues(var, &it)))
            return ReturnFalse;
        if (hsh == &m_valuemapStack.top())
            it->clear();
        else
            m_valuemapStack.top()[var].clear();
        return ReturnTrue;
    }
    case T_UNSET: {
        if (args.count() != 1) {
            evalError(fL1S("%1(variable) requires one argument.")
                      .arg(function.toQString(m_tmp1)));
            return ReturnFalse;
        }
        ProValueMap *hsh;
        ProValueMap::Iterator it;
        const ProKey &var = map(args.at(0));
        if (!(hsh = findValues(var, &it)))
            return ReturnFalse;
        if (m_valuemapStack.size() == 1)
            hsh->erase(it);
        else if (hsh == &m_valuemapStack.top())
            *it = statics.fakeValue;
        else
            m_valuemapStack.top()[var] = statics.fakeValue;
        return ReturnTrue;
    }
    case T_INCLUDE: {
        if (args.count() < 1 || args.count() > 3) {
            evalError(fL1S("include(file, [into, [silent]]) requires one, two or three arguments."));
            return ReturnFalse;
        }
        QString parseInto;
        LoadFlags flags = 0;
        if (args.count() >= 2) {
            parseInto = args.at(1).toQString(m_tmp2);
            if (args.count() >= 3 && isTrue(args.at(2), m_tmp3))
                flags = LoadSilent;
        }
        QString fn = resolvePath(m_option->expandEnvVars(args.at(0).toQString(m_tmp1)));
        fn.detach();
        VisitReturn ok;
        if (parseInto.isEmpty()) {
            ok = evaluateFileChecked(fn, QMakeHandler::EvalIncludeFile, LoadProOnly | flags);
        } else {
            ProValueMap symbols;
            if ((ok = evaluateFileInto(fn, &symbols, LoadAll | flags)) == ReturnTrue) {
                ProValueMap newMap;
                for (ProValueMap::ConstIterator
                        it = m_valuemapStack.top().constBegin(),
                        end = m_valuemapStack.top().constEnd();
                        it != end; ++it) {
                    const QString &ky = it.key().toQString(m_tmp1);
                    if (!(ky.startsWith(parseInto) &&
                          (ky.length() == parseInto.length()
                           || ky.at(parseInto.length()) == QLatin1Char('.'))))
                        newMap[it.key()] = it.value();
                }
                for (ProValueMap::ConstIterator it = symbols.constBegin();
                     it != symbols.constEnd(); ++it) {
                    const QString &ky = it.key().toQString(m_tmp1);
                    if (!ky.startsWith(QLatin1Char('.')))
                        newMap.insert(ProKey(parseInto + QLatin1Char('.') + ky), it.value());
                }
                m_valuemapStack.top() = newMap;
            }
        }
        if (ok == ReturnFalse && (flags & LoadSilent))
            ok = ReturnTrue;
        return ok;
    }
    case T_LOAD: {
        bool ignore_error = false;
        if (args.count() == 2) {
            ignore_error = isTrue(args.at(1), m_tmp2);
        } else if (args.count() != 1) {
            evalError(fL1S("load(feature) requires one or two arguments."));
            return ReturnFalse;
        }
        VisitReturn ok = evaluateFeatureFile(m_option->expandEnvVars(args.at(0).toQString()),
                                             ignore_error);
        if (ok == ReturnFalse && ignore_error)
            ok = ReturnTrue;
        return ok;
    }
    case T_DEBUG: {
#ifdef PROEVALUATOR_DEBUG
        if (args.count() != 2) {
            evalError(fL1S("debug(level, message) requires two arguments."));
            return ReturnFalse;
        }
        int level = args.at(0).toInt();
        if (level <= m_debugLevel) {
            const QString &msg = m_option->expandEnvVars(args.at(1).toQString(m_tmp2));
            debugMsg(level, "Project DEBUG: %s", qPrintable(msg));
        }
#endif
        return ReturnTrue;
    }
    case T_LOG:
    case T_ERROR:
    case T_WARNING:
    case T_MESSAGE: {
        if (args.count() != 1) {
            evalError(fL1S("%1(message) requires one argument.")
                      .arg(function.toQString(m_tmp1)));
            return ReturnFalse;
        }
        const QString &msg = m_option->expandEnvVars(args.at(0).toQString(m_tmp2));
        if (!m_skipLevel) {
            if (func_t == T_LOG) {
#ifdef PROEVALUATOR_FULL
                fputs(msg.toLatin1().constData(), stderr);
#endif
            } else {
                m_handler->fileMessage(fL1S("Project %1: %2")
                                       .arg(function.toQString(m_tmp1).toUpper(), msg));
            }
        }
        return (func_t == T_ERROR && !m_cumulative) ? ReturnError : ReturnTrue;
    }
#ifdef PROEVALUATOR_FULL
    case T_SYSTEM: {
        if (m_cumulative) // Anything else would be insanity
            return ReturnFalse;
        if (args.count() != 1) {
            evalError(fL1S("system(exec) requires one argument."));
            return ReturnFalse;
        }
#ifndef QT_BOOTSTRAPPED
        QProcess proc;
        proc.setProcessChannelMode(QProcess::ForwardedChannels);
        runProcess(&proc, args.at(0).toQString(m_tmp2));
        return returnBool(proc.exitStatus() == QProcess::NormalExit && proc.exitCode() == 0);
#else
        return returnBool(system((QLatin1String("cd ")
                                  + IoUtils::shellQuote(QDir::toNativeSeparators(currentDirectory()))
                                  + QLatin1String(" && ") + args.at(0)).toLocal8Bit().constData()) == 0);
#endif
    }
#endif
    case T_ISEMPTY: {
        if (args.count() != 1) {
            evalError(fL1S("isEmpty(var) requires one argument."));
            return ReturnFalse;
        }
        return returnBool(values(map(args.at(0))).isEmpty());
    }
    case T_EXISTS: {
        if (args.count() != 1) {
            evalError(fL1S("exists(file) requires one argument."));
            return ReturnFalse;
        }
        const QString &file = resolvePath(m_option->expandEnvVars(args.at(0).toQString(m_tmp1)));
        if (IoUtils::exists(file)) {
            return ReturnTrue;
        }
        int slsh = file.lastIndexOf(QLatin1Char('/'));
        QString fn = file.mid(slsh+1);
        if (fn.contains(QLatin1Char('*')) || fn.contains(QLatin1Char('?'))) {
            QString dirstr = file.left(slsh+1);
            if (!QDir(dirstr).entryList(QStringList(fn)).isEmpty())
                return ReturnTrue;
        }
        return ReturnFalse;
    }
#ifdef PROEVALUATOR_FULL
    case T_MKPATH: {
        if (args.count() != 1) {
            evalError(fL1S("mkpath(file) requires one argument."));
            return ReturnFalse;
        }
        const QString &fn = resolvePath(args.at(0).toQString(m_tmp1));
        if (!QDir::current().mkpath(fn)) {
            evalError(fL1S("Cannot create directory %1.").arg(QDir::toNativeSeparators(fn)));
            return ReturnFalse;
        }
        return ReturnTrue;
    }
    case T_WRITE_FILE: {
        if (args.count() > 3) {
            evalError(fL1S("write_file(name, [content var, [append]]) requires one to three arguments."));
            return ReturnFalse;
        }
        QIODevice::OpenMode mode = QIODevice::Truncate;
        QString contents;
        if (args.count() >= 2) {
            const ProStringList &vals = values(args.at(1).toKey());
            if (!vals.isEmpty())
                contents = vals.join(fL1S("\n")) + QLatin1Char('\n');
            if (args.count() >= 3)
                if (!args.at(2).toQString(m_tmp1).compare(fL1S("append"), Qt::CaseInsensitive))
                    mode = QIODevice::Append;
        }
        return writeFile(QString(), resolvePath(args.at(0).toQString(m_tmp1)), mode, contents);
    }
    case T_TOUCH: {
        if (args.count() != 2) {
            evalError(fL1S("touch(file, reffile) requires two arguments."));
            return ReturnFalse;
        }
        const QString &tfn = resolvePath(args.at(0).toQString(m_tmp1));
        const QString &rfn = resolvePath(args.at(1).toQString(m_tmp2));
#ifdef Q_OS_UNIX
        struct stat st;
        if (stat(rfn.toLocal8Bit().constData(), &st)) {
            evalError(fL1S("Cannot stat() reference file %1: %2.").arg(rfn, fL1S(strerror(errno))));
            return ReturnFalse;
        }
        struct utimbuf utb;
        utb.actime = time(0);
        utb.modtime = st.st_mtime;
        if (utime(tfn.toLocal8Bit().constData(), &utb)) {
            evalError(fL1S("Cannot touch %1: %2.").arg(tfn, fL1S(strerror(errno))));
            return ReturnFalse;
        }
#else
        HANDLE rHand = CreateFile((wchar_t*)rfn.utf16(),
                                  GENERIC_READ, FILE_SHARE_READ,
                                  NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
        if (rHand == INVALID_HANDLE_VALUE) {
            evalError(fL1S("Cannot open() reference file %1: %2.").arg(rfn, windowsErrorCode()));
            return ReturnFalse;
        }
        FILETIME ft;
        GetFileTime(rHand, 0, 0, &ft);
        CloseHandle(rHand);
        HANDLE wHand = CreateFile((wchar_t*)tfn.utf16(),
                                  GENERIC_WRITE, FILE_SHARE_READ,
                                  NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
        if (wHand == INVALID_HANDLE_VALUE) {
            evalError(fL1S("Cannot open() %1: %2.").arg(tfn, windowsErrorCode()));
            return ReturnFalse;
        }
        SetFileTime(wHand, 0, 0, &ft);
        CloseHandle(wHand);
#endif
        return ReturnTrue;
    }
    case T_CACHE: {
        if (args.count() > 3) {
            evalError(fL1S("cache(var, [set|add|sub] [transient] [super], [srcvar]) requires one to three arguments."));
            return ReturnFalse;
        }
        bool persist = true;
        bool super = false;
        enum { CacheSet, CacheAdd, CacheSub } mode = CacheSet;
        ProKey srcvar;
        if (args.count() >= 2) {
            foreach (const ProString &opt, split_value_list(args.at(1).toQString(m_tmp2))) {
                opt.toQString(m_tmp3);
                if (m_tmp3 == QLatin1String("transient")) {
                    persist = false;
                } else if (m_tmp3 == QLatin1String("super")) {
                    super = true;
                } else if (m_tmp3 == QLatin1String("set")) {
                    mode = CacheSet;
                } else if (m_tmp3 == QLatin1String("add")) {
                    mode = CacheAdd;
                } else if (m_tmp3 == QLatin1String("sub")) {
                    mode = CacheSub;
                } else {
                    evalError(fL1S("cache(): invalid flag %1.").arg(m_tmp3));
                    return ReturnFalse;
                }
            }
            if (args.count() >= 3) {
                srcvar = args.at(2).toKey();
            } else if (mode != CacheSet) {
                evalError(fL1S("cache(): modes other than 'set' require a source variable."));
                return ReturnFalse;
            }
        }
        QString varstr;
        ProKey dstvar = args.at(0).toKey();
        if (!dstvar.isEmpty()) {
            if (srcvar.isEmpty())
                srcvar = dstvar;
            ProValueMap::Iterator srcvarIt;
            if (!findValues(srcvar, &srcvarIt)) {
                evalError(fL1S("Variable %1 is not defined.").arg(srcvar.toQString(m_tmp1)));
                return ReturnFalse;
            }
            // The caches for the host and target may differ (e.g., when we are manipulating
            // CONFIG), so we cannot compute a common new value for both.
            const ProStringList &diffval = *srcvarIt;
            ProStringList newval;
            bool changed = false;
            for (bool hostBuild = false; ; hostBuild = true) {
                if (QMakeBaseEnv *baseEnv = m_option->baseEnvs.value(
                            QMakeBaseKey(m_buildRoot, hostBuild))) {
                    QMakeEvaluator *baseEval = baseEnv->evaluator;
                    const ProStringList &oldval = baseEval->values(dstvar);
                    if (mode == CacheSet) {
                        newval = diffval;
                    } else {
                        newval = oldval;
                        if (mode == CacheAdd)
                            newval += diffval;
                        else
                            removeEach(&newval, diffval);
                    }
                    if (oldval != newval) {
                        baseEval->valuesRef(dstvar) = newval;
                        if (super) {
                            do {
                                if (dstvar == QLatin1String("QMAKEPATH")) {
                                    baseEval->m_qmakepath = newval.toQStringList();
                                    baseEval->updateMkspecPaths();
                                } else if (dstvar == QLatin1String("QMAKEFEATURES")) {
                                    baseEval->m_qmakefeatures = newval.toQStringList();
                                } else {
                                    break;
                                }
                                baseEval->updateFeaturePaths();
                                if (hostBuild == m_hostBuild)
                                    m_featureRoots = baseEval->m_featureRoots;
                            } while (false);
                        }
                        changed = true;
                    }
                }
                if (hostBuild)
                    break;
            }
            // We assume that whatever got the cached value to be what it is now will do so
            // the next time as well, so we just skip the persisting if nothing changed.
            if (!persist || !changed)
                return ReturnTrue;
            varstr = dstvar.toQString();
            if (mode == CacheAdd)
                varstr += QLatin1String(" +=");
            else if (mode == CacheSub)
                varstr += QLatin1String(" -=");
            else
                varstr += QLatin1String(" =");
            if (diffval.count() == 1) {
                varstr += QLatin1Char(' ');
                varstr += quoteValue(diffval.at(0));
            } else if (!diffval.isEmpty()) {
                foreach (const ProString &vval, diffval) {
                    varstr += QLatin1String(" \\\n    ");
                    varstr += quoteValue(vval);
                }
            }
            varstr += QLatin1Char('\n');
        }
        QString fn;
        if (super) {
            if (m_superfile.isEmpty()) {
                m_superfile = m_outputDir + QLatin1String("/.qmake.super");
                printf("Info: creating super cache file %s\n", qPrintable(m_superfile));
                valuesRef(ProKey("_QMAKE_SUPER_CACHE_")) << ProString(m_superfile);
            }
            fn = m_superfile;
        } else {
            if (m_cachefile.isEmpty()) {
                m_cachefile = m_outputDir + QLatin1String("/.qmake.cache");
                printf("Info: creating cache file %s\n", qPrintable(m_cachefile));
                valuesRef(ProKey("_QMAKE_CACHE_")) << ProString(m_cachefile);
                // We could update m_{source,build}Root and m_featureRoots here, or even
                // "re-home" our rootEnv, but this doesn't sound too useful - if somebody
                // wanted qmake to find something in the build directory, he could have
                // done so "from the outside".
                // The sub-projects will find the new cache all by themselves.
            }
            fn = m_cachefile;
        }
        return writeFile(fL1S("cache "), fn, QIODevice::Append, varstr);
    }
#endif
    default:
        evalError(fL1S("Function '%1' is not implemented.").arg(function.toQString(m_tmp1)));
        return ReturnFalse;
    }
}
QT_END_NAMESPACE
QMakeFileReader/evaluator/qmakeevaluator.cpp
New file
@@ -0,0 +1,2027 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qmakeevaluator.h"
#include "qmakeevaluator_p.h"
#include "qmakeglobals.h"
#include "qmakeparser.h"
#include "ioutils.h"
#include <qbytearray.h>
#include <qdatetime.h>
#include <qdebug.h>
#include <qdir.h>
#include <qfile.h>
#include <qfileinfo.h>
#include <qlist.h>
#include <qregexp.h>
#include <qset.h>
#include <qstack.h>
#include <qstring.h>
#include <qstringlist.h>
#ifdef PROEVALUATOR_THREAD_SAFE
# include <qthreadpool.h>
#endif
#ifdef Q_OS_UNIX
#include <unistd.h>
#include <sys/utsname.h>
#else
#include <windows.h>
#endif
#include <stdio.h>
#include <stdlib.h>
using namespace QMakeInternal;
QT_BEGIN_NAMESPACE
#define fL1S(s) QString::fromLatin1(s)
QMakeBaseKey::QMakeBaseKey(const QString &_root, bool _hostBuild)
    : root(_root), hostBuild(_hostBuild)
{
}
uint qHash(const QMakeBaseKey &key)
{
    return qHash(key.root) ^ (uint)key.hostBuild;
}
bool operator==(const QMakeBaseKey &one, const QMakeBaseKey &two)
{
    return one.root == two.root && one.hostBuild == two.hostBuild;
}
QMakeBaseEnv::QMakeBaseEnv()
    : evaluator(0)
{
#ifdef PROEVALUATOR_THREAD_SAFE
    inProgress = false;
    isOk = false;
#endif
}
QMakeBaseEnv::~QMakeBaseEnv()
{
    delete evaluator;
}
namespace QMakeInternal {
QMakeStatics statics;
}
void QMakeEvaluator::initStatics()
{
    if (!statics.field_sep.isNull())
        return;
    statics.field_sep = QLatin1String(" ");
    statics.strtrue = QLatin1String("true");
    statics.strfalse = QLatin1String("false");
    statics.strCONFIG = ProKey("CONFIG");
    statics.strARGS = ProKey("ARGS");
    statics.strDot = QLatin1String(".");
    statics.strDotDot = QLatin1String("..");
    statics.strever = QLatin1String("ever");
    statics.strforever = QLatin1String("forever");
    statics.strhost_build = QLatin1String("host_build");
    statics.strTEMPLATE = ProKey("TEMPLATE");
#ifdef PROEVALUATOR_FULL
    statics.strREQUIRES = ProKey("REQUIRES");
#endif
    statics.fakeValue = ProStringList(ProString("_FAKE_")); // It has to have a unique begin() value
    initFunctionStatics();
    static const struct {
        const char * const oldname, * const newname;
    } mapInits[] = {
        { "INTERFACES", "FORMS" },
        { "QMAKE_POST_BUILD", "QMAKE_POST_LINK" },
        { "TARGETDEPS", "POST_TARGETDEPS" },
        { "LIBPATH", "QMAKE_LIBDIR" },
        { "QMAKE_EXT_MOC", "QMAKE_EXT_CPP_MOC" },
        { "QMAKE_MOD_MOC", "QMAKE_H_MOD_MOC" },
        { "QMAKE_LFLAGS_SHAPP", "QMAKE_LFLAGS_APP" },
        { "PRECOMPH", "PRECOMPILED_HEADER" },
        { "PRECOMPCPP", "PRECOMPILED_SOURCE" },
        { "INCPATH", "INCLUDEPATH" },
        { "QMAKE_EXTRA_WIN_COMPILERS", "QMAKE_EXTRA_COMPILERS" },
        { "QMAKE_EXTRA_UNIX_COMPILERS", "QMAKE_EXTRA_COMPILERS" },
        { "QMAKE_EXTRA_WIN_TARGETS", "QMAKE_EXTRA_TARGETS" },
        { "QMAKE_EXTRA_UNIX_TARGETS", "QMAKE_EXTRA_TARGETS" },
        { "QMAKE_EXTRA_UNIX_INCLUDES", "QMAKE_EXTRA_INCLUDES" },
        { "QMAKE_EXTRA_UNIX_VARIABLES", "QMAKE_EXTRA_VARIABLES" },
        { "QMAKE_RPATH", "QMAKE_LFLAGS_RPATH" },
        { "QMAKE_FRAMEWORKDIR", "QMAKE_FRAMEWORKPATH" },
        { "QMAKE_FRAMEWORKDIR_FLAGS", "QMAKE_FRAMEWORKPATH_FLAGS" },
        { "IN_PWD", "PWD" }
    };
    for (unsigned i = 0; i < sizeof(mapInits)/sizeof(mapInits[0]); ++i)
        statics.varMap.insert(ProKey(mapInits[i].oldname), ProKey(mapInits[i].newname));
}
const ProKey &QMakeEvaluator::map(const ProKey &var)
{
    QHash<ProKey, ProKey>::ConstIterator it = statics.varMap.constFind(var);
    if (it == statics.varMap.constEnd())
        return var;
    deprecationWarning(fL1S("Variable %1 is deprecated; use %2 instead.")
                       .arg(var.toQString(), it.value().toQString()));
    return it.value();
}
QMakeEvaluator::QMakeEvaluator(QMakeGlobals *option,
                               QMakeParser *parser, QMakeHandler *handler)
  :
#ifdef PROEVALUATOR_DEBUG
    m_debugLevel(option->debugLevel),
#endif
    m_option(option), m_parser(parser), m_handler(handler)
{
    // So that single-threaded apps don't have to call initialize() for now.
    initStatics();
    // Configuration, more or less
    m_caller = 0;
#ifdef PROEVALUATOR_CUMULATIVE
    m_cumulative = false;
#endif
    m_hostBuild = false;
    // Evaluator state
#ifdef PROEVALUATOR_CUMULATIVE
    m_skipLevel = 0;
#endif
    m_listCount = 0;
    m_valuemapStack.push(ProValueMap());
    m_valuemapInited = false;
}
QMakeEvaluator::~QMakeEvaluator()
{
}
void QMakeEvaluator::initFrom(const QMakeEvaluator &other)
{
    Q_ASSERT_X(&other, "QMakeEvaluator::visitProFile", "Project not prepared");
    m_functionDefs = other.m_functionDefs;
    m_valuemapStack = other.m_valuemapStack;
    m_valuemapInited = true;
    m_qmakespec = other.m_qmakespec;
    m_qmakespecName = other.m_qmakespecName;
    m_mkspecPaths = other.m_mkspecPaths;
    m_featureRoots = other.m_featureRoots;
    m_dirSep = other.m_dirSep;
}
//////// Evaluator tools /////////
uint QMakeEvaluator::getBlockLen(const ushort *&tokPtr)
{
    uint len = *tokPtr++;
    len |= (uint)*tokPtr++ << 16;
    return len;
}
ProString QMakeEvaluator::getStr(const ushort *&tokPtr)
{
    uint len = *tokPtr++;
    ProString ret(m_current.pro->items(), tokPtr - m_current.pro->tokPtr(), len);
    ret.setSource(m_current.pro);
    tokPtr += len;
    return ret;
}
ProKey QMakeEvaluator::getHashStr(const ushort *&tokPtr)
{
    uint hash = getBlockLen(tokPtr);
    uint len = *tokPtr++;
    ProKey ret(m_current.pro->items(), tokPtr - m_current.pro->tokPtr(), len, hash);
    tokPtr += len;
    return ret;
}
void QMakeEvaluator::skipStr(const ushort *&tokPtr)
{
    uint len = *tokPtr++;
    tokPtr += len;
}
void QMakeEvaluator::skipHashStr(const ushort *&tokPtr)
{
    tokPtr += 2;
    uint len = *tokPtr++;
    tokPtr += len;
}
// FIXME: this should not build new strings for direct sections.
// Note that the E_SPRINTF and E_LIST implementations rely on the deep copy.
ProStringList QMakeEvaluator::split_value_list(const QString &vals, const ProFile *source)
{
    QString build;
    ProStringList ret;
    QStack<char> quote;
    const ushort SPACE = ' ';
    const ushort LPAREN = '(';
    const ushort RPAREN = ')';
    const ushort SINGLEQUOTE = '\'';
    const ushort DOUBLEQUOTE = '"';
    const ushort BACKSLASH = '\\';
    if (!source)
        source = currentProFile();
    ushort unicode;
    const QChar *vals_data = vals.data();
    const int vals_len = vals.length();
    int parens = 0;
    for (int x = 0; x < vals_len; x++) {
        unicode = vals_data[x].unicode();
        if (x != (int)vals_len-1 && unicode == BACKSLASH &&
            (vals_data[x+1].unicode() == SINGLEQUOTE || vals_data[x+1].unicode() == DOUBLEQUOTE)) {
            build += vals_data[x++]; //get that 'escape'
        } else if (!quote.isEmpty() && unicode == quote.top()) {
            quote.pop();
        } else if (unicode == SINGLEQUOTE || unicode == DOUBLEQUOTE) {
            quote.push(unicode);
        } else if (unicode == RPAREN) {
            --parens;
        } else if (unicode == LPAREN) {
            ++parens;
        }
        if (!parens && quote.isEmpty() && vals_data[x] == SPACE) {
            ret << ProString(build).setSource(source);
            build.clear();
        } else {
            build += vals_data[x];
        }
    }
    if (!build.isEmpty())
        ret << ProString(build).setSource(source);
    if (parens)
        deprecationWarning(fL1S("Unmatched parentheses are deprecated."));
    return ret;
}
static void zipEmpty(ProStringList *value)
{
    for (int i = value->size(); --i >= 0;)
        if (value->at(i).isEmpty())
            value->remove(i);
}
static void insertUnique(ProStringList *varlist, const ProStringList &value)
{
    foreach (const ProString &str, value)
        if (!str.isEmpty() && !varlist->contains(str))
            varlist->append(str);
}
static void removeAll(ProStringList *varlist, const ProString &value)
{
    for (int i = varlist->size(); --i >= 0; )
        if (varlist->at(i) == value)
            varlist->remove(i);
}
void QMakeEvaluator::removeEach(ProStringList *varlist, const ProStringList &value)
{
    foreach (const ProString &str, value)
        if (!str.isEmpty())
            removeAll(varlist, str);
}
static void replaceInList(ProStringList *varlist,
        const QRegExp &regexp, const QString &replace, bool global, QString &tmp)
{
    for (ProStringList::Iterator varit = varlist->begin(); varit != varlist->end(); ) {
        QString val = varit->toQString(tmp);
        QString copy = val; // Force detach and have a reference value
        val.replace(regexp, replace);
        if (!val.isSharedWith(copy) && val != copy) {
            if (val.isEmpty()) {
                varit = varlist->erase(varit);
            } else {
                (*varit).setValue(val);
                ++varit;
            }
            if (!global)
                break;
        } else {
            ++varit;
        }
    }
}
//////// Evaluator /////////
static ALWAYS_INLINE void addStr(
        const ProString &str, ProStringList *ret, bool &pending, bool joined)
{
    if (joined) {
        ret->last().append(str, &pending);
    } else {
        if (!pending) {
            pending = true;
            *ret << str;
        } else {
            ret->last().append(str);
        }
    }
}
static ALWAYS_INLINE void addStrList(
        const ProStringList &list, ushort tok, ProStringList *ret, bool &pending, bool joined)
{
    if (!list.isEmpty()) {
        if (joined) {
            ret->last().append(list, &pending, !(tok & TokQuoted));
        } else {
            if (tok & TokQuoted) {
                if (!pending) {
                    pending = true;
                    *ret << ProString();
                }
                ret->last().append(list);
            } else {
                if (!pending) {
                    // Another qmake bizzarity: if nothing is pending and the
                    // first element is empty, it will be eaten
                    if (!list.at(0).isEmpty()) {
                        // The common case
                        pending = true;
                        *ret += list;
                        return;
                    }
                } else {
                    ret->last().append(list.at(0));
                }
                // This is somewhat slow, but a corner case
                for (int j = 1; j < list.size(); ++j) {
                    pending = true;
                    *ret << list.at(j);
                }
            }
        }
    }
}
void QMakeEvaluator::evaluateExpression(
        const ushort *&tokPtr, ProStringList *ret, bool joined)
{
    debugMsg(2, joined ? "evaluating joined expression" : "evaluating expression");
    if (joined)
        *ret << ProString();
    bool pending = false;
    forever {
        ushort tok = *tokPtr++;
        if (tok & TokNewStr) {
            debugMsg(2, "new string");
            pending = false;
        }
        ushort maskedTok = tok & TokMask;
        switch (maskedTok) {
        case TokLine:
            m_current.line = *tokPtr++;
            break;
        case TokLiteral: {
            const ProString &val = getStr(tokPtr);
            debugMsg(2, "literal %s", dbgStr(val));
            addStr(val, ret, pending, joined);
            break; }
        case TokHashLiteral: {
            const ProKey &val = getHashStr(tokPtr);
            debugMsg(2, "hashed literal %s", dbgStr(val.toString()));
            addStr(val, ret, pending, joined);
            break; }
        case TokVariable: {
            const ProKey &var = getHashStr(tokPtr);
            const ProStringList &val = values(map(var));
            debugMsg(2, "variable %s => %s", dbgKey(var), dbgStrList(val));
            addStrList(val, tok, ret, pending, joined);
            break; }
        case TokProperty: {
            const ProKey &var = getHashStr(tokPtr);
            const ProString &val = propertyValue(var);
            debugMsg(2, "property %s => %s", dbgKey(var), dbgStr(val));
            addStr(val, ret, pending, joined);
            break; }
        case TokEnvVar: {
            const ProString &var = getStr(tokPtr);
            const ProStringList &val = split_value_list(m_option->getEnv(var.toQString(m_tmp1)));
            debugMsg(2, "env var %s => %s", dbgStr(var), dbgStrList(val));
            addStrList(val, tok, ret, pending, joined);
            break; }
        case TokFuncName: {
            const ProKey &func = getHashStr(tokPtr);
            debugMsg(2, "function %s", dbgKey(func));
            addStrList(evaluateExpandFunction(func, tokPtr), tok, ret, pending, joined);
            break; }
        default:
            debugMsg(2, "evaluated expression => %s", dbgStrList(*ret));
            tokPtr--;
            return;
        }
    }
}
void QMakeEvaluator::skipExpression(const ushort *&pTokPtr)
{
    const ushort *tokPtr = pTokPtr;
    forever {
        ushort tok = *tokPtr++;
        switch (tok) {
        case TokLine:
            m_current.line = *tokPtr++;
            break;
        case TokValueTerminator:
        case TokFuncTerminator:
            pTokPtr = tokPtr;
            return;
        case TokArgSeparator:
            break;
        default:
            switch (tok & TokMask) {
            case TokLiteral:
            case TokEnvVar:
                skipStr(tokPtr);
                break;
            case TokHashLiteral:
            case TokVariable:
            case TokProperty:
                skipHashStr(tokPtr);
                break;
            case TokFuncName:
                skipHashStr(tokPtr);
                pTokPtr = tokPtr;
                skipExpression(pTokPtr);
                tokPtr = pTokPtr;
                break;
            default:
                Q_ASSERT_X(false, "skipExpression", "Unrecognized token");
                break;
            }
        }
    }
}
QMakeEvaluator::VisitReturn QMakeEvaluator::visitProBlock(
        ProFile *pro, const ushort *tokPtr)
{
    m_current.pro = pro;
    m_current.line = 0;
    return visitProBlock(tokPtr);
}
QMakeEvaluator::VisitReturn QMakeEvaluator::visitProBlock(
        const ushort *tokPtr)
{
    traceMsg("entering block");
    ProStringList curr;
    bool okey = true, or_op = false, invert = false;
    uint blockLen;
    while (ushort tok = *tokPtr++) {
        VisitReturn ret;
        switch (tok) {
        case TokLine:
            m_current.line = *tokPtr++;
            continue;
        case TokAssign:
        case TokAppend:
        case TokAppendUnique:
        case TokRemove:
        case TokReplace:
            visitProVariable(tok, curr, tokPtr);
            curr.clear();
            continue;
        case TokBranch:
            blockLen = getBlockLen(tokPtr);
            if (m_cumulative) {
#ifdef PROEVALUATOR_CUMULATIVE
                if (!okey)
                    m_skipLevel++;
                ret = blockLen ? visitProBlock(tokPtr) : ReturnTrue;
                tokPtr += blockLen;
                blockLen = getBlockLen(tokPtr);
                if (!okey)
                    m_skipLevel--;
                else
                    m_skipLevel++;
                if ((ret == ReturnTrue || ret == ReturnFalse) && blockLen)
                    ret = visitProBlock(tokPtr);
                if (okey)
                    m_skipLevel--;
#endif
            } else {
                if (okey) {
                    traceMsg("taking 'then' branch");
                    ret = blockLen ? visitProBlock(tokPtr) : ReturnTrue;
                    traceMsg("finished 'then' branch");
                }
                tokPtr += blockLen;
                blockLen = getBlockLen(tokPtr);
                if (!okey) {
                    traceMsg("taking 'else' branch");
                    ret = blockLen ? visitProBlock(tokPtr) : ReturnTrue;
                    traceMsg("finished 'else' branch");
                }
            }
            tokPtr += blockLen;
            okey = true, or_op = false; // force next evaluation
            break;
        case TokForLoop:
            if (m_cumulative) { // This is a no-win situation, so just pretend it's no loop
                skipHashStr(tokPtr);
                uint exprLen = getBlockLen(tokPtr);
                tokPtr += exprLen;
                blockLen = getBlockLen(tokPtr);
                ret = visitProBlock(tokPtr);
            } else if (okey != or_op) {
                const ProKey &variable = getHashStr(tokPtr);
                uint exprLen = getBlockLen(tokPtr);
                const ushort *exprPtr = tokPtr;
                tokPtr += exprLen;
                blockLen = getBlockLen(tokPtr);
                ret = visitProLoop(variable, exprPtr, tokPtr);
            } else {
                skipHashStr(tokPtr);
                uint exprLen = getBlockLen(tokPtr);
                tokPtr += exprLen;
                blockLen = getBlockLen(tokPtr);
                traceMsg("skipped loop");
                ret = ReturnTrue;
            }
            tokPtr += blockLen;
            okey = true, or_op = false; // force next evaluation
            break;
        case TokTestDef:
        case TokReplaceDef:
            if (m_cumulative || okey != or_op) {
                const ProKey &name = getHashStr(tokPtr);
                blockLen = getBlockLen(tokPtr);
                visitProFunctionDef(tok, name, tokPtr);
                traceMsg("defined %s function %s",
                      tok == TokTestDef ? "test" : "replace", dbgKey(name));
            } else {
                traceMsg("skipped function definition");
                skipHashStr(tokPtr);
                blockLen = getBlockLen(tokPtr);
            }
            tokPtr += blockLen;
            okey = true, or_op = false; // force next evaluation
            continue;
        case TokNot:
            traceMsg("NOT");
            invert ^= true;
            continue;
        case TokAnd:
            traceMsg("AND");
            or_op = false;
            continue;
        case TokOr:
            traceMsg("OR");
            or_op = true;
            continue;
        case TokCondition:
            if (!m_skipLevel && okey != or_op) {
                if (curr.size() != 1) {
                    if (!m_cumulative || !curr.isEmpty())
                        evalError(fL1S("Conditional must expand to exactly one word."));
                    okey = false;
                } else {
                    okey = isActiveConfig(curr.at(0).toQString(m_tmp2), true);
                    traceMsg("condition %s is %s", dbgStr(curr.at(0)), dbgBool(okey));
                    okey ^= invert;
                }
            } else {
                traceMsg("skipped condition %s", curr.size() == 1 ? dbgStr(curr.at(0)) : "<invalid>");
            }
            or_op = !okey; // tentatively force next evaluation
            invert = false;
            curr.clear();
            continue;
        case TokTestCall:
            if (!m_skipLevel && okey != or_op) {
                if (curr.size() != 1) {
                    if (!m_cumulative || !curr.isEmpty())
                        evalError(fL1S("Test name must expand to exactly one word."));
                    skipExpression(tokPtr);
                    okey = false;
                } else {
                    traceMsg("evaluating test function %s", dbgStr(curr.at(0)));
                    ret = evaluateConditionalFunction(curr.at(0).toKey(), tokPtr);
                    switch (ret) {
                    case ReturnTrue: okey = true; break;
                    case ReturnFalse: okey = false; break;
                    default:
                        traceMsg("aborting block, function status: %s", dbgReturn(ret));
                        return ret;
                    }
                    traceMsg("test function returned %s", dbgBool(okey));
                    okey ^= invert;
                }
            } else if (m_cumulative) {
#ifdef PROEVALUATOR_CUMULATIVE
                m_skipLevel++;
                if (curr.size() != 1)
                    skipExpression(tokPtr);
                else
                    evaluateConditionalFunction(curr.at(0).toKey(), tokPtr);
                m_skipLevel--;
#endif
            } else {
                skipExpression(tokPtr);
                traceMsg("skipped test function %s", curr.size() == 1 ? dbgStr(curr.at(0)) : "<invalid>");
            }
            or_op = !okey; // tentatively force next evaluation
            invert = false;
            curr.clear();
            continue;
        case TokReturn:
            m_returnValue = curr;
            curr.clear();
            ret = ReturnReturn;
            goto ctrlstm;
        case TokBreak:
            ret = ReturnBreak;
            goto ctrlstm;
        case TokNext:
            ret = ReturnNext;
          ctrlstm:
            if (!m_skipLevel && okey != or_op) {
                traceMsg("flow control statement '%s', aborting block", dbgReturn(ret));
                return ret;
            }
            traceMsg("skipped flow control statement '%s'", dbgReturn(ret));
            okey = false, or_op = true; // force next evaluation
            continue;
        default: {
                const ushort *oTokPtr = --tokPtr;
                evaluateExpression(tokPtr, &curr, false);
                if (tokPtr != oTokPtr)
                    continue;
            }
            Q_ASSERT_X(false, "visitProBlock", "unexpected item type");
            continue;
        }
        if (ret != ReturnTrue && ret != ReturnFalse) {
            traceMsg("aborting block, status: %s", dbgReturn(ret));
            return ret;
        }
    }
    traceMsg("leaving block, okey=%s", dbgBool(okey));
    return returnBool(okey);
}
void QMakeEvaluator::visitProFunctionDef(
        ushort tok, const ProKey &name, const ushort *tokPtr)
{
    QHash<ProKey, ProFunctionDef> *hash =
            (tok == TokTestDef
             ? &m_functionDefs.testFunctions
             : &m_functionDefs.replaceFunctions);
    hash->insert(name, ProFunctionDef(m_current.pro, tokPtr - m_current.pro->tokPtr()));
}
QMakeEvaluator::VisitReturn QMakeEvaluator::visitProLoop(
        const ProKey &_variable, const ushort *exprPtr, const ushort *tokPtr)
{
    VisitReturn ret = ReturnTrue;
    bool infinite = false;
    int index = 0;
    ProKey variable;
    ProStringList oldVarVal;
    ProString it_list = expandVariableReferences(exprPtr, 0, true).at(0);
    if (_variable.isEmpty()) {
        if (it_list != statics.strever) {
            evalError(fL1S("Invalid loop expression."));
            return ReturnFalse;
        }
        it_list = ProString(statics.strforever);
    } else {
        variable = map(_variable);
        oldVarVal = values(variable);
    }
    ProStringList list = values(it_list.toKey());
    if (list.isEmpty()) {
        if (it_list == statics.strforever) {
            infinite = true;
        } else {
            const QString &itl = it_list.toQString(m_tmp1);
            int dotdot = itl.indexOf(statics.strDotDot);
            if (dotdot != -1) {
                bool ok;
                int start = itl.left(dotdot).toInt(&ok);
                if (ok) {
                    int end = itl.mid(dotdot+2).toInt(&ok);
                    if (ok) {
                        if (start < end) {
                            for (int i = start; i <= end; i++)
                                list << ProString(QString::number(i));
                        } else {
                            for (int i = start; i >= end; i--)
                                list << ProString(QString::number(i));
                        }
                    }
                }
            }
        }
    }
    if (infinite)
        traceMsg("entering infinite loop for %s", dbgKey(variable));
    else
        traceMsg("entering loop for %s over %s", dbgKey(variable), dbgStrList(list));
    forever {
        if (infinite) {
            if (!variable.isEmpty())
                m_valuemapStack.top()[variable] = ProStringList(ProString(QString::number(index++)));
            if (index > 1000) {
                evalError(fL1S("Ran into infinite loop (> 1000 iterations)."));
                break;
            }
            traceMsg("loop iteration %d", index);
        } else {
            ProString val;
            do {
                if (index >= list.count())
                    goto do_break;
                val = list.at(index++);
            } while (val.isEmpty()); // stupid, but qmake is like that
            traceMsg("loop iteration %s", dbgStr(val));
            m_valuemapStack.top()[variable] = ProStringList(val);
        }
        ret = visitProBlock(tokPtr);
        switch (ret) {
        case ReturnTrue:
        case ReturnFalse:
            break;
        case ReturnNext:
            ret = ReturnTrue;
            break;
        case ReturnBreak:
            ret = ReturnTrue;
            goto do_break;
        default:
            goto do_break;
        }
    }
  do_break:
    traceMsg("done looping");
    if (!variable.isEmpty())
        m_valuemapStack.top()[variable] = oldVarVal;
    return ret;
}
void QMakeEvaluator::visitProVariable(
        ushort tok, const ProStringList &curr, const ushort *&tokPtr)
{
    int sizeHint = *tokPtr++;
    if (curr.size() != 1) {
        skipExpression(tokPtr);
        if (!m_cumulative || !curr.isEmpty())
            evalError(fL1S("Left hand side of assignment must expand to exactly one word."));
        return;
    }
    const ProKey &varName = map(curr.first());
    if (tok == TokReplace) {      // ~=
        // DEFINES ~= s/a/b/?[gqi]
        const ProStringList &varVal = expandVariableReferences(tokPtr, sizeHint, true);
        const QString &val = varVal.at(0).toQString(m_tmp1);
        if (val.length() < 4 || val.at(0) != QLatin1Char('s')) {
            evalError(fL1S("The ~= operator can handle only the s/// function."));
            return;
        }
        QChar sep = val.at(1);
        QStringList func = val.split(sep);
        if (func.count() < 3 || func.count() > 4) {
            evalError(fL1S("The s/// function expects 3 or 4 arguments."));
            return;
        }
        bool global = false, quote = false, case_sense = false;
        if (func.count() == 4) {
            global = func[3].indexOf(QLatin1Char('g')) != -1;
            case_sense = func[3].indexOf(QLatin1Char('i')) == -1;
            quote = func[3].indexOf(QLatin1Char('q')) != -1;
        }
        QString pattern = func[1];
        QString replace = func[2];
        if (quote)
            pattern = QRegExp::escape(pattern);
        QRegExp regexp(pattern, case_sense ? Qt::CaseSensitive : Qt::CaseInsensitive);
        // We could make a union of modified and unmodified values,
        // but this will break just as much as it fixes, so leave it as is.
        replaceInList(&valuesRef(varName), regexp, replace, global, m_tmp2);
        debugMsg(2, "replaced %s with %s", dbgQStr(pattern), dbgQStr(replace));
    } else {
        ProStringList varVal = expandVariableReferences(tokPtr, sizeHint);
        switch (tok) {
        default: // whatever - cannot happen
        case TokAssign:          // =
            zipEmpty(&varVal);
            if (!m_cumulative) {
                // FIXME: add check+warning about accidental value removal.
                // This may be a bit too noisy, though.
                m_valuemapStack.top()[varName] = varVal;
            } else {
                if (!varVal.isEmpty()) {
                    // We are greedy for values. But avoid exponential growth.
                    ProStringList &v = valuesRef(varName);
                    if (v.isEmpty()) {
                        v = varVal;
                    } else {
                        ProStringList old = v;
                        v = varVal;
                        QSet<ProString> has;
                        has.reserve(v.size());
                        foreach (const ProString &s, v)
                            has.insert(s);
                        v.reserve(v.size() + old.size());
                        foreach (const ProString &s, old)
                            if (!has.contains(s))
                                v << s;
                    }
                }
            }
            debugMsg(2, "assigning");
            break;
        case TokAppendUnique:    // *=
            insertUnique(&valuesRef(varName), varVal);
            debugMsg(2, "appending unique");
            break;
        case TokAppend:          // +=
            zipEmpty(&varVal);
            valuesRef(varName) += varVal;
            debugMsg(2, "appending");
            break;
        case TokRemove:       // -=
            if (!m_cumulative) {
                removeEach(&valuesRef(varName), varVal);
            } else {
                // We are stingy with our values, too.
            }
            debugMsg(2, "removing");
            break;
        }
    }
    traceMsg("%s := %s", dbgKey(varName), dbgStrList(values(varName)));
    if (varName == statics.strTEMPLATE)
        setTemplate();
#ifdef PROEVALUATOR_FULL
    else if (varName == statics.strREQUIRES)
        checkRequirements(values(varName));
#endif
}
void QMakeEvaluator::setTemplate()
{
    ProStringList &values = valuesRef(statics.strTEMPLATE);
    if (!m_option->user_template.isEmpty()) {
        // Don't allow override
        values = ProStringList(ProString(m_option->user_template));
    } else {
        if (values.isEmpty())
            values.append(ProString("app"));
        else
            values.erase(values.begin() + 1, values.end());
    }
    if (!m_option->user_template_prefix.isEmpty()) {
        QString val = values.first().toQString(m_tmp1);
        if (!val.startsWith(m_option->user_template_prefix)) {
            val.prepend(m_option->user_template_prefix);
            values = ProStringList(ProString(val));
        }
    }
}
void QMakeEvaluator::loadDefaults()
{
    ProValueMap &vars = m_valuemapStack.top();
    vars[ProKey("DIR_SEPARATOR")] << ProString(m_option->dir_sep);
    vars[ProKey("DIRLIST_SEPARATOR")] << ProString(m_option->dirlist_sep);
    vars[ProKey("_DATE_")] << ProString(QDateTime::currentDateTime().toString());
    if (!m_option->qmake_abslocation.isEmpty())
        vars[ProKey("QMAKE_QMAKE")] << ProString(m_option->qmake_abslocation);
#if defined(Q_OS_WIN32)
    vars[ProKey("QMAKE_HOST.os")] << ProString("Windows");
    DWORD name_length = 1024;
    wchar_t name[1024];
    if (GetComputerName(name, &name_length))
        vars[ProKey("QMAKE_HOST.name")] << ProString(QString::fromWCharArray(name));
    QSysInfo::WinVersion ver = QSysInfo::WindowsVersion;
    vars[ProKey("QMAKE_HOST.version")] << ProString(QString::number(ver));
    ProString verStr;
    switch (ver) {
    case QSysInfo::WV_Me: verStr = ProString("WinMe"); break;
    case QSysInfo::WV_95: verStr = ProString("Win95"); break;
    case QSysInfo::WV_98: verStr = ProString("Win98"); break;
    case QSysInfo::WV_NT: verStr = ProString("WinNT"); break;
    case QSysInfo::WV_2000: verStr = ProString("Win2000"); break;
    case QSysInfo::WV_2003: verStr = ProString("Win2003"); break;
    case QSysInfo::WV_XP: verStr = ProString("WinXP"); break;
    case QSysInfo::WV_VISTA: verStr = ProString("WinVista"); break;
    default: verStr = ProString("Unknown"); break;
    }
    vars[ProKey("QMAKE_HOST.version_string")] << verStr;
    SYSTEM_INFO info;
    GetSystemInfo(&info);
    ProString archStr;
    switch (info.wProcessorArchitecture) {
# ifdef PROCESSOR_ARCHITECTURE_AMD64
    case PROCESSOR_ARCHITECTURE_AMD64:
        archStr = ProString("x86_64");
        break;
# endif
    case PROCESSOR_ARCHITECTURE_INTEL:
        archStr = ProString("x86");
        break;
    case PROCESSOR_ARCHITECTURE_IA64:
# ifdef PROCESSOR_ARCHITECTURE_IA32_ON_WIN64
    case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64:
# endif
        archStr = ProString("IA64");
        break;
    default:
        archStr = ProString("Unknown");
        break;
    }
    vars[ProKey("QMAKE_HOST.arch")] << archStr;
# if defined(Q_CC_MSVC) // ### bogus condition, but nobody x-builds for msvc with a different qmake
    QLatin1Char backslash('\\');
    QString paths = m_option->getEnv(QLatin1String("PATH"));
    QString vcBin64 = m_option->getEnv(QLatin1String("VCINSTALLDIR"));
    if (!vcBin64.endsWith(backslash))
        vcBin64.append(backslash);
    vcBin64.append(QLatin1String("bin\\amd64"));
    QString vcBinX86_64 = m_option->getEnv(QLatin1String("VCINSTALLDIR"));
    if (!vcBinX86_64.endsWith(backslash))
        vcBinX86_64.append(backslash);
    vcBinX86_64.append(QLatin1String("bin\\x86_amd64"));
    if (paths.contains(vcBin64, Qt::CaseInsensitive)
            || paths.contains(vcBinX86_64, Qt::CaseInsensitive))
        vars[ProKey("QMAKE_TARGET.arch")] << ProString("x86_64");
    else
        vars[ProKey("QMAKE_TARGET.arch")] << ProString("x86");
# endif
#elif defined(Q_OS_UNIX)
    struct utsname name;
    if (!uname(&name)) {
        vars[ProKey("QMAKE_HOST.os")] << ProString(name.sysname);
        vars[ProKey("QMAKE_HOST.name")] << ProString(QString::fromLocal8Bit(name.nodename));
        vars[ProKey("QMAKE_HOST.version")] << ProString(name.release);
        vars[ProKey("QMAKE_HOST.version_string")] << ProString(name.version);
        vars[ProKey("QMAKE_HOST.arch")] << ProString(name.machine);
    }
#endif
    m_valuemapInited = true;
}
bool QMakeEvaluator::prepareProject(const QString &inDir)
{
    QString superdir;
    if (m_option->do_cache) {
        QString conffile;
        QString cachefile = m_option->cachefile;
        if (cachefile.isEmpty())  { //find it as it has not been specified
            if (m_outputDir.isEmpty())
                goto no_cache;
            superdir = m_outputDir;
            forever {
                QString superfile = superdir + QLatin1String("/.qmake.super");
                if (IoUtils::exists(superfile)) {
                    m_superfile = superfile;
                    break;
                }
                QFileInfo qdfi(superdir);
                if (qdfi.isRoot()) {
                    superdir.clear();
                    break;
                }
                superdir = qdfi.path();
            }
            QString sdir = inDir;
            QString dir = m_outputDir;
            forever {
                conffile = sdir + QLatin1String("/.qmake.conf");
                if (!IoUtils::exists(conffile))
                    conffile.clear();
                cachefile = dir + QLatin1String("/.qmake.cache");
                if (!IoUtils::exists(cachefile))
                    cachefile.clear();
                if (!conffile.isEmpty() || !cachefile.isEmpty()) {
                    if (dir != sdir)
                        m_sourceRoot = sdir;
                    m_buildRoot = dir;
                    break;
                }
                if (dir == superdir)
                    goto no_cache;
                QFileInfo qsdfi(sdir);
                QFileInfo qdfi(dir);
                if (qsdfi.isRoot() || qdfi.isRoot())
                    goto no_cache;
                sdir = qsdfi.path();
                dir = qdfi.path();
            }
        } else {
            m_buildRoot = QFileInfo(cachefile).path();
        }
        m_conffile = conffile;
        m_cachefile = cachefile;
    }
  no_cache:
    // Look for mkspecs/ in source and build. First to win determines the root.
    QString sdir = inDir;
    QString dir = m_outputDir;
    while (dir != m_buildRoot) {
        if ((dir != sdir && QFileInfo(sdir, QLatin1String("mkspecs")).isDir())
                || QFileInfo(dir, QLatin1String("mkspecs")).isDir()) {
            if (dir != sdir)
                m_sourceRoot = sdir;
            m_buildRoot = dir;
            break;
        }
        if (dir == superdir)
            break;
        QFileInfo qsdfi(sdir);
        QFileInfo qdfi(dir);
        if (qsdfi.isRoot() || qdfi.isRoot())
            break;
        sdir = qsdfi.path();
        dir = qdfi.path();
    }
    return true;
}
bool QMakeEvaluator::loadSpecInternal()
{
    if (evaluateFeatureFile(QLatin1String("spec_pre.prf")) != ReturnTrue)
        return false;
    QString spec = m_qmakespec + QLatin1String("/qmake.conf");
    if (evaluateFile(spec, QMakeHandler::EvalConfigFile, LoadProOnly) != ReturnTrue) {
        evalError(fL1S("Could not read qmake configuration file %1.").arg(spec));
        return false;
    }
#ifndef QT_BUILD_QMAKE
    // Legacy support for Qt4 default specs
#  ifdef Q_OS_UNIX
    if (m_qmakespec.endsWith(QLatin1String("/default-host"))
        || m_qmakespec.endsWith(QLatin1String("/default"))) {
        QString rspec = QFileInfo(m_qmakespec).readLink();
        if (!rspec.isEmpty())
            m_qmakespec = QDir::cleanPath(QDir(m_qmakespec).absoluteFilePath(rspec));
    }
#  else
    // We can't resolve symlinks as they do on Unix, so configure.exe puts
    // the source of the qmake.conf at the end of the default/qmake.conf in
    // the QMAKESPEC_ORIGINAL variable.
    const ProString &orig_spec = first(ProKey("QMAKESPEC_ORIGINAL"));
    if (!orig_spec.isEmpty())
        m_qmakespec = orig_spec.toQString();
#  endif
#endif
    valuesRef(ProKey("QMAKESPEC")) << ProString(m_qmakespec);
    m_qmakespecName = IoUtils::fileName(m_qmakespec).toString();
    if (evaluateFeatureFile(QLatin1String("spec_post.prf")) != ReturnTrue)
        return false;
    // The MinGW and x-build specs may change the separator; $$shell_{path,quote}() need it
    m_dirSep = first(ProKey("QMAKE_DIR_SEP"));
    return true;
}
bool QMakeEvaluator::loadSpec()
{
    QString qmakespec = m_option->expandEnvVars(
                m_hostBuild ? m_option->qmakespec : m_option->xqmakespec);
    {
        QMakeEvaluator evaluator(m_option, m_parser, m_handler);
        if (!m_superfile.isEmpty()) {
            valuesRef(ProKey("_QMAKE_SUPER_CACHE_")) << ProString(m_superfile);
            if (evaluator.evaluateFile(
                    m_superfile, QMakeHandler::EvalConfigFile, LoadProOnly) != ReturnTrue)
                return false;
        }
        if (!m_conffile.isEmpty()) {
            valuesRef(ProKey("_QMAKE_CONF_")) << ProString(m_conffile);
            if (evaluator.evaluateFile(
                    m_conffile, QMakeHandler::EvalConfigFile, LoadProOnly) != ReturnTrue)
                return false;
        }
        if (!m_cachefile.isEmpty()) {
            valuesRef(ProKey("_QMAKE_CACHE_")) << ProString(m_cachefile);
            if (evaluator.evaluateFile(
                    m_cachefile, QMakeHandler::EvalConfigFile, LoadProOnly) != ReturnTrue)
                return false;
        }
        if (qmakespec.isEmpty()) {
            if (!m_hostBuild)
                qmakespec = evaluator.first(ProKey("XQMAKESPEC")).toQString();
            if (qmakespec.isEmpty())
                qmakespec = evaluator.first(ProKey("QMAKESPEC")).toQString();
        }
        m_qmakepath = evaluator.values(ProKey("QMAKEPATH")).toQStringList();
        m_qmakefeatures = evaluator.values(ProKey("QMAKEFEATURES")).toQStringList();
    }
    updateMkspecPaths();
    if (qmakespec.isEmpty())
        qmakespec = propertyValue(ProKey(m_hostBuild ? "QMAKE_SPEC" : "QMAKE_XSPEC")).toQString();
#ifndef QT_BUILD_QMAKE
    // Legacy support for Qt4 qmake in Qt Creator, etc.
    if (qmakespec.isEmpty())
        qmakespec = m_hostBuild ? QLatin1String("default-host") : QLatin1String("default");
#endif
    if (IoUtils::isRelativePath(qmakespec)) {
        foreach (const QString &root, m_mkspecPaths) {
            QString mkspec = root + QLatin1Char('/') + qmakespec;
            if (IoUtils::exists(mkspec)) {
                qmakespec = mkspec;
                goto cool;
            }
        }
        evalError(fL1S("Could not find qmake configuration file %1.").arg(qmakespec));
        return false;
    }
  cool:
    m_qmakespec = QDir::cleanPath(qmakespec);
    if (!m_superfile.isEmpty()
        && evaluateFile(m_superfile, QMakeHandler::EvalConfigFile, LoadProOnly) != ReturnTrue) {
        return false;
    }
    if (!loadSpecInternal())
        return false;
    updateFeaturePaths(); // The spec extends the feature search path, so rebuild the cache.
    if (!m_conffile.isEmpty()
        && evaluateFile(m_conffile, QMakeHandler::EvalConfigFile, LoadProOnly) != ReturnTrue) {
        return false;
    }
    if (!m_cachefile.isEmpty()
        && evaluateFile(m_cachefile, QMakeHandler::EvalConfigFile, LoadProOnly) != ReturnTrue) {
        return false;
    }
    return true;
}
void QMakeEvaluator::setupProject()
{
    setTemplate();
    ProValueMap &vars = m_valuemapStack.top();
    vars[ProKey("TARGET")] << ProString(QFileInfo(currentFileName()).baseName());
    vars[ProKey("_PRO_FILE_")] << ProString(currentFileName());
    vars[ProKey("_PRO_FILE_PWD_")] << ProString(currentDirectory());
    vars[ProKey("OUT_PWD")] << ProString(m_outputDir);
}
void QMakeEvaluator::evaluateCommand(const QString &cmds, const QString &where)
{
    if (!cmds.isEmpty()) {
        if (ProFile *pro = m_parser->parsedProBlock(cmds, where, -1)) {
            if (pro->isOk()) {
                m_locationStack.push(m_current);
                visitProBlock(pro, pro->tokPtr());
                m_current = m_locationStack.pop();
            }
            pro->deref();
        }
    }
}
QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateConfigFeatures()
{
    QSet<QString> processed;
    forever {
        bool finished = true;
        ProStringList configs = values(statics.strCONFIG);
        for (int i = configs.size() - 1; i >= 0; --i) {
            QString config = configs.at(i).toQString(m_tmp1).toLower();
            if (!processed.contains(config)) {
                config.detach();
                processed.insert(config);
                VisitReturn vr = evaluateFeatureFile(config, true);
                if (vr == ReturnError)
                    return vr;
                if (vr == ReturnTrue) {
                    finished = false;
                    break;
                }
            }
        }
        if (finished)
            break;
    }
    return ReturnTrue;
}
QMakeEvaluator::VisitReturn QMakeEvaluator::visitProFile(
        ProFile *pro, QMakeHandler::EvalFileType type, LoadFlags flags)
{
    if (!m_cumulative && !pro->isOk())
        return ReturnFalse;
    if (flags & LoadPreFiles) {
        if (!prepareProject(pro->directoryName()))
            return ReturnFalse;
        m_hostBuild = pro->isHostBuild();
#ifdef PROEVALUATOR_THREAD_SAFE
        m_option->mutex.lock();
#endif
        QMakeBaseEnv **baseEnvPtr = &m_option->baseEnvs[QMakeBaseKey(m_buildRoot, m_hostBuild)];
        if (!*baseEnvPtr)
            *baseEnvPtr = new QMakeBaseEnv;
        QMakeBaseEnv *baseEnv = *baseEnvPtr;
#ifdef PROEVALUATOR_THREAD_SAFE
        {
            QMutexLocker locker(&baseEnv->mutex);
            m_option->mutex.unlock();
            if (baseEnv->inProgress) {
                QThreadPool::globalInstance()->releaseThread();
                baseEnv->cond.wait(&baseEnv->mutex);
                QThreadPool::globalInstance()->reserveThread();
                if (!baseEnv->isOk)
                    return ReturnFalse;
            } else
#endif
            if (!baseEnv->evaluator) {
#ifdef PROEVALUATOR_THREAD_SAFE
                baseEnv->inProgress = true;
                locker.unlock();
#endif
                QMakeEvaluator *baseEval = new QMakeEvaluator(m_option, m_parser, m_handler);
                baseEnv->evaluator = baseEval;
                baseEval->m_superfile = m_superfile;
                baseEval->m_conffile = m_conffile;
                baseEval->m_cachefile = m_cachefile;
                baseEval->m_sourceRoot = m_sourceRoot;
                baseEval->m_buildRoot = m_buildRoot;
                baseEval->m_hostBuild = m_hostBuild;
                bool ok = baseEval->loadSpec();
#ifdef PROEVALUATOR_THREAD_SAFE
                locker.relock();
                baseEnv->isOk = ok;
                baseEnv->inProgress = false;
                baseEnv->cond.wakeAll();
#endif
                if (!ok)
                    return ReturnFalse;
            }
#ifdef PROEVALUATOR_THREAD_SAFE
        }
#endif
        initFrom(*baseEnv->evaluator);
    } else {
        if (!m_valuemapInited)
            loadDefaults();
    }
#ifdef QT_BUILD_QMAKE
    for (ProValueMap::ConstIterator it = m_extraVars.constBegin();
         it != m_extraVars.constEnd(); ++it)
        m_valuemapStack.first().insert(it.key(), it.value());
#endif
    VisitReturn vr;
    m_handler->aboutToEval(currentProFile(), pro, type);
    m_profileStack.push(pro);
    valuesRef(ProKey("PWD")) = ProStringList(ProString(currentDirectory()));
    if (flags & LoadPreFiles) {
        setupProject();
        if ((vr = evaluateFeatureFile(QLatin1String("default_pre.prf"))) == ReturnError)
            goto failed;
        evaluateCommand(m_option->precmds, fL1S("(command line)"));
#ifdef QT_BUILD_QMAKE
        // After user configs, to override them
        if (!m_extraConfigs.isEmpty())
            evaluateCommand("CONFIG += " + m_extraConfigs.join(' '), fL1S("(extra configs)"));
#endif
    }
    debugMsg(1, "visiting file %s", qPrintable(pro->fileName()));
    if ((vr = visitProBlock(pro, pro->tokPtr())) == ReturnError)
        goto failed;
    debugMsg(1, "done visiting file %s", qPrintable(pro->fileName()));
    if (flags & LoadPostFiles) {
        evaluateCommand(m_option->postcmds, fL1S("(command line -after)"));
#ifdef QT_BUILD_QMAKE
        // Again, to ensure the project does not mess with us.
        // Specifically, do not allow a project to override debug/release within a
        // debug_and_release build pass - it's too late for that at this point anyway.
        if (!m_extraConfigs.isEmpty())
            evaluateCommand("CONFIG += " + m_extraConfigs.join(' '), fL1S("(extra configs)"));
#endif
        if ((vr = evaluateFeatureFile(QLatin1String("default_post.prf"))) == ReturnError)
            goto failed;
        if ((vr = evaluateConfigFeatures()) == ReturnError)
            goto failed;
    }
    vr = ReturnTrue;
  failed:
    m_profileStack.pop();
    valuesRef(ProKey("PWD")) = ProStringList(ProString(currentDirectory()));
    m_handler->doneWithEval(currentProFile());
    return vr;
}
void QMakeEvaluator::updateMkspecPaths()
{
    QStringList ret;
    const QString concat = QLatin1String("/mkspecs");
    foreach (const QString &it, m_option->getPathListEnv(QLatin1String("QMAKEPATH")))
        ret << it + concat;
    foreach (const QString &it, m_qmakepath)
        ret << it + concat;
    if (!m_buildRoot.isEmpty())
        ret << m_buildRoot + concat;
    if (!m_sourceRoot.isEmpty())
        ret << m_sourceRoot + concat;
    ret << m_option->propertyValue(ProKey("QT_HOST_DATA/get")) + concat;
    ret.removeDuplicates();
    m_mkspecPaths = ret;
}
void QMakeEvaluator::updateFeaturePaths()
{
    QString mkspecs_concat = QLatin1String("/mkspecs");
    QString features_concat = QLatin1String("/features/");
    QStringList feature_roots;
    foreach (const QString &f, m_option->getPathListEnv(QLatin1String("QMAKEFEATURES")))
        feature_roots += f;
    feature_roots += m_qmakefeatures;
    feature_roots += m_option->propertyValue(ProKey("QMAKEFEATURES")).toQString(m_mtmp).split(
            m_option->dirlist_sep, QString::SkipEmptyParts);
    QStringList feature_bases;
    if (!m_buildRoot.isEmpty())
        feature_bases << m_buildRoot;
    if (!m_sourceRoot.isEmpty())
        feature_bases << m_sourceRoot;
    foreach (const QString &item, m_option->getPathListEnv(QLatin1String("QMAKEPATH")))
        feature_bases << (item + mkspecs_concat);
    foreach (const QString &item, m_qmakepath)
        feature_bases << (item + mkspecs_concat);
    if (!m_qmakespec.isEmpty()) {
        // The spec is already platform-dependent, so no subdirs here.
        feature_roots << (m_qmakespec + features_concat);
        // Also check directly under the root directory of the mkspecs collection
        QDir specdir(m_qmakespec);
        while (!specdir.isRoot() && specdir.cdUp()) {
            const QString specpath = specdir.path();
            if (specpath.endsWith(mkspecs_concat)) {
                if (IoUtils::exists(specpath + features_concat))
                    feature_bases << specpath;
                break;
            }
        }
    }
    feature_bases << (m_option->propertyValue(ProKey("QT_HOST_DATA/get")).toQString(m_mtmp)
                      + mkspecs_concat);
    foreach (const QString &fb, feature_bases) {
        foreach (const ProString &sfx, values(ProKey("QMAKE_PLATFORM")))
            feature_roots << (fb + features_concat + sfx + QLatin1Char('/'));
        feature_roots << (fb + features_concat);
    }
    for (int i = 0; i < feature_roots.count(); ++i)
        if (!feature_roots.at(i).endsWith((ushort)'/'))
            feature_roots[i].append((ushort)'/');
    feature_roots.removeDuplicates();
    QStringList ret;
    foreach (const QString &root, feature_roots)
        if (IoUtils::exists(root))
            ret << root;
    m_featureRoots = ret;
}
ProString QMakeEvaluator::propertyValue(const ProKey &name) const
{
    if (name == QLatin1String("QMAKE_MKSPECS"))
        return ProString(m_mkspecPaths.join(m_option->dirlist_sep));
    ProString ret = m_option->propertyValue(name);
//    if (ret.isNull())
//        evalError(fL1S("Querying unknown property %1").arg(name.toQString(m_mtmp)));
    return ret;
}
ProFile *QMakeEvaluator::currentProFile() const
{
    if (m_profileStack.count() > 0)
        return m_profileStack.top();
    return 0;
}
QString QMakeEvaluator::currentFileName() const
{
    ProFile *pro = currentProFile();
    if (pro)
        return pro->fileName();
    return QString();
}
QString QMakeEvaluator::currentDirectory() const
{
    ProFile *pro = currentProFile();
    if (pro)
        return pro->directoryName();
    return QString();
}
bool QMakeEvaluator::isActiveConfig(const QString &config, bool regex)
{
    // magic types for easy flipping
    if (config == statics.strtrue)
        return true;
    if (config == statics.strfalse)
        return false;
    if (config == statics.strhost_build)
        return m_hostBuild;
    if (regex && (config.contains(QLatin1Char('*')) || config.contains(QLatin1Char('?')))) {
        QString cfg = config;
        cfg.detach(); // Keep m_tmp out of QRegExp's cache
        QRegExp re(cfg, Qt::CaseSensitive, QRegExp::Wildcard);
        // mkspecs
        if (re.exactMatch(m_qmakespecName))
            return true;
        // CONFIG variable
        int t = 0;
        foreach (const ProString &configValue, values(statics.strCONFIG)) {
            if (re.exactMatch(configValue.toQString(m_tmp[t])))
                return true;
            t ^= 1;
        }
    } else {
        // mkspecs
        if (m_qmakespecName == config)
            return true;
        // CONFIG variable
        if (values(statics.strCONFIG).contains(ProString(config)))
            return true;
    }
    return false;
}
ProStringList QMakeEvaluator::expandVariableReferences(
        const ushort *&tokPtr, int sizeHint, bool joined)
{
    ProStringList ret;
    ret.reserve(sizeHint);
    forever {
        evaluateExpression(tokPtr, &ret, joined);
        switch (*tokPtr) {
        case TokValueTerminator:
        case TokFuncTerminator:
            tokPtr++;
            return ret;
        case TokArgSeparator:
            if (joined) {
                tokPtr++;
                continue;
            }
            // fallthrough
        default:
            Q_ASSERT_X(false, "expandVariableReferences", "Unrecognized token");
            break;
        }
    }
}
QList<ProStringList> QMakeEvaluator::prepareFunctionArgs(const ushort *&tokPtr)
{
    QList<ProStringList> args_list;
    if (*tokPtr != TokFuncTerminator) {
        for (;; tokPtr++) {
            ProStringList arg;
            evaluateExpression(tokPtr, &arg, false);
            args_list << arg;
            if (*tokPtr == TokFuncTerminator)
                break;
            Q_ASSERT(*tokPtr == TokArgSeparator);
        }
    }
    tokPtr++;
    return args_list;
}
ProStringList QMakeEvaluator::evaluateFunction(
        const ProFunctionDef &func, const QList<ProStringList> &argumentsList, VisitReturn *ok)
{
    VisitReturn vr;
    ProStringList ret;
    if (m_valuemapStack.count() >= 100) {
        evalError(fL1S("Ran into infinite recursion (depth > 100)."));
        vr = ReturnFalse;
    } else {
        m_valuemapStack.push(ProValueMap());
        m_locationStack.push(m_current);
        ProStringList args;
        for (int i = 0; i < argumentsList.count(); ++i) {
            args += argumentsList[i];
            m_valuemapStack.top()[ProKey(QString::number(i+1))] = argumentsList[i];
        }
        m_valuemapStack.top()[statics.strARGS] = args;
        vr = visitProBlock(func.pro(), func.tokPtr());
        if (vr == ReturnReturn)
            vr = ReturnTrue;
        ret = m_returnValue;
        m_returnValue.clear();
        m_current = m_locationStack.pop();
        m_valuemapStack.pop();
    }
    if (ok)
        *ok = vr;
    if (vr == ReturnTrue)
        return ret;
    return ProStringList();
}
QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBoolFunction(
        const ProFunctionDef &func, const QList<ProStringList> &argumentsList,
        const ProString &function)
{
    VisitReturn vr;
    ProStringList ret = evaluateFunction(func, argumentsList, &vr);
    if (vr == ReturnTrue) {
        if (ret.isEmpty())
            return ReturnTrue;
        if (ret.at(0) != statics.strfalse) {
            if (ret.at(0) == statics.strtrue)
                return ReturnTrue;
            bool ok;
            int val = ret.at(0).toQString(m_tmp1).toInt(&ok);
            if (ok) {
                if (val)
                    return ReturnTrue;
            } else {
                evalError(fL1S("Unexpected return value from test '%1': %2.")
                          .arg(function.toQString(m_tmp1))
                          .arg(ret.join(QLatin1String(" :: "))));
            }
        }
        return ReturnFalse;
    }
    return vr;
}
QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateConditionalFunction(
        const ProKey &func, const ushort *&tokPtr)
{
    if (int func_t = statics.functions.value(func)) {
        //why don't the builtin functions just use args_list? --Sam
        return evaluateBuiltinConditional(func_t, func, expandVariableReferences(tokPtr, 5, true));
    }
    QHash<ProKey, ProFunctionDef>::ConstIterator it =
            m_functionDefs.testFunctions.constFind(func);
    if (it != m_functionDefs.testFunctions.constEnd()) {
        const QList<ProStringList> args = prepareFunctionArgs(tokPtr);
        traceMsg("calling %s(%s)", dbgKey(func), dbgStrListList(args));
        return evaluateBoolFunction(*it, args, func);
    }
    skipExpression(tokPtr);
    evalError(fL1S("'%1' is not a recognized test function.").arg(func.toQString(m_tmp1)));
    return ReturnFalse;
}
ProStringList QMakeEvaluator::evaluateExpandFunction(
        const ProKey &func, const ushort *&tokPtr)
{
    if (int func_t = statics.expands.value(func)) {
        //why don't the builtin functions just use args_list? --Sam
        return evaluateBuiltinExpand(func_t, func, expandVariableReferences(tokPtr, 5, true));
    }
    QHash<ProKey, ProFunctionDef>::ConstIterator it =
            m_functionDefs.replaceFunctions.constFind(func);
    if (it != m_functionDefs.replaceFunctions.constEnd()) {
        const QList<ProStringList> args = prepareFunctionArgs(tokPtr);
        traceMsg("calling $$%s(%s)", dbgKey(func), dbgStrListList(args));
        return evaluateFunction(*it, args, 0);
    }
    skipExpression(tokPtr);
    evalError(fL1S("'%1' is not a recognized replace function.").arg(func.toQString(m_tmp1)));
    return ProStringList();
}
bool QMakeEvaluator::evaluateConditional(const QString &cond, const QString &where, int line)
{
    bool ret = false;
    ProFile *pro = m_parser->parsedProBlock(cond, where, line, QMakeParser::TestGrammar);
    if (pro) {
        if (pro->isOk()) {
            m_locationStack.push(m_current);
            ret = visitProBlock(pro, pro->tokPtr()) == ReturnTrue;
            m_current = m_locationStack.pop();
        }
        pro->deref();
    }
    return ret;
}
#ifdef PROEVALUATOR_FULL
void QMakeEvaluator::checkRequirements(const ProStringList &deps)
{
    ProStringList &failed = valuesRef(ProKey("QMAKE_FAILED_REQUIREMENTS"));
    foreach (const ProString &dep, deps)
        if (!evaluateConditional(dep.toQString(), m_current.pro->fileName(), m_current.line))
            failed << dep;
}
#endif
ProValueMap *QMakeEvaluator::findValues(const ProKey &variableName, ProValueMap::Iterator *rit)
{
    ProValueMapStack::Iterator vmi = m_valuemapStack.end();
    do {
        --vmi;
        ProValueMap::Iterator it = (*vmi).find(variableName);
        if (it != (*vmi).end()) {
            if (it->constBegin() == statics.fakeValue.constBegin())
                return 0;
            *rit = it;
            return &(*vmi);
        }
    } while (vmi != m_valuemapStack.begin());
    return 0;
}
ProStringList &QMakeEvaluator::valuesRef(const ProKey &variableName)
{
    ProValueMap::Iterator it = m_valuemapStack.top().find(variableName);
    if (it != m_valuemapStack.top().end()) {
        if (it->constBegin() == statics.fakeValue.constBegin())
            it->clear();
        return *it;
    }
    ProValueMapStack::Iterator vmi = m_valuemapStack.end();
    if (--vmi != m_valuemapStack.begin()) {
        do {
            --vmi;
            ProValueMap::ConstIterator it = (*vmi).constFind(variableName);
            if (it != (*vmi).constEnd()) {
                ProStringList &ret = m_valuemapStack.top()[variableName];
                if (it->constBegin() != statics.fakeValue.constBegin())
                    ret = *it;
                return ret;
            }
        } while (vmi != m_valuemapStack.begin());
    }
    return m_valuemapStack.top()[variableName];
}
ProStringList QMakeEvaluator::values(const ProKey &variableName) const
{
    ProValueMapStack::ConstIterator vmi = m_valuemapStack.constEnd();
    do {
        --vmi;
        ProValueMap::ConstIterator it = (*vmi).constFind(variableName);
        if (it != (*vmi).constEnd()) {
            if (it->constBegin() == statics.fakeValue.constBegin())
                break;
            return *it;
        }
    } while (vmi != m_valuemapStack.constBegin());
    return ProStringList();
}
ProString QMakeEvaluator::first(const ProKey &variableName) const
{
    const ProStringList &vals = values(variableName);
    if (!vals.isEmpty())
        return vals.first();
    return ProString();
}
QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateFile(
        const QString &fileName, QMakeHandler::EvalFileType type, LoadFlags flags)
{
    if (ProFile *pro = m_parser->parsedProFile(fileName, true)) {
        m_locationStack.push(m_current);
        VisitReturn ok = visitProFile(pro, type, flags);
        m_current = m_locationStack.pop();
        pro->deref();
#ifdef PROEVALUATOR_FULL
        if (ok == ReturnTrue) {
            ProStringList &iif = m_valuemapStack.first()[ProKey("QMAKE_INTERNAL_INCLUDED_FILES")];
            ProString ifn(fileName);
            if (!iif.contains(ifn))
                iif << ifn;
        }
#endif
        return ok;
    } else {
        if (!(flags & LoadSilent) && !IoUtils::exists(fileName))
            evalError(fL1S("WARNING: Include file %1 not found").arg(fileName));
        return ReturnFalse;
    }
}
QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateFileChecked(
        const QString &fileName, QMakeHandler::EvalFileType type, LoadFlags flags)
{
    if (fileName.isEmpty())
        return ReturnFalse;
    QMakeEvaluator *ref = this;
    do {
        foreach (const ProFile *pf, ref->m_profileStack)
            if (pf->fileName() == fileName) {
                evalError(fL1S("Circular inclusion of %1.").arg(fileName));
                return ReturnFalse;
            }
    } while ((ref = ref->m_caller));
    return evaluateFile(fileName, type, flags);
}
QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateFeatureFile(
        const QString &fileName, bool silent)
{
    QString fn = fileName;
    if (!fn.endsWith(QLatin1String(".prf")))
        fn += QLatin1String(".prf");
    if (m_featureRoots.isEmpty())
        updateFeaturePaths();
    int start_root = 0;
    QString currFn = currentFileName();
    if (IoUtils::fileName(currFn) == IoUtils::fileName(fn)) {
        for (int root = 0; root < m_featureRoots.size(); ++root)
            if (currFn == m_featureRoots.at(root) + fn) {
                start_root = root + 1;
                break;
            }
    }
    for (int root = start_root; root < m_featureRoots.size(); ++root) {
        QString fname = m_featureRoots.at(root) + fn;
        if (IoUtils::exists(fname)) {
            fn = fname;
            goto cool;
        }
    }
#ifdef QMAKE_BUILTIN_PRFS
    fn.prepend(QLatin1String(":/qmake/features/"));
    if (QFileInfo(fn).exists())
        goto cool;
#endif
    if (!silent)
        evalError(fL1S("Cannot find feature %1").arg(fileName));
    return ReturnFalse;
  cool:
    ProStringList &already = valuesRef(ProKey("QMAKE_INTERNAL_INCLUDED_FEATURES"));
    ProString afn(fn);
    if (already.contains(afn)) {
        if (!silent)
            languageWarning(fL1S("Feature %1 already included").arg(fileName));
        return ReturnTrue;
    }
    already.append(afn);
#ifdef PROEVALUATOR_CUMULATIVE
    bool cumulative = m_cumulative;
    m_cumulative = false;
#endif
    // The path is fully normalized already.
    VisitReturn ok = evaluateFile(fn, QMakeHandler::EvalFeatureFile, LoadProOnly);
#ifdef PROEVALUATOR_CUMULATIVE
    m_cumulative = cumulative;
#endif
    return ok;
}
QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateFileInto(
        const QString &fileName, ProValueMap *values, LoadFlags flags)
{
    QMakeEvaluator visitor(m_option, m_parser, m_handler);
    visitor.m_caller = this;
    visitor.m_outputDir = m_outputDir;
    visitor.m_featureRoots = m_featureRoots;
    VisitReturn ret = visitor.evaluateFileChecked(fileName, QMakeHandler::EvalAuxFile, flags);
    if (ret != ReturnTrue)
        return ret;
    *values = visitor.m_valuemapStack.top();
#ifdef PROEVALUATOR_FULL
    ProKey qiif("QMAKE_INTERNAL_INCLUDED_FILES");
    ProStringList &iif = m_valuemapStack.first()[qiif];
    foreach (const ProString &ifn, values->value(qiif))
        if (!iif.contains(ifn))
            iif << ifn;
#endif
    return ReturnTrue;
}
void QMakeEvaluator::message(int type, const QString &msg) const
{
    if (!m_skipLevel)
        m_handler->message(type, msg,
                m_current.line ? m_current.pro->fileName() : QString(),
                m_current.line != 0xffff ? m_current.line : -1);
}
#ifdef PROEVALUATOR_DEBUG
void QMakeEvaluator::debugMsgInternal(int level, const char *fmt, ...) const
{
    va_list ap;
    if (level <= m_debugLevel) {
        fprintf(stderr, "DEBUG %d: ", level);
        va_start(ap, fmt);
        vfprintf(stderr, fmt, ap);
        va_end(ap);
        fputc('\n', stderr);
    }
}
void QMakeEvaluator::traceMsgInternal(const char *fmt, ...) const
{
    va_list ap;
    if (!m_current.pro)
        fprintf(stderr, "DEBUG 1: ");
    else if (m_current.line <= 0)
        fprintf(stderr, "DEBUG 1: %s: ", qPrintable(m_current.pro->fileName()));
    else
        fprintf(stderr, "DEBUG 1: %s:%d: ", qPrintable(m_current.pro->fileName()), m_current.line);
    va_start(ap, fmt);
    vfprintf(stderr, fmt, ap);
    va_end(ap);
    fputc('\n', stderr);
}
QString QMakeEvaluator::formatValue(const ProString &val, bool forceQuote)
{
    QString ret;
    ret.reserve(val.size() + 2);
    const QChar *chars = val.constData();
    bool quote = forceQuote || val.isEmpty();
    for (int i = 0, l = val.size(); i < l; i++) {
        QChar c = chars[i];
        ushort uc = c.unicode();
        if (uc < 32) {
            switch (uc) {
            case '\r':
                ret += QLatin1String("\\r");
                break;
            case '\n':
                ret += QLatin1String("\\n");
                break;
            case '\t':
                ret += QLatin1String("\\t");
                break;
            default:
                ret += QString::fromLatin1("\\x%1").arg(uc, 2, 16, QLatin1Char('0'));
                break;
            }
        } else {
            switch (uc) {
            case '\\':
                ret += QLatin1String("\\\\");
                break;
            case '"':
                ret += QLatin1String("\\\"");
                break;
            case '\'':
                ret += QLatin1String("\\'");
                break;
            case 32:
                quote = true;
                // fallthrough
            default:
                ret += c;
                break;
            }
        }
    }
    if (quote) {
        ret.prepend(QLatin1Char('"'));
        ret.append(QLatin1Char('"'));
    }
    return ret;
}
QString QMakeEvaluator::formatValueList(const ProStringList &vals, bool commas)
{
    QString ret;
    foreach (const ProString &str, vals) {
        if (!ret.isEmpty()) {
            if (commas)
                ret += QLatin1Char(',');
            ret += QLatin1Char(' ');
        }
        ret += formatValue(str);
    }
    return ret;
}
QString QMakeEvaluator::formatValueListList(const QList<ProStringList> &lists)
{
    QString ret;
    foreach (const ProStringList &list, lists) {
        if (!ret.isEmpty())
            ret += QLatin1String(", ");
        ret += formatValueList(list);
    }
    return ret;
}
#endif
QT_END_NAMESPACE
QMakeFileReader/evaluator/qmakeevaluator.h
New file
@@ -0,0 +1,294 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QMAKEEVALUATOR_H
#define QMAKEEVALUATOR_H
#if defined(PROEVALUATOR_FULL) && defined(PROEVALUATOR_THREAD_SAFE)
#  error PROEVALUATOR_FULL is incompatible with PROEVALUATOR_THREAD_SAFE due to cache() implementation
#endif
#include "qmakeparser.h"
#include "ioutils.h"
#include <qlist.h>
#include <qlinkedlist.h>
#include <qset.h>
#include <qstack.h>
#include <qstring.h>
#include <qstringlist.h>
#ifndef QT_BOOTSTRAPPED
# include <qprocess.h>
#endif
QT_BEGIN_NAMESPACE
class QMakeGlobals;
class QMAKE_EXPORT QMakeHandler : public QMakeParserHandler
{
public:
    enum {
        SourceEvaluator = 0x10,
        EvalWarnLanguage = SourceEvaluator |  WarningMessage | WarnLanguage,
        EvalWarnDeprecated = SourceEvaluator | WarningMessage | WarnDeprecated,
        EvalError = ErrorMessage | SourceEvaluator
    };
    // error(), warning() and message() from .pro file
    virtual void fileMessage(const QString &msg) = 0;
    enum EvalFileType { EvalProjectFile, EvalIncludeFile, EvalConfigFile, EvalFeatureFile, EvalAuxFile };
    virtual void aboutToEval(ProFile *parent, ProFile *proFile, EvalFileType type) = 0;
    virtual void doneWithEval(ProFile *parent) = 0;
};
// We use a QLinkedList based stack instead of a QVector based one (QStack), so that
// the addresses of value maps stay constant. The qmake generators rely on that.
class QMAKE_EXPORT ProValueMapStack : public QLinkedList<ProValueMap>
{
public:
    inline void push(const ProValueMap &t) { append(t); }
    inline ProValueMap pop() { return takeLast(); }
    ProValueMap &top() { return last(); }
    const ProValueMap &top() const { return last(); }
};
class QMAKE_EXPORT QMakeEvaluator
{
public:
    enum LoadFlag {
        LoadProOnly = 0,
        LoadPreFiles = 1,
        LoadPostFiles = 2,
        LoadAll = LoadPreFiles|LoadPostFiles,
        LoadSilent = 0x10
    };
    Q_DECLARE_FLAGS(LoadFlags, LoadFlag)
    static void initStatics();
    static void initFunctionStatics();
    QMakeEvaluator(QMakeGlobals *option, QMakeParser *parser,
                   QMakeHandler *handler);
    ~QMakeEvaluator();
#ifdef QT_BUILD_QMAKE
    void setExtraVars(const ProValueMap &extraVars) { m_extraVars = extraVars; }
    void setExtraConfigs(const ProStringList &extraConfigs) { m_extraConfigs = extraConfigs; }
#endif
    void setOutputDir(const QString &outputDir) { m_outputDir = outputDir; }
    ProStringList values(const ProKey &variableName) const;
    ProStringList &valuesRef(const ProKey &variableName);
    ProString first(const ProKey &variableName) const;
    ProString propertyValue(const ProKey &val) const;
    ProString dirSep() const { return m_dirSep; }
    bool isHostBuild() const { return m_hostBuild; }
    enum VisitReturn {
        ReturnFalse,
        ReturnTrue,
        ReturnError,
        ReturnBreak,
        ReturnNext,
        ReturnReturn
    };
    static ALWAYS_INLINE VisitReturn returnBool(bool b)
        { return b ? ReturnTrue : ReturnFalse; }
    static ALWAYS_INLINE uint getBlockLen(const ushort *&tokPtr);
    ProString getStr(const ushort *&tokPtr);
    ProKey getHashStr(const ushort *&tokPtr);
    void evaluateExpression(const ushort *&tokPtr, ProStringList *ret, bool joined);
    static ALWAYS_INLINE void skipStr(const ushort *&tokPtr);
    static ALWAYS_INLINE void skipHashStr(const ushort *&tokPtr);
    void skipExpression(const ushort *&tokPtr);
    void loadDefaults();
    bool prepareProject(const QString &inDir);
    bool loadSpecInternal();
    bool loadSpec();
    void initFrom(const QMakeEvaluator &other);
    void setupProject();
    void evaluateCommand(const QString &cmds, const QString &where);
    VisitReturn visitProFile(ProFile *pro, QMakeHandler::EvalFileType type,
                             LoadFlags flags);
    VisitReturn visitProBlock(ProFile *pro, const ushort *tokPtr);
    VisitReturn visitProBlock(const ushort *tokPtr);
    VisitReturn visitProLoop(const ProKey &variable, const ushort *exprPtr,
                             const ushort *tokPtr);
    void visitProFunctionDef(ushort tok, const ProKey &name, const ushort *tokPtr);
    void visitProVariable(ushort tok, const ProStringList &curr, const ushort *&tokPtr);
    ALWAYS_INLINE const ProKey &map(const ProString &var) { return map(var.toKey()); }
    const ProKey &map(const ProKey &var);
    ProValueMap *findValues(const ProKey &variableName, ProValueMap::Iterator *it);
    void setTemplate();
    ProStringList split_value_list(const QString &vals, const ProFile *source = 0);
    ProStringList expandVariableReferences(const ProString &value, int *pos = 0, bool joined = false);
    ProStringList expandVariableReferences(const ushort *&tokPtr, int sizeHint = 0, bool joined = false);
    QString currentFileName() const;
    QString currentDirectory() const;
    ProFile *currentProFile() const;
    QString resolvePath(const QString &fileName) const
        { return QMakeInternal::IoUtils::resolvePath(currentDirectory(), fileName); }
    VisitReturn evaluateFile(const QString &fileName, QMakeHandler::EvalFileType type,
                             LoadFlags flags);
    VisitReturn evaluateFileChecked(const QString &fileName, QMakeHandler::EvalFileType type,
                                    LoadFlags flags);
    VisitReturn evaluateFeatureFile(const QString &fileName, bool silent = false);
    VisitReturn evaluateFileInto(const QString &fileName,
                                 ProValueMap *values, // output-only
                                 LoadFlags flags);
    VisitReturn evaluateConfigFeatures();
    void message(int type, const QString &msg) const;
    void evalError(const QString &msg) const
            { message(QMakeHandler::EvalError, msg); }
    void languageWarning(const QString &msg) const
            { message(QMakeHandler::EvalWarnLanguage, msg); }
    void deprecationWarning(const QString &msg) const
            { message(QMakeHandler::EvalWarnDeprecated, msg); }
    QList<ProStringList> prepareFunctionArgs(const ushort *&tokPtr);
    ProStringList evaluateFunction(const ProFunctionDef &func,
                                   const QList<ProStringList> &argumentsList, VisitReturn *ok);
    VisitReturn evaluateBoolFunction(const ProFunctionDef &func,
                                     const QList<ProStringList> &argumentsList,
                                     const ProString &function);
    ProStringList evaluateExpandFunction(const ProKey &function, const ushort *&tokPtr);
    VisitReturn evaluateConditionalFunction(const ProKey &function, const ushort *&tokPtr);
    ProStringList evaluateBuiltinExpand(int func_t, const ProKey &function, const ProStringList &args);
    VisitReturn evaluateBuiltinConditional(int func_t, const ProKey &function, const ProStringList &args);
    bool evaluateConditional(const QString &cond, const QString &where, int line = -1);
#ifdef PROEVALUATOR_FULL
    void checkRequirements(const ProStringList &deps);
#endif
    void updateMkspecPaths();
    void updateFeaturePaths();
    bool isActiveConfig(const QString &config, bool regex = false);
    void populateDeps(
            const ProStringList &deps, const ProString &prefix,
            QHash<ProKey, QSet<ProKey> > &dependencies,
            ProValueMap &dependees, ProStringList &rootSet) const;
    VisitReturn writeFile(const QString &ctx, const QString &fn, QIODevice::OpenMode mode,
                          const QString &contents);
#ifndef QT_BOOTSTRAPPED
    void runProcess(QProcess *proc, const QString &command) const;
#endif
    QByteArray getCommandOutput(const QString &args) const;
    static void removeEach(ProStringList *varlist, const ProStringList &value);
    QMakeEvaluator *m_caller;
#ifdef PROEVALUATOR_CUMULATIVE
    bool m_cumulative;
    int m_skipLevel;
#else
    enum { m_cumulative = 0 };
    enum { m_skipLevel = 0 };
#endif
#ifdef PROEVALUATOR_DEBUG
    void debugMsgInternal(int level, const char *fmt, ...) const;
    void traceMsgInternal(const char *fmt, ...) const;
    static QString formatValue(const ProString &val, bool forceQuote = false);
    static QString formatValueList(const ProStringList &vals, bool commas = false);
    static QString formatValueListList(const QList<ProStringList> &vals);
    const int m_debugLevel;
#else
    ALWAYS_INLINE void debugMsgInternal(int, const char *, ...) const {}
    ALWAYS_INLINE void traceMsgInternal(const char *, ...) const {}
    enum { m_debugLevel = 0 };
#endif
    struct Location {
        Location() : pro(0), line(0) {}
        Location(ProFile *_pro, ushort _line) : pro(_pro), line(_line) {}
        void clear() { pro = 0; line = 0; }
        ProFile *pro;
        ushort line;
    };
    Location m_current; // Currently evaluated location
    QStack<Location> m_locationStack; // All execution location changes
    QStack<ProFile *> m_profileStack; // Includes only
#ifdef QT_BUILD_QMAKE
    ProValueMap m_extraVars;
    ProStringList m_extraConfigs;
#endif
    QString m_outputDir;
    int m_listCount;
    bool m_valuemapInited;
    bool m_hostBuild;
    QString m_qmakespec;
    QString m_qmakespecName;
    QString m_superfile;
    QString m_conffile;
    QString m_cachefile;
    QString m_sourceRoot;
    QString m_buildRoot;
    QStringList m_qmakepath;
    QStringList m_qmakefeatures;
    QStringList m_mkspecPaths;
    QStringList m_featureRoots;
    ProString m_dirSep;
    ProFunctionDefs m_functionDefs;
    ProStringList m_returnValue;
    ProValueMapStack m_valuemapStack; // VariableName must be us-ascii, the content however can be non-us-ascii.
    QString m_tmp1, m_tmp2, m_tmp3, m_tmp[2]; // Temporaries for efficient toQString
    mutable QString m_mtmp;
    QMakeGlobals *m_option;
    QMakeParser *m_parser;
    QMakeHandler *m_handler;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QMakeEvaluator::LoadFlags)
QT_END_NAMESPACE
#endif // QMAKEEVALUATOR_H
QMakeFileReader/evaluator/qmakeevaluator_p.h
New file
@@ -0,0 +1,94 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QMAKEEVALUATOR_P_H
#define QMAKEEVALUATOR_P_H
#include "proitems.h"
#include <qregexp.h>
#define debugMsg if (!m_debugLevel) {} else debugMsgInternal
#define traceMsg if (!m_debugLevel) {} else traceMsgInternal
#ifdef PROEVALUATOR_DEBUG
#  define dbgBool(b) (b ? "true" : "false")
#  define dbgReturn(r) \
    (r == ReturnError ? "error" : \
     r == ReturnBreak ? "break" : \
     r == ReturnNext ? "next" : \
     r == ReturnReturn ? "return" : \
     "<invalid>")
#  define dbgKey(s) qPrintable(s.toString().toQString())
#  define dbgStr(s) qPrintable(formatValue(s, true))
#  define dbgStrList(s) qPrintable(formatValueList(s))
#  define dbgSepStrList(s) qPrintable(formatValueList(s, true))
#  define dbgStrListList(s) qPrintable(formatValueListList(s))
#  define dbgQStr(s) dbgStr(ProString(s))
#else
#  define dbgBool(b) 0
#  define dbgReturn(r) 0
#  define dbgKey(s) 0
#  define dbgStr(s) 0
#  define dbgStrList(s) 0
#  define dbgSepStrList(s) 0
#  define dbgStrListList(s) 0
#  define dbgQStr(s) 0
#endif
QT_BEGIN_NAMESPACE
namespace QMakeInternal {
struct QMakeStatics {
    QString field_sep;
    QString strtrue;
    QString strfalse;
    ProKey strCONFIG;
    ProKey strARGS;
    QString strDot;
    QString strDotDot;
    QString strever;
    QString strforever;
    QString strhost_build;
    ProKey strTEMPLATE;
#ifdef PROEVALUATOR_FULL
    ProKey strREQUIRES;
#endif
    QHash<ProKey, int> expands;
    QHash<ProKey, int> functions;
    QHash<ProKey, ProKey> varMap;
    ProStringList fakeValue;
};
extern QMakeStatics statics;
}
QT_END_NAMESPACE
#endif // QMAKEEVALUATOR_P_H
QMakeFileReader/evaluator/qmakeglobals.cpp
New file
@@ -0,0 +1,355 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qmakeglobals.h"
#include "qmakeevaluator.h"
#include "ioutils.h"
#include <qbytearray.h>
#include <qdatetime.h>
#include <qdebug.h>
#include <qdir.h>
#include <qfile.h>
#include <qfileinfo.h>
#include <qlist.h>
#include <qregexp.h>
#include <qset.h>
#include <qstack.h>
#include <qstring.h>
#include <qstringlist.h>
#include <qtextstream.h>
#ifdef PROEVALUATOR_THREAD_SAFE
# include <qthreadpool.h>
#endif
#ifdef Q_OS_UNIX
#include <unistd.h>
#include <sys/utsname.h>
#else
#include <windows.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#ifdef Q_OS_WIN32
#define QT_POPEN _popen
#define QT_PCLOSE _pclose
#else
#define QT_POPEN popen
#define QT_PCLOSE pclose
#endif
QT_BEGIN_NAMESPACE
#define fL1S(s) QString::fromLatin1(s)
namespace { // MSVC doesn't seem to know the semantics of "static" ...
static struct {
    QRegExp reg_variableName;
} statics;
}
static void initStatics()
{
    if (!statics.reg_variableName.isEmpty())
        return;
    statics.reg_variableName.setPattern(QLatin1String("\\$\\(.*\\)"));
    statics.reg_variableName.setMinimal(true);
}
QMakeGlobals::QMakeGlobals()
{
    initStatics();
    do_cache = true;
#ifdef PROEVALUATOR_DEBUG
    debugLevel = 0;
#endif
#ifdef Q_OS_WIN
    dirlist_sep = QLatin1Char(';');
    dir_sep = QLatin1Char('\\');
#else
    dirlist_sep = QLatin1Char(':');
    dir_sep = QLatin1Char('/');
#endif
    qmakespec = getEnv(QLatin1String("QMAKESPEC"));
}
QMakeGlobals::~QMakeGlobals()
{
    qDeleteAll(baseEnvs);
}
QString QMakeGlobals::cleanSpec(QMakeCmdLineParserState &state, const QString &spec)
{
    QString ret = QDir::cleanPath(spec);
    if (ret.contains(QLatin1Char('/'))) {
        QString absRet = QDir(state.pwd).absoluteFilePath(ret);
        if (QFile::exists(absRet))
            ret = QDir::cleanPath(absRet);
    }
    return ret;
}
QMakeGlobals::ArgumentReturn QMakeGlobals::addCommandLineArguments(
        QMakeCmdLineParserState &state, QStringList &args, int *pos)
{
    enum { ArgNone, ArgConfig, ArgSpec, ArgXSpec, ArgTmpl, ArgTmplPfx, ArgCache } argState = ArgNone;
    for (; *pos < args.count(); (*pos)++) {
        QString arg = args.at(*pos);
        switch (argState) {
        case ArgConfig:
            if (state.after)
                state.postconfigs << arg;
            else
                state.preconfigs << arg;
            break;
        case ArgSpec:
            qmakespec = args[*pos] = cleanSpec(state, arg);
            break;
        case ArgXSpec:
            xqmakespec = args[*pos] = cleanSpec(state, arg);
            break;
        case ArgTmpl:
            user_template = arg;
            break;
        case ArgTmplPfx:
            user_template_prefix = arg;
            break;
        case ArgCache:
            cachefile = args[*pos] = QDir::cleanPath(QDir(state.pwd).absoluteFilePath(arg));
            break;
        default:
            if (arg.startsWith(QLatin1Char('-'))) {
                if (arg == QLatin1String("-after")) {
                    state.after = true;
                } else if (arg == QLatin1String("-config")) {
                    argState = ArgConfig;
                } else if (arg == QLatin1String("-nocache")) {
                    do_cache = false;
                } else if (arg == QLatin1String("-cache")) {
                    argState = ArgCache;
                } else if (arg == QLatin1String("-platform") || arg == QLatin1String("-spec")) {
                    argState = ArgSpec;
                } else if (arg == QLatin1String("-xplatform") || arg == QLatin1String("-xspec")) {
                    argState = ArgXSpec;
                } else if (arg == QLatin1String("-template") || arg == QLatin1String("-t")) {
                    argState = ArgTmpl;
                } else if (arg == QLatin1String("-template_prefix") || arg == QLatin1String("-tp")) {
                    argState = ArgTmplPfx;
                } else if (arg == QLatin1String("-win32")) {
                    dir_sep = QLatin1Char('\\');
                } else if (arg == QLatin1String("-unix")) {
                    dir_sep = QLatin1Char('/');
                } else {
                    return ArgumentUnknown;
                }
            } else if (arg.contains(QLatin1Char('='))) {
                if (state.after)
                    state.postcmds << arg;
                else
                    state.precmds << arg;
            } else {
                return ArgumentUnknown;
            }
            continue;
        }
        argState = ArgNone;
    }
    if (argState != ArgNone)
        return ArgumentMalformed;
    return ArgumentsOk;
}
void QMakeGlobals::commitCommandLineArguments(QMakeCmdLineParserState &state)
{
    if (!state.preconfigs.isEmpty())
        state.precmds << (fL1S("CONFIG += ") + state.preconfigs.join(fL1S(" ")));
    precmds = state.precmds.join(fL1S("\n"));
    if (!state.postconfigs.isEmpty())
        state.postcmds << (fL1S("CONFIG += ") + state.postconfigs.join(fL1S(" ")));
    postcmds = state.postcmds.join(fL1S("\n"));
    if (xqmakespec.isEmpty())
        xqmakespec = qmakespec;
}
void QMakeGlobals::useEnvironment()
{
    if (xqmakespec.isEmpty())
        xqmakespec = getEnv(QLatin1String("XQMAKESPEC"));
    if (qmakespec.isEmpty()) {
        qmakespec = getEnv(QLatin1String("QMAKESPEC"));
        if (xqmakespec.isEmpty())
            xqmakespec = qmakespec;
    }
}
void QMakeGlobals::setCommandLineArguments(const QString &pwd, const QStringList &_args)
{
    QStringList args = _args;
    QMakeCmdLineParserState state(pwd);
    for (int pos = 0; pos < args.size(); pos++)
        addCommandLineArguments(state, args, &pos);
    commitCommandLineArguments(state);
    useEnvironment();
}
void QMakeGlobals::setDirectories(const QString &input_dir, const QString &output_dir)
{
    if (input_dir != output_dir && !output_dir.isEmpty()) {
        QString srcpath = input_dir;
        if (!srcpath.endsWith(QLatin1Char('/')))
            srcpath += QLatin1Char('/');
        QString dstpath = output_dir;
        if (!dstpath.endsWith(QLatin1Char('/')))
            dstpath += QLatin1Char('/');
        int srcLen = srcpath.length();
        int dstLen = dstpath.length();
        int lastSl = -1;
        while (++lastSl, srcpath.at(--srcLen) == dstpath.at(--dstLen))
            if (srcpath.at(srcLen) == QLatin1Char('/'))
                lastSl = 0;
        source_root = srcpath.left(srcLen + lastSl);
        build_root = dstpath.left(dstLen + lastSl);
    }
}
QString QMakeGlobals::shadowedPath(const QString &fileName) const
{
    if (source_root.isEmpty())
        return fileName;
    if (fileName.startsWith(source_root)
        && (fileName.length() == source_root.length()
            || fileName.at(source_root.length()) == QLatin1Char('/'))) {
        return build_root + fileName.mid(source_root.length());
    }
    return QString();
}
QString QMakeGlobals::getEnv(const QString &var) const
{
#ifdef PROEVALUATOR_SETENV
    return environment.value(var);
#else
    return QString::fromLocal8Bit(qgetenv(var.toLocal8Bit().constData()));
#endif
}
QStringList QMakeGlobals::getPathListEnv(const QString &var) const
{
    QStringList ret;
    QString val = getEnv(var);
    if (!val.isEmpty()) {
        QDir bdir;
        QStringList vals = val.split(dirlist_sep);
        ret.reserve(vals.length());
        foreach (const QString &it, vals)
            ret << QDir::cleanPath(bdir.absoluteFilePath(it));
    }
    return ret;
}
QString QMakeGlobals::expandEnvVars(const QString &str) const
{
    QString string = str;
    int rep;
    QRegExp reg_variableName = statics.reg_variableName; // Copy for thread safety
    while ((rep = reg_variableName.indexIn(string)) != -1)
        string.replace(rep, reg_variableName.matchedLength(),
                       getEnv(string.mid(rep + 2, reg_variableName.matchedLength() - 3)));
    return string;
}
#ifndef QT_BUILD_QMAKE
#ifdef PROEVALUATOR_INIT_PROPS
bool QMakeGlobals::initProperties()
{
    QByteArray data;
#ifndef QT_BOOTSTRAPPED
    QProcess proc;
    proc.start(qmake_abslocation, QStringList() << QLatin1String("-query"));
    if (!proc.waitForFinished())
        return false;
    data = proc.readAll();
#else
    if (FILE *proc = QT_POPEN(QString(QMakeInternal::IoUtils::shellQuote(qmake_abslocation)
                                      + QLatin1String(" -query")).toLocal8Bit(), "r")) {
        char buff[1024];
        while (!feof(proc))
            data.append(buff, int(fread(buff, 1, 1023, proc)));
        QT_PCLOSE(proc);
    }
#endif
    foreach (QByteArray line, data.split('\n'))
        if (!line.startsWith("QMAKE_")) {
            int off = line.indexOf(':');
            if (off < 0) // huh?
                continue;
            if (line.endsWith('\r'))
                line.chop(1);
            QString name = QString::fromLatin1(line.left(off));
            ProString value = ProString(QDir::fromNativeSeparators(
                        QString::fromLocal8Bit(line.mid(off + 1))));
            properties.insert(ProKey(name), value);
            if (name.startsWith(QLatin1String("QT_")) && !name.contains(QLatin1Char('/'))) {
                if (name.startsWith(QLatin1String("QT_INSTALL_"))) {
                    properties.insert(ProKey(name + QLatin1String("/raw")), value);
                    properties.insert(ProKey(name + QLatin1String("/get")), value);
                    if (name == QLatin1String("QT_INSTALL_PREFIX")
                        || name == QLatin1String("QT_INSTALL_DATA")
                        || name == QLatin1String("QT_INSTALL_BINS")) {
                        name.replace(3, 7, QLatin1String("HOST"));
                        properties.insert(ProKey(name), value);
                        properties.insert(ProKey(name + QLatin1String("/get")), value);
                    }
                } else if (name.startsWith(QLatin1String("QT_HOST_"))) {
                    properties.insert(ProKey(name + QLatin1String("/get")), value);
                }
            }
        }
    properties.insert(ProKey("QMAKE_VERSION"), ProString("2.01a"));
    return true;
}
#else
void QMakeGlobals::setProperties(const QHash<QString, QString> &props)
{
    QHash<QString, QString>::ConstIterator it = props.constBegin(), eit = props.constEnd();
    for (; it != eit; ++it)
        properties.insert(ProKey(it.key()), ProString(it.value()));
}
#endif
#endif // QT_BUILD_QMAKE
QT_END_NAMESPACE
QMakeFileReader/evaluator/qmakeglobals.h
New file
@@ -0,0 +1,160 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QMAKEGLOBALS_H
#define QMAKEGLOBALS_H
#include "qmake_global.h"
#include "proitems.h"
#ifdef QT_BUILD_QMAKE
#  include <property.h>
#endif
#include <qhash.h>
#include <qstringlist.h>
#ifndef QT_BOOTSTRAPPED
# include <qprocess.h>
#endif
#ifdef PROEVALUATOR_THREAD_SAFE
# include <qmutex.h>
# include <qwaitcondition.h>
#endif
QT_BEGIN_NAMESPACE
class QMakeEvaluator;
class QMakeBaseKey
{
public:
    QMakeBaseKey(const QString &_root, bool _hostBuild);
    QString root;
    bool hostBuild;
};
uint qHash(const QMakeBaseKey &key);
bool operator==(const QMakeBaseKey &one, const QMakeBaseKey &two);
class QMakeBaseEnv
{
public:
    QMakeBaseEnv();
    ~QMakeBaseEnv();
#ifdef PROEVALUATOR_THREAD_SAFE
    QMutex mutex;
    QWaitCondition cond;
    bool inProgress;
    // The coupling of this flag to thread safety exists because for other
    // use cases failure is immediately fatal anyway.
    bool isOk;
#endif
    QMakeEvaluator *evaluator;
};
class QMAKE_EXPORT QMakeCmdLineParserState
{
public:
    QMakeCmdLineParserState(const QString &_pwd) : pwd(_pwd), after(false) {}
    QString pwd;
    QStringList precmds, preconfigs, postcmds, postconfigs;
    bool after;
};
class QMAKE_EXPORT QMakeGlobals
{
public:
    QMakeGlobals();
    ~QMakeGlobals();
    bool do_cache;
    QString dir_sep;
    QString dirlist_sep;
    QString cachefile;
#ifdef PROEVALUATOR_SETENV
    QProcessEnvironment environment;
#endif
    QString qmake_abslocation;
    QString qmakespec, xqmakespec;
    QString user_template, user_template_prefix;
    QString precmds, postcmds;
#ifdef PROEVALUATOR_DEBUG
    int debugLevel;
#endif
    enum ArgumentReturn { ArgumentUnknown, ArgumentMalformed, ArgumentsOk };
    ArgumentReturn addCommandLineArguments(QMakeCmdLineParserState &state,
                                           QStringList &args, int *pos);
    void commitCommandLineArguments(QMakeCmdLineParserState &state);
    void setCommandLineArguments(const QString &pwd, const QStringList &args);
    void useEnvironment();
    void setDirectories(const QString &input_dir, const QString &output_dir);
#ifdef QT_BUILD_QMAKE
    void setQMakeProperty(QMakeProperty *prop) { property = prop; }
    ProString propertyValue(const ProKey &name) const { return property->value(name); }
#else
#  ifdef PROEVALUATOR_INIT_PROPS
    bool initProperties();
#  else
    void setProperties(const QHash<QString, QString> &props);
#  endif
    ProString propertyValue(const ProKey &name) const { return properties.value(name); }
#endif
    QString expandEnvVars(const QString &str) const;
    QString shadowedPath(const QString &fileName) const;
private:
    QString getEnv(const QString &) const;
    QStringList getPathListEnv(const QString &var) const;
    QString cleanSpec(QMakeCmdLineParserState &state, const QString &spec);
    QString source_root, build_root;
#ifdef QT_BUILD_QMAKE
    QMakeProperty *property;
#else
    QHash<ProKey, ProString> properties;
#endif
#ifdef PROEVALUATOR_THREAD_SAFE
    QMutex mutex;
#endif
    QHash<QMakeBaseKey, QMakeBaseEnv *> baseEnvs;
    friend class QMakeEvaluator;
};
QT_END_NAMESPACE
#endif // QMAKEGLOBALS_H
QMakeFileReader/evaluator/qmakeparser.cpp
New file
@@ -0,0 +1,1212 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qmakeparser.h"
#include "ioutils.h"
using namespace QMakeInternal;
#include <qfile.h>
#ifdef PROPARSER_THREAD_SAFE
# include <qthreadpool.h>
#endif
QT_BEGIN_NAMESPACE
///////////////////////////////////////////////////////////////////////
//
// ProFileCache
//
///////////////////////////////////////////////////////////////////////
ProFileCache::~ProFileCache()
{
    foreach (const Entry &ent, parsed_files)
        if (ent.pro)
            ent.pro->deref();
}
void ProFileCache::discardFile(const QString &fileName)
{
#ifdef PROPARSER_THREAD_SAFE
    QMutexLocker lck(&mutex);
#endif
    QHash<QString, Entry>::Iterator it = parsed_files.find(fileName);
    if (it != parsed_files.end()) {
        if (it->pro)
            it->pro->deref();
        parsed_files.erase(it);
    }
}
void ProFileCache::discardFiles(const QString &prefix)
{
#ifdef PROPARSER_THREAD_SAFE
    QMutexLocker lck(&mutex);
#endif
    QHash<QString, Entry>::Iterator
            it = parsed_files.begin(),
            end = parsed_files.end();
    while (it != end)
        if (it.key().startsWith(prefix)) {
            if (it->pro)
                it->pro->deref();
            it = parsed_files.erase(it);
        } else {
            ++it;
        }
}
////////// Parser ///////////
#define fL1S(s) QString::fromLatin1(s)
namespace { // MSVC2010 doesn't seem to know the semantics of "static" ...
static struct {
    QString strelse;
    QString strfor;
    QString strdefineTest;
    QString strdefineReplace;
    QString stroption;
    QString strreturn;
    QString strnext;
    QString strbreak;
    QString strhost_build;
    QString strLINE;
    QString strFILE;
    QString strLITERAL_HASH;
    QString strLITERAL_DOLLAR;
    QString strLITERAL_WHITESPACE;
} statics;
}
void QMakeParser::initialize()
{
    if (!statics.strelse.isNull())
        return;
    statics.strelse = QLatin1String("else");
    statics.strfor = QLatin1String("for");
    statics.strdefineTest = QLatin1String("defineTest");
    statics.strdefineReplace = QLatin1String("defineReplace");
    statics.stroption = QLatin1String("option");
    statics.strreturn = QLatin1String("return");
    statics.strnext = QLatin1String("next");
    statics.strbreak = QLatin1String("break");
    statics.strhost_build = QLatin1String("host_build");
    statics.strLINE = QLatin1String("_LINE_");
    statics.strFILE = QLatin1String("_FILE_");
    statics.strLITERAL_HASH = QLatin1String("LITERAL_HASH");
    statics.strLITERAL_DOLLAR = QLatin1String("LITERAL_DOLLAR");
    statics.strLITERAL_WHITESPACE = QLatin1String("LITERAL_WHITESPACE");
}
QMakeParser::QMakeParser(ProFileCache *cache, QMakeParserHandler *handler)
    : m_cache(cache)
    , m_handler(handler)
{
    // So that single-threaded apps don't have to call initialize() for now.
    initialize();
}
ProFile *QMakeParser::parsedProFile(const QString &fileName, bool cache)
{
    ProFile *pro;
    if (cache && m_cache) {
        ProFileCache::Entry *ent;
#ifdef PROPARSER_THREAD_SAFE
        QMutexLocker locker(&m_cache->mutex);
#endif
        QHash<QString, ProFileCache::Entry>::Iterator it = m_cache->parsed_files.find(fileName);
        if (it != m_cache->parsed_files.end()) {
            ent = &*it;
#ifdef PROPARSER_THREAD_SAFE
            if (ent->locker && !ent->locker->done) {
                ++ent->locker->waiters;
                QThreadPool::globalInstance()->releaseThread();
                ent->locker->cond.wait(locker.mutex());
                QThreadPool::globalInstance()->reserveThread();
                if (!--ent->locker->waiters) {
                    delete ent->locker;
                    ent->locker = 0;
                }
            }
#endif
            if ((pro = ent->pro))
                pro->ref();
        } else {
            ent = &m_cache->parsed_files[fileName];
#ifdef PROPARSER_THREAD_SAFE
            ent->locker = new ProFileCache::Entry::Locker;
            locker.unlock();
#endif
            pro = new ProFile(fileName);
            if (!read(pro)) {
                delete pro;
                pro = 0;
            } else {
                pro->itemsRef()->squeeze();
                pro->ref();
            }
            ent->pro = pro;
#ifdef PROPARSER_THREAD_SAFE
            locker.relock();
            if (ent->locker->waiters) {
                ent->locker->done = true;
                ent->locker->cond.wakeAll();
            } else {
                delete ent->locker;
                ent->locker = 0;
            }
#endif
        }
    } else {
        pro = new ProFile(fileName);
        if (!read(pro)) {
            delete pro;
            pro = 0;
        }
    }
    return pro;
}
ProFile *QMakeParser::parsedProBlock(
        const QString &contents, const QString &name, int line, SubGrammar grammar)
{
    ProFile *pro = new ProFile(name);
    if (!read(pro, contents, line, grammar)) {
        delete pro;
        pro = 0;
    }
    return pro;
}
void QMakeParser::discardFileFromCache(const QString &fileName)
{
    if (m_cache)
        m_cache->discardFile(fileName);
}
bool QMakeParser::read(ProFile *pro)
{
    QFile file(pro->fileName());
    if (!file.open(QIODevice::ReadOnly)) {
        if (m_handler && IoUtils::exists(pro->fileName()))
            m_handler->message(QMakeParserHandler::ParserIoError,
                               fL1S("Cannot read %1: %2").arg(pro->fileName(), file.errorString()));
        return false;
    }
    QByteArray bcont = file.readAll();
    if (bcont.startsWith(QByteArray("\xef\xbb\xbf"))) {
        // UTF-8 BOM will cause subtle errors
        m_handler->message(QMakeParserHandler::ParserIoError,
                           fL1S("Unexpected UTF-8 BOM in %1").arg(pro->fileName()));
        return false;
    }
    QString content(QString::fromLocal8Bit(bcont));
    bcont.clear();
    file.close();
    return read(pro, content, 1, FullGrammar);
}
void QMakeParser::putTok(ushort *&tokPtr, ushort tok)
{
    *tokPtr++ = tok;
}
void QMakeParser::putBlockLen(ushort *&tokPtr, uint len)
{
    *tokPtr++ = (ushort)len;
    *tokPtr++ = (ushort)(len >> 16);
}
void QMakeParser::putBlock(ushort *&tokPtr, const ushort *buf, uint len)
{
    memcpy(tokPtr, buf, len * 2);
    tokPtr += len;
}
void QMakeParser::putHashStr(ushort *&pTokPtr, const ushort *buf, uint len)
{
    uint hash = ProString::hash((const QChar *)buf, len);
    ushort *tokPtr = pTokPtr;
    *tokPtr++ = (ushort)hash;
    *tokPtr++ = (ushort)(hash >> 16);
    *tokPtr++ = (ushort)len;
    memcpy(tokPtr, buf, len * 2);
    pTokPtr = tokPtr + len;
}
void QMakeParser::finalizeHashStr(ushort *buf, uint len)
{
    buf[-4] = TokHashLiteral;
    buf[-1] = len;
    uint hash = ProString::hash((const QChar *)buf, len);
    buf[-3] = (ushort)hash;
    buf[-2] = (ushort)(hash >> 16);
}
bool QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar grammar)
{
    m_proFile = pro;
    m_lineNo = line;
    // Final precompiled token stream buffer
    QString tokBuff;
    // Worst-case size calculations:
    // - line marker adds 1 (2-nl) to 1st token of each line
    // - empty assignment "A=":2 =>
    //   TokHashLiteral(1) + hash(2) + len(1) + "A"(1) + TokAssign(1) +
    //   TokValueTerminator(1) == 7 (8)
    // - non-empty assignment "A=B C":5 =>
    //   TokHashLiteral(1) + hash(2) + len(1) + "A"(1) + TokAssign(1) +
    //   TokLiteral(1) + len(1) + "B"(1) +
    //   TokLiteral(1) + len(1) + "C"(1) + TokValueTerminator(1) == 13 (14)
    // - variable expansion: "$$f":3 =>
    //   TokVariable(1) + hash(2) + len(1) + "f"(1) = 5
    // - function expansion: "$$f()":5 =>
    //   TokFuncName(1) + hash(2) + len(1) + "f"(1) + TokFuncTerminator(1) = 6
    // - scope: "X:":2 =>
    //   TokHashLiteral(1) + hash(2) + len(1) + "A"(1) + TokCondition(1) +
    //   TokBranch(1) + len(2) + ... + len(2) + ... == 10
    // - test: "X():":4 =>
    //   TokHashLiteral(1) + hash(2) + len(1) + "A"(1) + TokTestCall(1) + TokFuncTerminator(1) +
    //   TokBranch(1) + len(2) + ... + len(2) + ... == 11
    // - "for(A,B):":9 =>
    //   TokForLoop(1) + hash(2) + len(1) + "A"(1) +
    //   len(2) + TokLiteral(1) + len(1) + "B"(1) + TokValueTerminator(1) +
    //   len(2) + ... + TokTerminator(1) == 14 (15)
    tokBuff.reserve((in.size() + 1) * 5);
    ushort *tokPtr = (ushort *)tokBuff.constData(); // Current writing position
    // Expression precompiler buffer.
    QString xprBuff;
    xprBuff.reserve(tokBuff.capacity()); // Excessive, but simple
    ushort *buf = (ushort *)xprBuff.constData();
    // Parser state
    m_blockstack.clear();
    m_blockstack.resize(1);
    QStack<ParseCtx> xprStack;
    xprStack.reserve(10);
    // We rely on QStrings being null-terminated, so don't maintain a global end pointer.
    const ushort *cur = (const ushort *)in.unicode();
    m_canElse = false;
  freshLine:
    m_state = StNew;
    m_invert = false;
    m_operator = NoOperator;
    m_markLine = m_lineNo;
    m_inError = false;
    int parens = 0; // Braces in value context
    int argc = 0;
    int wordCount = 0; // Number of words in currently accumulated expression
    int lastIndent = 0; // Previous line's indentation, to detect accidental continuation abuse
    bool lineMarked = true; // For in-expression markers
    ushort needSep = TokNewStr; // Met unquoted whitespace
    ushort quote = 0;
    ushort term = 0;
    Context context;
    ushort *ptr;
    if (grammar == ValueGrammar) {
        context = CtxPureValue;
        ptr = tokPtr + 2;
    } else {
        context = CtxTest;
        ptr = buf + 4;
    }
    ushort *xprPtr = ptr;
#define FLUSH_LHS_LITERAL() \
    do { \
        if ((tlen = ptr - xprPtr)) { \
            finalizeHashStr(xprPtr, tlen); \
            if (needSep) { \
                wordCount++; \
                needSep = 0; \
            } \
        } else { \
            ptr -= 4; \
        } \
    } while (0)
#define FLUSH_RHS_LITERAL() \
    do { \
        if ((tlen = ptr - xprPtr)) { \
            xprPtr[-2] = TokLiteral | needSep; \
            xprPtr[-1] = tlen; \
            if (needSep) { \
                wordCount++; \
                needSep = 0; \
            } \
        } else { \
            ptr -= 2; \
        } \
    } while (0)
#define FLUSH_LITERAL() \
    do { \
        if (context == CtxTest) \
            FLUSH_LHS_LITERAL(); \
        else \
            FLUSH_RHS_LITERAL(); \
    } while (0)
#define FLUSH_VALUE_LIST() \
    do { \
        if (wordCount > 1) { \
            xprPtr = tokPtr; \
            if (*xprPtr == TokLine) \
                xprPtr += 2; \
            tokPtr[-1] = ((*xprPtr & TokMask) == TokLiteral) ? wordCount : 0; \
        } else { \
            tokPtr[-1] = 0; \
        } \
        tokPtr = ptr; \
        putTok(tokPtr, TokValueTerminator); \
    } while (0)
    const ushort *end; // End of this line
    const ushort *cptr; // Start of next line
    bool lineCont;
    int indent;
    if (context == CtxPureValue) {
        end = (const ushort *)in.unicode() + in.length();
        cptr = 0;
        lineCont = false;
        indent = 0; // just gcc being stupid
        goto nextChr;
    }
    forever {
        ushort c;
        // First, skip leading whitespace
        for (indent = 0; ; ++cur, ++indent) {
            c = *cur;
            if (c == '\n') {
                ++cur;
                goto flushLine;
            } else if (!c) {
                cur = 0;
                goto flushLine;
            } else if (c != ' ' && c != '\t' && c != '\r') {
                break;
            }
        }
        // Then strip comments. Yep - no escaping is possible.
        for (cptr = cur;; ++cptr) {
            c = *cptr;
            if (c == '#') {
                for (end = cptr; (c = *++cptr);) {
                    if (c == '\n') {
                        ++cptr;
                        break;
                    }
                }
                if (end == cur) { // Line with only a comment (sans whitespace)
                    if (m_markLine == m_lineNo)
                        m_markLine++;
                    // Qmake bizarreness: such lines do not affect line continuations
                    goto ignore;
                }
                break;
            }
            if (!c) {
                end = cptr;
                break;
            }
            if (c == '\n') {
                end = cptr++;
                break;
            }
        }
        // Then look for line continuations. Yep - no escaping here as well.
        forever {
            // We don't have to check for underrun here, as we already determined
            // that the line is non-empty.
            ushort ec = *(end - 1);
            if (ec == '\\') {
                --end;
                lineCont = true;
                break;
            }
            if (ec != ' ' && ec != '\t' && ec != '\r') {
                lineCont = false;
                break;
            }
            --end;
        }
            // Finally, do the tokenization
            ushort tok, rtok;
            int tlen;
          newWord:
            do {
                if (cur == end)
                    goto lineEnd;
                c = *cur++;
            } while (c == ' ' || c == '\t');
            forever {
                if (c == '$') {
                    if (*cur == '$') { // may be EOF, EOL, WS, '#' or '\\' if past end
                        cur++;
                        FLUSH_LITERAL();
                        if (!lineMarked) {
                            lineMarked = true;
                            *ptr++ = TokLine;
                            *ptr++ = (ushort)m_lineNo;
                        }
                        term = 0;
                        tok = TokVariable;
                        c = *cur;
                        if (c == '[') {
                            ptr += 4;
                            tok = TokProperty;
                            term = ']';
                            c = *++cur;
                        } else if (c == '{') {
                            ptr += 4;
                            term = '}';
                            c = *++cur;
                        } else if (c == '(') {
                            ptr += 2;
                            tok = TokEnvVar;
                            term = ')';
                            c = *++cur;
                        } else {
                            ptr += 4;
                        }
                        xprPtr = ptr;
                        rtok = tok;
                        while ((c & 0xFF00) || c == '.' || c == '_' ||
                               (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
                               (c >= '0' && c <= '9') || (c == '/' && term)) {
                            *ptr++ = c;
                            if (++cur == end) {
                                c = 0;
                                goto notfunc;
                            }
                            c = *cur;
                        }
                        if (tok == TokVariable && c == '(')
                            tok = TokFuncName;
                      notfunc:
                        if (ptr == xprPtr)
                            languageWarning(fL1S("Missing name in expansion"));
                        if (quote)
                            tok |= TokQuoted;
                        if (needSep) {
                            tok |= needSep;
                            wordCount++;
                        }
                        tlen = ptr - xprPtr;
                        if (rtok != TokVariable
                            || !resolveVariable(xprPtr, tlen, needSep, &ptr,
                                                &buf, &xprBuff, &tokPtr, &tokBuff, cur, in)) {
                            if (rtok == TokVariable || rtok == TokProperty) {
                                xprPtr[-4] = tok;
                                uint hash = ProString::hash((const QChar *)xprPtr, tlen);
                                xprPtr[-3] = (ushort)hash;
                                xprPtr[-2] = (ushort)(hash >> 16);
                                xprPtr[-1] = tlen;
                            } else {
                                xprPtr[-2] = tok;
                                xprPtr[-1] = tlen;
                            }
                        }
                        if ((tok & TokMask) == TokFuncName) {
                            cur++;
                          funcCall:
                            {
                                xprStack.resize(xprStack.size() + 1);
                                ParseCtx &top = xprStack.top();
                                top.parens = parens;
                                top.quote = quote;
                                top.terminator = term;
                                top.context = context;
                                top.argc = argc;
                                top.wordCount = wordCount;
                            }
                            parens = 0;
                            quote = 0;
                            term = 0;
                            argc = 1;
                            context = CtxArgs;
                          nextToken:
                            wordCount = 0;
                          nextWord:
                            ptr += (context == CtxTest) ? 4 : 2;
                            xprPtr = ptr;
                            needSep = TokNewStr;
                            goto newWord;
                        }
                        if (term) {
                          checkTerm:
                            if (c != term) {
                                parseError(fL1S("Missing %1 terminator [found %2]")
                                    .arg(QChar(term))
                                    .arg(c ? QString(c) : QString::fromLatin1("end-of-line")));
                                pro->setOk(false);
                                m_inError = true;
                                // Just parse on, as if there was a terminator ...
                            } else {
                                cur++;
                            }
                        }
                      joinToken:
                        ptr += (context == CtxTest) ? 4 : 2;
                        xprPtr = ptr;
                        needSep = 0;
                        goto nextChr;
                    }
                } else if (c == '\\') {
                    static const char symbols[] = "[]{}()$\\'\"";
                    ushort c2;
                    if (cur != end && !((c2 = *cur) & 0xff00) && strchr(symbols, c2)) {
                        c = c2;
                        cur++;
                    } else {
                        deprecationWarning(fL1S("Unescaped backslashes are deprecated"));
                    }
                } else if (quote) {
                    if (c == quote) {
                        quote = 0;
                        goto nextChr;
                    } else if (c == '!' && ptr == xprPtr && context == CtxTest) {
                        m_invert ^= true;
                        goto nextChr;
                    }
                } else if (c == '\'' || c == '"') {
                    quote = c;
                    goto nextChr;
                } else if (context == CtxArgs) {
                    // Function arg context
                    if (c == ' ' || c == '\t') {
                        FLUSH_RHS_LITERAL();
                        goto nextWord;
                    } else if (c == '(') {
                        ++parens;
                    } else if (c == ')') {
                        if (--parens < 0) {
                            FLUSH_RHS_LITERAL();
                            *ptr++ = TokFuncTerminator;
                            int theargc = argc;
                            {
                                ParseCtx &top = xprStack.top();
                                parens = top.parens;
                                quote = top.quote;
                                term = top.terminator;
                                context = top.context;
                                argc = top.argc;
                                wordCount = top.wordCount;
                                xprStack.resize(xprStack.size() - 1);
                            }
                            if (term == ':') {
                                finalizeCall(tokPtr, buf, ptr, theargc);
                                goto nextItem;
                            } else if (term == '}') {
                                c = (cur == end) ? 0 : *cur;
                                goto checkTerm;
                            } else {
                                Q_ASSERT(!term);
                                goto joinToken;
                            }
                        }
                    } else if (!parens && c == ',') {
                        FLUSH_RHS_LITERAL();
                        *ptr++ = TokArgSeparator;
                        argc++;
                        goto nextToken;
                    }
                } else if (context == CtxTest) {
                    // Test or LHS context
                    if (c == ' ' || c == '\t') {
                        FLUSH_LHS_LITERAL();
                        goto nextWord;
                    } else if (c == '(') {
                        FLUSH_LHS_LITERAL();
                        if (wordCount != 1) {
                            if (wordCount)
                                parseError(fL1S("Extra characters after test expression."));
                            else
                                parseError(fL1S("Opening parenthesis without prior test name."));
                            pro->setOk(false);
                            ptr = buf; // Put empty function name
                        }
                        *ptr++ = TokTestCall;
                        term = ':';
                        goto funcCall;
                    } else if (c == '!' && ptr == xprPtr) {
                        m_invert ^= true;
                        goto nextChr;
                    } else if (c == ':') {
                        FLUSH_LHS_LITERAL();
                        finalizeCond(tokPtr, buf, ptr, wordCount);
                        if (m_state == StNew)
                            parseError(fL1S("And operator without prior condition."));
                        else
                            m_operator = AndOperator;
                      nextItem:
                        ptr = buf;
                        goto nextToken;
                    } else if (c == '|') {
                        FLUSH_LHS_LITERAL();
                        finalizeCond(tokPtr, buf, ptr, wordCount);
                        if (m_state != StCond)
                            parseError(fL1S("Or operator without prior condition."));
                        else
                            m_operator = OrOperator;
                        goto nextItem;
                    } else if (c == '{') {
                        FLUSH_LHS_LITERAL();
                        finalizeCond(tokPtr, buf, ptr, wordCount);
                        flushCond(tokPtr);
                        ++m_blockstack.top().braceLevel;
                        if (grammar == TestGrammar) {
                            parseError(fL1S("Opening scope not permitted in this context."));
                            pro->setOk(false);
                        }
                        goto nextItem;
                    } else if (c == '}') {
                        FLUSH_LHS_LITERAL();
                        finalizeCond(tokPtr, buf, ptr, wordCount);
                        flushScopes(tokPtr);
                      closeScope:
                        if (!m_blockstack.top().braceLevel) {
                            parseError(fL1S("Excess closing brace."));
                        } else if (!--m_blockstack.top().braceLevel
                                   && m_blockstack.count() != 1) {
                            leaveScope(tokPtr);
                            m_state = StNew;
                            m_canElse = false;
                            m_markLine = m_lineNo;
                        }
                        goto nextItem;
                    } else if (c == '+') {
                        tok = TokAppend;
                        goto do2Op;
                    } else if (c == '-') {
                        tok = TokRemove;
                        goto do2Op;
                    } else if (c == '*') {
                        tok = TokAppendUnique;
                        goto do2Op;
                    } else if (c == '~') {
                        tok = TokReplace;
                      do2Op:
                        if (*cur == '=') {
                            cur++;
                            goto doOp;
                        }
                    } else if (c == '=') {
                        tok = TokAssign;
                      doOp:
                        FLUSH_LHS_LITERAL();
                        flushCond(tokPtr);
                        putLineMarker(tokPtr);
                        if (grammar == TestGrammar) {
                            parseError(fL1S("Assignment not permitted in this context."));
                            pro->setOk(false);
                        } else if (wordCount != 1) {
                            parseError(fL1S("Assignment needs exactly one word on the left hand side."));
                            pro->setOk(false);
                            // Put empty variable name.
                        } else {
                            putBlock(tokPtr, buf, ptr - buf);
                        }
                        putTok(tokPtr, tok);
                        context = CtxValue;
                        ptr = ++tokPtr;
                        goto nextToken;
                    }
                } else if (context == CtxValue) {
                    if (c == ' ' || c == '\t') {
                        FLUSH_RHS_LITERAL();
                        goto nextWord;
                    } else if (c == '{') {
                        ++parens;
                    } else if (c == '}') {
                        if (!parens) {
                            FLUSH_RHS_LITERAL();
                            FLUSH_VALUE_LIST();
                            context = CtxTest;
                            goto closeScope;
                        }
                        --parens;
                    } else if (c == '=') {
                        if (indent < lastIndent)
                            languageWarning(fL1S("Possible accidental line continuation"));
                    }
                }
                *ptr++ = c;
              nextChr:
                if (cur == end)
                    goto lineEnd;
                c = *cur++;
            }
          lineEnd:
            if (lineCont) {
                if (quote) {
                    *ptr++ = ' ';
                } else {
                    FLUSH_LITERAL();
                    needSep = TokNewStr;
                    ptr += (context == CtxTest) ? 4 : 2;
                    xprPtr = ptr;
                }
            } else {
                cur = cptr;
              flushLine:
                FLUSH_LITERAL();
                if (quote) {
                    parseError(fL1S("Missing closing %1 quote").arg(QChar(quote)));
                    if (!xprStack.isEmpty()) {
                        context = xprStack.at(0).context;
                        xprStack.clear();
                    }
                    goto flErr;
                } else if (!xprStack.isEmpty()) {
                    parseError(fL1S("Missing closing parenthesis in function call"));
                    context = xprStack.at(0).context;
                    xprStack.clear();
                  flErr:
                    pro->setOk(false);
                    if (context == CtxValue) {
                        tokPtr[-1] = 0; // sizehint
                        putTok(tokPtr, TokValueTerminator);
                    } else if (context == CtxPureValue) {
                        putTok(tokPtr, TokValueTerminator);
                    } else {
                        bogusTest(tokPtr);
                    }
                } else if (context == CtxValue) {
                    FLUSH_VALUE_LIST();
                    if (parens)
                        languageWarning(fL1S("Possible braces mismatch"));
                } else if (context == CtxPureValue) {
                    tokPtr = ptr;
                    putTok(tokPtr, TokValueTerminator);
                } else {
                    finalizeCond(tokPtr, buf, ptr, wordCount);
                }
                if (!cur)
                    break;
                ++m_lineNo;
                goto freshLine;
            }
        lastIndent = indent;
        lineMarked = false;
      ignore:
        cur = cptr;
        ++m_lineNo;
    }
    flushScopes(tokPtr);
    if (m_blockstack.size() > 1) {
        parseError(fL1S("Missing closing brace(s)."));
        pro->setOk(false);
    }
    while (m_blockstack.size())
        leaveScope(tokPtr);
    tokBuff.resize(tokPtr - (ushort *)tokBuff.constData()); // Reserved capacity stays
    *pro->itemsRef() = tokBuff;
    return true;
#undef FLUSH_VALUE_LIST
#undef FLUSH_LITERAL
#undef FLUSH_LHS_LITERAL
#undef FLUSH_RHS_LITERAL
}
void QMakeParser::putLineMarker(ushort *&tokPtr)
{
    if (m_markLine) {
        *tokPtr++ = TokLine;
        *tokPtr++ = (ushort)m_markLine;
        m_markLine = 0;
    }
}
void QMakeParser::enterScope(ushort *&tokPtr, bool special, ScopeState state)
{
    uchar nest = m_blockstack.top().nest;
    m_blockstack.resize(m_blockstack.size() + 1);
    m_blockstack.top().special = special;
    m_blockstack.top().start = tokPtr;
    m_blockstack.top().nest = nest;
    tokPtr += 2;
    m_state = state;
    m_canElse = false;
    if (special)
        m_markLine = m_lineNo;
}
void QMakeParser::leaveScope(ushort *&tokPtr)
{
    if (m_blockstack.top().inBranch) {
        // Put empty else block
        putBlockLen(tokPtr, 0);
    }
    if (ushort *start = m_blockstack.top().start) {
        putTok(tokPtr, TokTerminator);
        uint len = tokPtr - start - 2;
        start[0] = (ushort)len;
        start[1] = (ushort)(len >> 16);
    }
    m_blockstack.resize(m_blockstack.size() - 1);
}
// If we are on a fresh line, close all open one-line scopes.
void QMakeParser::flushScopes(ushort *&tokPtr)
{
    if (m_state == StNew) {
        while (!m_blockstack.top().braceLevel && m_blockstack.size() > 1)
            leaveScope(tokPtr);
        if (m_blockstack.top().inBranch) {
            m_blockstack.top().inBranch = false;
            // Put empty else block
            putBlockLen(tokPtr, 0);
        }
        m_canElse = false;
    }
}
// If there is a pending conditional, enter a new scope, otherwise flush scopes.
void QMakeParser::flushCond(ushort *&tokPtr)
{
    if (m_state == StCond) {
        putTok(tokPtr, TokBranch);
        m_blockstack.top().inBranch = true;
        enterScope(tokPtr, false, StNew);
    } else {
        flushScopes(tokPtr);
    }
}
void QMakeParser::finalizeTest(ushort *&tokPtr)
{
    flushScopes(tokPtr);
    putLineMarker(tokPtr);
    if (m_operator != NoOperator) {
        putTok(tokPtr, (m_operator == AndOperator) ? TokAnd : TokOr);
        m_operator = NoOperator;
    }
    if (m_invert) {
        putTok(tokPtr, TokNot);
        m_invert = false;
    }
    m_state = StCond;
    m_canElse = true;
}
void QMakeParser::bogusTest(ushort *&tokPtr)
{
    flushScopes(tokPtr);
    m_operator = NoOperator;
    m_invert = false;
    m_state = StCond;
    m_canElse = true;
    m_proFile->setOk(false);
}
void QMakeParser::finalizeCond(ushort *&tokPtr, ushort *uc, ushort *ptr, int wordCount)
{
    if (wordCount != 1) {
        if (wordCount) {
            parseError(fL1S("Extra characters after test expression."));
            bogusTest(tokPtr);
        }
        return;
    }
    // Check for magic tokens
    if (*uc == TokHashLiteral) {
        uint nlen = uc[3];
        ushort *uce = uc + 4 + nlen;
        if (uce == ptr) {
            m_tmp.setRawData((QChar *)uc + 4, nlen);
            if (!m_tmp.compare(statics.strelse, Qt::CaseInsensitive)) {
                if (m_invert || m_operator != NoOperator) {
                    parseError(fL1S("Unexpected operator in front of else."));
                    return;
                }
                BlockScope &top = m_blockstack.top();
                if (m_canElse && (!top.special || top.braceLevel)) {
                    // A list of tests (the last one likely with side effects),
                    // but no assignment, scope, etc.
                    putTok(tokPtr, TokBranch);
                    // Put empty then block
                    putBlockLen(tokPtr, 0);
                    enterScope(tokPtr, false, StCtrl);
                    return;
                }
                forever {
                    BlockScope &top = m_blockstack.top();
                    if (top.inBranch && (!top.special || top.braceLevel)) {
                        top.inBranch = false;
                        enterScope(tokPtr, false, StCtrl);
                        return;
                    }
                    if (top.braceLevel || m_blockstack.size() == 1)
                        break;
                    leaveScope(tokPtr);
                }
                parseError(fL1S("Unexpected 'else'."));
                return;
            }
        }
    }
    finalizeTest(tokPtr);
    putBlock(tokPtr, uc, ptr - uc);
    putTok(tokPtr, TokCondition);
}
void QMakeParser::finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int argc)
{
    // Check for magic tokens
    if (*uc == TokHashLiteral) {
        uint nlen = uc[3];
        ushort *uce = uc + 4 + nlen;
        if (*uce == TokTestCall) {
            uce++;
            m_tmp.setRawData((QChar *)uc + 4, nlen);
            const QString *defName;
            ushort defType;
            uchar nest;
            if (m_tmp == statics.strfor) {
                if (m_invert || m_operator == OrOperator) {
                    // '|' could actually work reasonably, but qmake does nonsense here.
                    parseError(fL1S("Unexpected operator in front of for()."));
                    bogusTest(tokPtr);
                    return;
                }
                flushCond(tokPtr);
                putLineMarker(tokPtr);
                if (*uce == (TokLiteral|TokNewStr)) {
                    nlen = uce[1];
                    uc = uce + 2 + nlen;
                    if (*uc == TokFuncTerminator) {
                        // for(literal) (only "ever" would be legal if qmake was sane)
                        putTok(tokPtr, TokForLoop);
                        putHashStr(tokPtr, (ushort *)0, (uint)0);
                        putBlockLen(tokPtr, 1 + 3 + nlen + 1);
                        putTok(tokPtr, TokHashLiteral);
                        putHashStr(tokPtr, uce + 2, nlen);
                      didFor:
                        putTok(tokPtr, TokValueTerminator);
                        enterScope(tokPtr, true, StCtrl);
                        m_blockstack.top().nest |= NestLoop;
                        return;
                    } else if (*uc == TokArgSeparator && argc == 2) {
                        // for(var, something)
                        uc++;
                        putTok(tokPtr, TokForLoop);
                        putHashStr(tokPtr, uce + 2, nlen);
                      doFor:
                        nlen = ptr - uc;
                        putBlockLen(tokPtr, nlen + 1);
                        putBlock(tokPtr, uc, nlen);
                        goto didFor;
                    }
                } else if (argc == 1) {
                    // for(non-literal) (this wouldn't be here if qmake was sane)
                    putTok(tokPtr, TokForLoop);
                    putHashStr(tokPtr, (ushort *)0, (uint)0);
                    uc = uce;
                    goto doFor;
                }
                parseError(fL1S("Syntax is for(var, list), for(var, forever) or for(ever)."));
                return;
            } else if (m_tmp == statics.strdefineReplace) {
                defName = &statics.strdefineReplace;
                defType = TokReplaceDef;
                goto deffunc;
            } else if (m_tmp == statics.strdefineTest) {
                defName = &statics.strdefineTest;
                defType = TokTestDef;
              deffunc:
                if (m_invert) {
                    parseError(fL1S("Unexpected operator in front of function definition."));
                    bogusTest(tokPtr);
                    return;
                }
                flushScopes(tokPtr);
                putLineMarker(tokPtr);
                if (*uce == (TokLiteral|TokNewStr)) {
                    uint nlen = uce[1];
                    if (uce[nlen + 2] == TokFuncTerminator) {
                        if (m_operator != NoOperator) {
                            putTok(tokPtr, (m_operator == AndOperator) ? TokAnd : TokOr);
                            m_operator = NoOperator;
                        }
                        putTok(tokPtr, defType);
                        putHashStr(tokPtr, uce + 2, nlen);
                        enterScope(tokPtr, true, StCtrl);
                        m_blockstack.top().nest = NestFunction;
                        return;
                    }
                }
                parseError(fL1S("%1(function) requires one literal argument.").arg(*defName));
                return;
            } else if (m_tmp == statics.strreturn) {
                if (argc > 1) {
                    parseError(fL1S("return() requires zero or one argument."));
                    bogusTest(tokPtr);
                    return;
                }
                defType = TokReturn;
                nest = NestFunction;
                goto ctrlstm2;
            } else if (m_tmp == statics.strnext) {
                defType = TokNext;
                goto ctrlstm;
            } else if (m_tmp == statics.strbreak) {
                defType = TokBreak;
              ctrlstm:
                if (*uce != TokFuncTerminator) {
                    parseError(fL1S("%1() requires zero arguments.").arg(m_tmp));
                    bogusTest(tokPtr);
                    return;
                }
                nest = NestLoop;
              ctrlstm2:
                if (m_invert) {
                    parseError(fL1S("Unexpected NOT operator in front of %1().").arg(m_tmp));
                    bogusTest(tokPtr);
                    return;
                }
                if (!(m_blockstack.top().nest & nest)) {
                    parseError(fL1S("Unexpected %1().").arg(m_tmp));
                    bogusTest(tokPtr);
                    return;
                }
                finalizeTest(tokPtr);
                putBlock(tokPtr, uce, ptr - uce - 1); // Only for TokReturn
                putTok(tokPtr, defType);
                return;
            } else if (m_tmp == statics.stroption) {
                if (m_state != StNew || m_blockstack.top().braceLevel || m_blockstack.size() > 1
                        || m_invert || m_operator != NoOperator) {
                    parseError(fL1S("option() must appear outside any control structures."));
                    bogusTest(tokPtr);
                    return;
                }
                if (*uce == (TokLiteral|TokNewStr)) {
                    uint nlen = uce[1];
                    if (uce[nlen + 2] == TokFuncTerminator) {
                        m_tmp.setRawData((QChar *)uce + 2, nlen);
                        if (m_tmp == statics.strhost_build) {
                            m_proFile->setHostBuild(true);
                        } else {
                            parseError(fL1S("Unknown option() %1.").arg(m_tmp));
                        }
                        return;
                    }
                }
                parseError(fL1S("option() requires one literal argument."));
                return;
            }
        }
    }
    finalizeTest(tokPtr);
    putBlock(tokPtr, uc, ptr - uc);
}
bool QMakeParser::resolveVariable(ushort *xprPtr, int tlen, int needSep, ushort **ptr,
                                  ushort **buf, QString *xprBuff,
                                  ushort **tokPtr, QString *tokBuff,
                                  const ushort *cur, const QString &in)
{
    QString out;
    m_tmp.setRawData((const QChar *)xprPtr, tlen);
    if (m_tmp == statics.strLINE) {
        out.setNum(m_lineNo);
    } else if (m_tmp == statics.strFILE) {
        out = m_proFile->fileName();
        // The string is typically longer than the variable reference, so we need
        // to ensure that there is enough space in the output buffer - as unlikely
        // as an overflow is to actually happen in practice.
        int need = (in.length() - (cur - (const ushort *)in.constData()) + 2) * 5 + out.length();
        int tused = *tokPtr - (ushort *)tokBuff->constData();
        int xused;
        int total;
        bool ptrFinal = xprPtr >= (ushort *)tokBuff->constData()
                && xprPtr < (ushort *)tokBuff->constData() + tokBuff->capacity();
        if (ptrFinal) {
            xused = xprPtr - (ushort *)tokBuff->constData();
            total = xused + need;
        } else {
            xused = xprPtr - *buf;
            total = tused + xused + need;
        }
        if (tokBuff->capacity() < total) {
            tokBuff->reserve(total);
            *tokPtr = (ushort *)tokBuff->constData() + tused;
            xprBuff->reserve(total);
            *buf = (ushort *)xprBuff->constData();
            xprPtr = (ptrFinal ? (ushort *)tokBuff->constData() : *buf) + xused;
        }
    } else if (m_tmp == statics.strLITERAL_HASH) {
        out = QLatin1String("#");
    } else if (m_tmp == statics.strLITERAL_DOLLAR) {
        out = QLatin1String("$");
    } else if (m_tmp == statics.strLITERAL_WHITESPACE) {
        out = QLatin1String("\t");
    } else {
        return false;
    }
    xprPtr -= 2; // Was set up for variable reference
    xprPtr[-2] = TokLiteral | needSep;
    xprPtr[-1] = out.length();
    memcpy(xprPtr, out.constData(), out.length() * 2);
    *ptr = xprPtr + out.length();
    return true;
}
void QMakeParser::message(int type, const QString &msg) const
{
    if (!m_inError && m_handler)
        m_handler->message(type, msg, m_proFile->fileName(), m_lineNo);
}
QT_END_NAMESPACE
QMakeFileReader/evaluator/qmakeparser.h
New file
@@ -0,0 +1,210 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QMAKEPARSER_H
#define QMAKEPARSER_H
#include "qmake_global.h"
#include "proitems.h"
#include <qhash.h>
#include <qstack.h>
#ifdef PROPARSER_THREAD_SAFE
# include <qmutex.h>
# include <qwaitcondition.h>
#endif
QT_BEGIN_NAMESPACE
class QMAKE_EXPORT QMakeParserHandler
{
public:
    enum {
        CategoryMask = 0xf00,
        WarningMessage = 0x000,
        ErrorMessage = 0x100,
        SourceMask = 0xf0,
        SourceParser = 0,
        CodeMask = 0xf,
        WarnLanguage = 0,
        WarnDeprecated,
        ParserWarnLanguage = SourceParser | WarningMessage | WarnLanguage,
        ParserWarnDeprecated = SourceParser | WarningMessage | WarnDeprecated,
        ParserIoError = ErrorMessage | SourceParser,
        ParserError
    };
    virtual void message(int type, const QString &msg,
                         const QString &fileName = QString(), int lineNo = 0) = 0;
};
class ProFileCache;
class QMAKE_EXPORT QMakeParser
{
public:
    // Call this from a concurrency-free context
    static void initialize();
    QMakeParser(ProFileCache *cache, QMakeParserHandler *handler);
    enum SubGrammar { FullGrammar, TestGrammar, ValueGrammar };
    // fileName is expected to be absolute and cleanPath()ed.
    ProFile *parsedProFile(const QString &fileName, bool cache = false);
    ProFile *parsedProBlock(const QString &contents, const QString &name, int line = 0,
                            SubGrammar grammar = FullGrammar);
    void discardFileFromCache(const QString &fileName);
private:
    enum ScopeNesting {
        NestNone = 0,
        NestLoop = 1,
        NestFunction = 2
    };
    struct BlockScope {
        BlockScope() : start(0), braceLevel(0), special(false), inBranch(false), nest(NestNone) {}
        BlockScope(const BlockScope &other) { *this = other; }
        ushort *start; // Where this block started; store length here
        int braceLevel; // Nesting of braces in scope
        bool special; // Single-line conditionals inside loops, etc. cannot have else branches
        bool inBranch; // The 'else' branch of the previous TokBranch is still open
        uchar nest; // Into what control structures we are nested
    };
    enum ScopeState {
        StNew,  // Fresh scope
        StCtrl, // Control statement (for or else) met on current line
        StCond  // Conditionals met on current line
    };
    enum Context { CtxTest, CtxValue, CtxPureValue, CtxArgs };
    struct ParseCtx {
        int parens; // Nesting of non-functional parentheses
        int argc; // Number of arguments in current function call
        int wordCount; // Number of words in current expression
        Context context;
        ushort quote; // Enclosing quote type
        ushort terminator; // '}' if replace function call is braced, ':' if test function
    };
    bool read(ProFile *pro);
    bool read(ProFile *pro, const QString &content, int line, SubGrammar grammar);
    ALWAYS_INLINE void putTok(ushort *&tokPtr, ushort tok);
    ALWAYS_INLINE void putBlockLen(ushort *&tokPtr, uint len);
    ALWAYS_INLINE void putBlock(ushort *&tokPtr, const ushort *buf, uint len);
    void putHashStr(ushort *&pTokPtr, const ushort *buf, uint len);
    void finalizeHashStr(ushort *buf, uint len);
    void putLineMarker(ushort *&tokPtr);
    ALWAYS_INLINE bool resolveVariable(ushort *xprPtr, int tlen, int needSep, ushort **ptr,
                                       ushort **buf, QString *xprBuff,
                                       ushort **tokPtr, QString *tokBuff,
                                       const ushort *cur, const QString &in);
    void finalizeCond(ushort *&tokPtr, ushort *uc, ushort *ptr, int wordCount);
    void finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int argc);
    void finalizeTest(ushort *&tokPtr);
    void bogusTest(ushort *&tokPtr);
    void enterScope(ushort *&tokPtr, bool special, ScopeState state);
    void leaveScope(ushort *&tokPtr);
    void flushCond(ushort *&tokPtr);
    void flushScopes(ushort *&tokPtr);
    void message(int type, const QString &msg) const;
    void parseError(const QString &msg) const
            { message(QMakeParserHandler::ParserError, msg); }
    void languageWarning(const QString &msg) const
            { message(QMakeParserHandler::ParserWarnLanguage, msg); }
    void deprecationWarning(const QString &msg) const
            { message(QMakeParserHandler::ParserWarnDeprecated, msg); }
    // Current location
    ProFile *m_proFile;
    int m_lineNo;
    QStack<BlockScope> m_blockstack;
    ScopeState m_state;
    int m_markLine; // Put marker for this line
    bool m_inError; // Current line had a parsing error; suppress followup error messages
    bool m_canElse; // Conditionals met on previous line, but no scope was opened
    bool m_invert; // Pending conditional is negated
    enum { NoOperator, AndOperator, OrOperator } m_operator; // Pending conditional is ORed/ANDed
    QString m_tmp; // Temporary for efficient toQString
    ProFileCache *m_cache;
    QMakeParserHandler *m_handler;
    // This doesn't help gcc 3.3 ...
    template<typename T> friend class QTypeInfo;
    friend class ProFileCache;
};
class QMAKE_EXPORT ProFileCache
{
public:
    ProFileCache() {}
    ~ProFileCache();
    void discardFile(const QString &fileName);
    void discardFiles(const QString &prefix);
private:
    struct Entry {
        ProFile *pro;
#ifdef PROPARSER_THREAD_SAFE
        struct Locker {
            Locker() : waiters(0), done(false) {}
            QWaitCondition cond;
            int waiters;
            bool done;
        };
        Locker *locker;
#endif
    };
    QHash<QString, Entry> parsed_files;
#ifdef PROPARSER_THREAD_SAFE
    QMutex mutex;
#endif
    friend class QMakeParser;
};
#if !defined(__GNUC__) || __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 3)
Q_DECLARE_TYPEINFO(QMakeParser::BlockScope, Q_MOVABLE_TYPE);
Q_DECLARE_TYPEINFO(QMakeParser::Context, Q_PRIMITIVE_TYPE);
#endif
QT_END_NAMESPACE
#endif // PROFILEPARSER_H
QMakeFileReader/main.cpp
New file
@@ -0,0 +1,87 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qmakedataprovider.h"
#include <QCoreApplication>
#include <QStringList>
#include <QFileInfo>
#include <QXmlStreamWriter>
QString toString(bool b)
{
    return b ? QStringLiteral("true") : QStringLiteral("false");
}
int main(int argc, char *argv[])
{
    if (argc < 3) {
        fputs("Usage: qmakefilereader <QtDir> <filePath>\n", stderr);
        return -1;
    }
    QCoreApplication app(argc, argv);
    const QStringList args = app.arguments();
    const QString qtDir = args.at(1);
    const QString filePath = QFileInfo(args.at(2)).absoluteFilePath();
    QMakeDataProvider dataProvider;
    dataProvider.setQtDir(qtDir);
    if (!dataProvider.readFile(filePath))
        return 1;
    QFile fout;
    if (!fout.open(stdout, QFile::WriteOnly))
        return 2;
    QXmlStreamWriter stream(&fout);
    stream.setAutoFormatting(true);
    stream.writeStartDocument();
    stream.writeStartElement("content");
    stream.writeAttribute("valid", toString(dataProvider.isValid()));
    stream.writeAttribute("flat", toString(dataProvider.isFlat()));
    stream.writeStartElement("SOURCES");
    foreach (const QString &str, dataProvider.getSourceFiles())
         stream.writeTextElement("file", str);
    stream.writeEndElement();
    stream.writeStartElement("HEADERS");
    foreach (const QString &str, dataProvider.getHeaderFiles())
         stream.writeTextElement("file", str);
    stream.writeEndElement();
    stream.writeStartElement("RESOURCES");
    foreach (const QString &str, dataProvider.getResourceFiles())
         stream.writeTextElement("file", str);
    stream.writeEndElement();
    stream.writeStartElement("FORMS");
    foreach (const QString &str, dataProvider.getFormFiles())
         stream.writeTextElement("file", str);
    stream.writeEndElement();
    stream.writeEndElement();   // content
    stream.writeEndDocument();
    return 0;
}
QMakeFileReader/qmakedataprovider.cpp
New file
@@ -0,0 +1,142 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qmakedataprovider.h"
#include "evalhandler.h"
#include <qmakeevaluator.h>
#include <qmakeglobals.h>
#include <QtCore/QFileInfo>
#include <QtCore/QList>
#include <QtCore/QPair>
class QMakeDataProviderPrivate
{
public:
    QStringList m_headerFiles;
    QStringList m_sourceFiles;
    QStringList m_resourceFiles;
    QStringList m_formFiles;
    typedef QPair<QStringList *, ProKey> Mapping;
    QList<Mapping> m_variableMappings;
    bool m_valid;
    bool m_flat;
    QString m_qtdir;
    QMakeDataProviderPrivate()
    {
        m_variableMappings
                << qMakePair(&m_headerFiles, ProKey("HEADERS"))
                << qMakePair(&m_sourceFiles, ProKey("SOURCES"))
                << qMakePair(&m_resourceFiles, ProKey("RESOURCES"))
                << qMakePair(&m_formFiles, ProKey("FORMS"));
    }
    bool readFile(const QString &fileName)
    {
        QFileInfo fi(fileName);
        if (fi.isRelative())
            qWarning("qmakewrapper: expecting an absolute filename.");
        m_headerFiles.clear();
        m_sourceFiles.clear();
        m_resourceFiles.clear();
        m_formFiles.clear();
        m_valid = false;
        m_flat = true;
        QMakeGlobals globals;
        ProFileCache proFileCache;
        EvalHandler handler;
        QMakeParser parser(&proFileCache, &handler);
        QMakeEvaluator evaluator(&globals, &parser, &handler);
        if (evaluator.evaluateFile(fileName, QMakeHandler::EvalProjectFile,
                                   QMakeEvaluator::LoadProOnly) != QMakeEvaluator::ReturnTrue)
        {
            qWarning("qmakewrapper: failed to parse %s", qPrintable(fileName));
            return false;
        }
        m_valid = true;
        m_flat = evaluator.isActiveConfig(QStringLiteral("flat"));
        foreach (const Mapping &mapping, m_variableMappings)
            *mapping.first = evaluator.values(mapping.second).toQStringList();
        return true;
    }
};
QMakeDataProvider::QMakeDataProvider()
    : d(new QMakeDataProviderPrivate())
{
}
QMakeDataProvider::~QMakeDataProvider()
{
    delete d;
}
bool QMakeDataProvider::readFile(const QString &fileName)
{
    return d->readFile(fileName);
}
void QMakeDataProvider::setQtDir(const QString &qtdir)
{
    d->m_qtdir = qtdir;
}
QStringList QMakeDataProvider::getFormFiles() const
{
    return d->m_formFiles;
}
QStringList QMakeDataProvider::getHeaderFiles() const
{
    return d->m_headerFiles;
}
QStringList QMakeDataProvider::getResourceFiles() const
{
    return d->m_resourceFiles;
}
QStringList QMakeDataProvider::getSourceFiles() const
{
    return d->m_sourceFiles;
}
bool QMakeDataProvider::isFlat() const
{
    return d->m_flat;
}
bool QMakeDataProvider::isValid() const
{
    return d->m_valid;
}
QMakeFileReader/qmakedataprovider.h
New file
@@ -0,0 +1,56 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QMAKEDATAPROVIDER_H
#define QMAKEDATAPROVIDER_H
#include <QtCore/QString>
#include <QtCore/QStringList>
class QMakeDataProviderPrivate;
class QMakeDataProvider {
    QMakeDataProviderPrivate * const d;
public:
    QMakeDataProvider();
    ~QMakeDataProvider();
    bool readFile(const QString &fileName);
    void setQtDir(const QString &qtdir);
    QStringList getFormFiles() const;
    QStringList getHeaderFiles() const;
    QStringList getResourceFiles() const;
    QStringList getSourceFiles() const;
    bool isFlat() const;
    bool isValid() const;
};
#endif // QMAKEDATAPROVIDER_H
QMakeFileReader/qmakefilereader.ico
QMakeFileReader/qmakefilereader.rc
New file
@@ -0,0 +1 @@
IDI_ICON1        ICON        DISCARDABLE    "qmakefilereader.ico"
QMakeFileReader/qmakefilereader.vcxproj
New file
@@ -0,0 +1,257 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup Label="ProjectConfigurations">
    <ProjectConfiguration Include="Debug|Win32">
      <Configuration>Debug</Configuration>
      <Platform>Win32</Platform>
    </ProjectConfiguration>
    <ProjectConfiguration Include="Release|Win32">
      <Configuration>Release</Configuration>
      <Platform>Win32</Platform>
    </ProjectConfiguration>
    <ProjectConfiguration Include="Debug|x64">
      <Configuration>Debug</Configuration>
      <Platform>x64</Platform>
    </ProjectConfiguration>
    <ProjectConfiguration Include="Release|x64">
      <Configuration>Release</Configuration>
      <Platform>x64</Platform>
    </ProjectConfiguration>
  </ItemGroup>
  <PropertyGroup Label="Globals">
    <ProjectGuid>{70711A97-D9B0-3A86-9756-9FF47337908B}</ProjectGuid>
    <Keyword>QtVS_v303</Keyword>
    <RootNamespace>QMakeFileReader</RootNamespace>
    <WindowsTargetPlatformVersion Condition="'$(VisualStudioVersion)'=='15.0'">10.0.17763.0</WindowsTargetPlatformVersion>
    <WindowsTargetPlatformVersion Condition="'$(VisualStudioVersion)'=='16.0'">10.0</WindowsTargetPlatformVersion>
    <WindowsTargetPlatformVersion Condition="'$(VisualStudioVersion)'=='17.0'">10.0</WindowsTargetPlatformVersion>
    <QtMsBuild>$(SolutionDir)\qtmsbuild\QtMsBuild</QtMsBuild>
  </PropertyGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
  <PropertyGroup>
    <PlatformToolset Condition="'$(VisualStudioVersion)'=='15.0'">v141</PlatformToolset>
    <PlatformToolset Condition="'$(VisualStudioVersion)'=='16.0'">v142</PlatformToolset>
    <PlatformToolset Condition="'$(VisualStudioVersion)'=='17.0'">v143</PlatformToolset>
  </PropertyGroup>
  <PropertyGroup Label="Configuration">
    <ConfigurationType>Application</ConfigurationType>
    <OutDir>bin\$(VisualStudioVersion)\$(Platform)\$(Configuration)\</OutDir>
    <IntDir>obj\$(VisualStudioVersion)\$(Platform)\$(Configuration)\</IntDir>
  </PropertyGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
  <ImportGroup Label="ExtensionSettings" />
  <ImportGroup Label="PropertySheets">
    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
    <Import Project="..\QtCppConfig.props" />
  </ImportGroup>
  <PropertyGroup Label="UserMacros" />
  <ImportGroup Condition="Exists('$(QtMsBuild)\qt_defaults.props')">
    <Import Project="$(QtMsBuild)\qt_defaults.props" />
  </ImportGroup>
  <Target Name="QtMsBuildNotFound" BeforeTargets="CustomBuild;ClCompile" Condition="!Exists('$(QtMsBuild)\qt.targets') or !Exists('$(QtMsBuild)\qt.props')">
    <Message Importance="High" Text="QtMsBuild: could not locate qt.targets, qt.props; project may not build correctly." />
  </Target>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
  </PropertyGroup>
  <PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <QtModules>core</QtModules>
    <QtInstall>$(QtBuild)</QtInstall>
  </PropertyGroup>
  <PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <QtModules>core</QtModules>
    <QtInstall>$(QtBuild)</QtInstall>
  </PropertyGroup>
  <PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
    <QtModules>core</QtModules>
    <QtInstall>$(QtBuild)</QtInstall>
  </PropertyGroup>
  <PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
    <QtModules>core</QtModules>
    <QtInstall>$(QtBuild)</QtInstall>
  </PropertyGroup>
  <ImportGroup Condition="Exists('$(QtMsBuild)\qt.props')">
    <Import Project="$(QtMsBuild)\qt.props" />
  </ImportGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <ClCompile>
      <Optimization>Disabled</Optimization>
      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
      <PreprocessorDefinitions>_CONSOLE;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <MultiProcessorCompilation>true</MultiProcessorCompilation>
      <AdditionalIncludeDirectories>evaluator;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
      <AdditionalOptions>-Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 %(AdditionalOptions)</AdditionalOptions>
      <BrowseInformation>false</BrowseInformation>
      <DisableSpecificWarnings>4577;4467;%(DisableSpecificWarnings)</DisableSpecificWarnings>
      <ExceptionHandling>Sync</ExceptionHandling>
      <PreprocessToFile>false</PreprocessToFile>
      <SuppressStartupBanner>true</SuppressStartupBanner>
      <WarningLevel>Level3</WarningLevel>
    </ClCompile>
    <Link>
      <SubSystem>Console</SubSystem>
      <OutputFile>$(OutDir)\QMakeFileReader.exe</OutputFile>
      <GenerateDebugInformation>true</GenerateDebugInformation>
      <AdditionalOptions>"/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions)</AdditionalOptions>
      <DataExecutionPrevention>true</DataExecutionPrevention>
      <IgnoreImportLibrary>true</IgnoreImportLibrary>
      <RandomizedBaseAddress>true</RandomizedBaseAddress>
      <SuppressStartupBanner>true</SuppressStartupBanner>
    </Link>
    <PostBuildEvent>
      <Command>copy $(TargetPath) bin</Command>
    </PostBuildEvent>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <ClCompile>
      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
      <PreprocessorDefinitions>_CONSOLE;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;NDEBUG;QT_NO_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <MultiProcessorCompilation>true</MultiProcessorCompilation>
      <AdditionalIncludeDirectories>evaluator;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
      <AdditionalOptions>-Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 %(AdditionalOptions)</AdditionalOptions>
      <BrowseInformation>false</BrowseInformation>
      <DebugInformationFormat>None</DebugInformationFormat>
      <DisableSpecificWarnings>4577;4467;%(DisableSpecificWarnings)</DisableSpecificWarnings>
      <ExceptionHandling>Sync</ExceptionHandling>
      <Optimization>MaxSpeed</Optimization>
      <PreprocessToFile>false</PreprocessToFile>
      <ProgramDataBaseFileName>
      </ProgramDataBaseFileName>
      <SuppressStartupBanner>true</SuppressStartupBanner>
      <WarningLevel>Level3</WarningLevel>
    </ClCompile>
    <Link>
      <SubSystem>Console</SubSystem>
      <OutputFile>$(OutDir)\QMakeFileReader.exe</OutputFile>
      <GenerateDebugInformation>false</GenerateDebugInformation>
      <AdditionalOptions>"/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions)</AdditionalOptions>
      <DataExecutionPrevention>true</DataExecutionPrevention>
      <IgnoreImportLibrary>true</IgnoreImportLibrary>
      <LinkIncremental>false</LinkIncremental>
      <OptimizeReferences>true</OptimizeReferences>
      <RandomizedBaseAddress>true</RandomizedBaseAddress>
      <SuppressStartupBanner>true</SuppressStartupBanner>
    </Link>
    <PostBuildEvent>
      <Command>copy $(TargetPath) bin</Command>
    </PostBuildEvent>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
    <ClCompile>
      <Optimization>Disabled</Optimization>
      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
      <PreprocessorDefinitions>_CONSOLE;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <MultiProcessorCompilation>true</MultiProcessorCompilation>
      <AdditionalIncludeDirectories>evaluator;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
      <AdditionalOptions>-Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 %(AdditionalOptions)</AdditionalOptions>
      <BrowseInformation>false</BrowseInformation>
      <DisableSpecificWarnings>4577;4467;%(DisableSpecificWarnings)</DisableSpecificWarnings>
      <ExceptionHandling>Sync</ExceptionHandling>
      <PreprocessToFile>false</PreprocessToFile>
      <SuppressStartupBanner>true</SuppressStartupBanner>
      <WarningLevel>Level3</WarningLevel>
    </ClCompile>
    <Link>
      <SubSystem>Console</SubSystem>
      <OutputFile>$(OutDir)\QMakeFileReader.exe</OutputFile>
      <GenerateDebugInformation>true</GenerateDebugInformation>
      <AdditionalOptions>"/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions)</AdditionalOptions>
      <DataExecutionPrevention>true</DataExecutionPrevention>
      <IgnoreImportLibrary>true</IgnoreImportLibrary>
      <RandomizedBaseAddress>true</RandomizedBaseAddress>
      <SuppressStartupBanner>true</SuppressStartupBanner>
    </Link>
    <PostBuildEvent>
      <Command>copy $(TargetPath) bin</Command>
    </PostBuildEvent>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
    <ClCompile>
      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
      <PreprocessorDefinitions>_CONSOLE;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;NDEBUG;QT_NO_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <MultiProcessorCompilation>true</MultiProcessorCompilation>
      <AdditionalIncludeDirectories>evaluator;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
      <AdditionalOptions>-Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 %(AdditionalOptions)</AdditionalOptions>
      <BrowseInformation>false</BrowseInformation>
      <DebugInformationFormat>None</DebugInformationFormat>
      <DisableSpecificWarnings>4577;4467;%(DisableSpecificWarnings)</DisableSpecificWarnings>
      <ExceptionHandling>Sync</ExceptionHandling>
      <Optimization>MaxSpeed</Optimization>
      <PreprocessToFile>false</PreprocessToFile>
      <ProgramDataBaseFileName>
      </ProgramDataBaseFileName>
      <SuppressStartupBanner>true</SuppressStartupBanner>
      <WarningLevel>Level3</WarningLevel>
    </ClCompile>
    <Link>
      <SubSystem>Console</SubSystem>
      <OutputFile>$(OutDir)\QMakeFileReader.exe</OutputFile>
      <GenerateDebugInformation>false</GenerateDebugInformation>
      <AdditionalOptions>"/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions)</AdditionalOptions>
      <DataExecutionPrevention>true</DataExecutionPrevention>
      <IgnoreImportLibrary>true</IgnoreImportLibrary>
      <LinkIncremental>false</LinkIncremental>
      <OptimizeReferences>true</OptimizeReferences>
      <RandomizedBaseAddress>true</RandomizedBaseAddress>
      <SuppressStartupBanner>true</SuppressStartupBanner>
    </Link>
    <PostBuildEvent>
      <Command>copy $(TargetPath) bin</Command>
    </PostBuildEvent>
  </ItemDefinitionGroup>
  <ItemGroup>
    <ClCompile Include="main.cpp" />
    <ClCompile Include="evalhandler.cpp" />
    <ClCompile Include="evaluator\ioutils.cpp" />
    <ClCompile Include="evaluator\proitems.cpp" />
    <ClCompile Include="evaluator\qmakebuiltins.cpp" />
    <ClCompile Include="qmakedataprovider.cpp" />
    <ClCompile Include="evaluator\qmakeevaluator.cpp" />
    <ClCompile Include="evaluator\qmakeglobals.cpp" />
    <ClCompile Include="evaluator\qmakeparser.cpp" />
  </ItemGroup>
  <ItemGroup>
    <ClInclude Include="evalhandler.h" />
    <ClInclude Include="evaluator\ioutils.h" />
    <ClInclude Include="evaluator\proitems.h" />
    <ClInclude Include="evaluator\qmake_global.h" />
    <ClInclude Include="qmakedataprovider.h" />
    <ClInclude Include="evaluator\qmakeevaluator.h" />
    <ClInclude Include="evaluator\qmakeevaluator_p.h" />
    <ClInclude Include="evaluator\qmakeglobals.h" />
    <ClInclude Include="evaluator\qmakeparser.h" />
  </ItemGroup>
  <ItemGroup>
    <ResourceCompile Include="qmakefilereader.rc" />
  </ItemGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
  <Import Project="$(SolutionDir)\transform.targets" />
  <ImportGroup Condition="Exists('$(QtMsBuild)\qt.targets')">
    <Import Project="$(QtMsBuild)\qt.targets" />
  </ImportGroup>
  <ImportGroup Label="ExtensionTargets" />
  <ItemGroup>
    <ProjectReference Include="..\qtmsbuild\QtMSBuild.csproj">
      <Project>{A618D28B-9352-44F4-AA71-609BF68BF871}</Project>
    </ProjectReference>
  </ItemGroup>
  <Target Name="qmakeFileReader_PreBuild">
    <ItemGroup>
      <ProjectReference Remove="..\qtmsbuild\QtMSBuild.csproj"/>
    </ItemGroup>
  </Target>
  <PropertyGroup>
    <ResolveReferencesDependsOn>qmakeFileReader_PreBuild;$(ResolveReferencesDependsOn)</ResolveReferencesDependsOn>
  </PropertyGroup>
</Project>
QMakeFileReader/qmakefilereader.vcxproj.filters
New file
@@ -0,0 +1,86 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup>
    <Filter Include="Generated Files">
      <UniqueIdentifier>{71ED8ED8-ACB9-4CE9-BBE1-E00B30144E11}</UniqueIdentifier>
      <Extensions>cpp;c;cxx;moc;h;def;odl;idl;res;</Extensions>
    </Filter>
    <Filter Include="Header Files">
      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
    </Filter>
    <Filter Include="Header Files">
      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
    </Filter>
    <Filter Include="Source Files">
      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
      <Extensions>cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
    </Filter>
    <Filter Include="Source Files">
      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
      <Extensions>cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
    </Filter>
  </ItemGroup>
  <ItemGroup>
    <ClCompile Include="evalhandler.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="evaluator\ioutils.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="main.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="evaluator\proitems.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="evaluator\qmakebuiltins.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="qmakedataprovider.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="evaluator\qmakeevaluator.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="evaluator\qmakeglobals.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="evaluator\qmakeparser.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
  </ItemGroup>
  <ItemGroup>
    <ClInclude Include="evalhandler.h">
      <Filter>Header Files</Filter>
    </ClInclude>
    <ClInclude Include="evaluator\ioutils.h">
      <Filter>Header Files</Filter>
    </ClInclude>
    <ClInclude Include="evaluator\proitems.h">
      <Filter>Header Files</Filter>
    </ClInclude>
    <ClInclude Include="evaluator\qmake_global.h">
      <Filter>Header Files</Filter>
    </ClInclude>
    <ClInclude Include="qmakedataprovider.h">
      <Filter>Header Files</Filter>
    </ClInclude>
    <ClInclude Include="evaluator\qmakeevaluator.h">
      <Filter>Header Files</Filter>
    </ClInclude>
    <ClInclude Include="evaluator\qmakeevaluator_p.h">
      <Filter>Header Files</Filter>
    </ClInclude>
    <ClInclude Include="evaluator\qmakeglobals.h">
      <Filter>Header Files</Filter>
    </ClInclude>
    <ClInclude Include="evaluator\qmakeparser.h">
      <Filter>Header Files</Filter>
    </ClInclude>
  </ItemGroup>
  <ItemGroup>
    <ResourceCompile Include="qmakefilereader.rc" />
  </ItemGroup>
</Project>
QrcEditor/main.cpp
New file
@@ -0,0 +1,40 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qrceditor.h"
#include "mainwindow.h"
int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    MainWindow mw;
    mw.show();
    if (argc == 2)
        mw.openFile(argv[1]);
    return app.exec();
}
QrcEditor/mainwindow.cpp
New file
@@ -0,0 +1,183 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "mainwindow.h"
#include "qrceditor.h"
#include <QAction>
#include <QDebug>
#include <QFileDialog>
#include <QMenuBar>
#include <QStatusBar>
#include <QVBoxLayout>
#include <QMessageBox>
#include <QToolBar>
#include <QProcess>
#include <windows.h>
#include <Tlhelp32.h>
MainWindow::MainWindow() :
    m_qrcEditor(new  SharedTools::QrcEditor())
{
    m_qrcEditor->setResourceDragEnabled(true);
    setWindowTitle(tr("Qt Resource Editor"));
    QMenu* fMenu = menuBar()->addMenu(tr("&File"));
    QToolBar* tb = new QToolBar("Title", this);
    tb->setMovable(false);
    addToolBar(Qt::TopToolBarArea, tb);
    QAction* oa = fMenu->addAction(tr("&Open..."));
    oa->setShortcut(tr("Ctrl+O", "File|Open"));
    oa->setIcon(style()->standardIcon(QStyle::SP_DialogOpenButton));
    tb->addAction(oa);
    connect(oa, SIGNAL(triggered()), this, SLOT(slotOpen()));
    QAction* sa = fMenu->addAction(tr("&Save"));
    sa->setShortcut(tr("Ctrl+S", "File|Save"));
    sa->setIcon(style()->standardIcon(QStyle::SP_DialogSaveButton));
    tb->addAction(sa);
    connect(sa, SIGNAL(triggered()), this, SLOT(slotSave()));
    fMenu->addSeparator();
    QAction* xa = fMenu->addAction(tr("E&xit"));
    xa->setIcon(style()->standardIcon(QStyle::SP_DialogCloseButton));
    connect(xa, SIGNAL(triggered()), this, SLOT(close()));
    QMenu* hMenu = menuBar()->addMenu(tr("&Help"));
    QAction* actionAbout = hMenu->addAction(tr("&About"));
    connect(actionAbout, SIGNAL(triggered()), this, SLOT(slotAbout()));
    QAction* actionAboutQt = hMenu->addAction(tr("A&bout Qt"));
    connect(actionAboutQt, SIGNAL(triggered()), this, SLOT(slotAboutQt()));
    QWidget *cw = new QWidget();
    setCentralWidget(cw);
    QVBoxLayout *lt = new QVBoxLayout(cw);
    lt->addWidget(m_qrcEditor);
    setMinimumSize(QSize(500, 500));
}
void MainWindow::openFile(QString fileName)
{
    if (fileName.isEmpty())
    return;
    if (m_qrcEditor->isDirty()) {
        int ret = fileChangedDialog();
        switch (ret) {
            case QMessageBox::Yes:
                slotSave();
            case QMessageBox::No:
            break;
            default:
                return;
            break;
        }
    }
    if (m_qrcEditor->load(fileName)) {
        statusBar()->showMessage(tr("%1 opened").arg(fileName));
        QFileInfo fi(fileName);
        setWindowTitle(tr("Qt Resource Editor") + " - " + fi.fileName());
    }
    else
        statusBar()->showMessage(tr("Unable to open %1.").arg(fileName));
}
void MainWindow::slotOpen()
{
    const QString fileName = QFileDialog::getOpenFileName(this, tr("Choose Resource File"),
                                                          QString(),
                                                          tr("Resource files (*.qrc)"));
    this->openFile(fileName);
}
void MainWindow::slotSave()
{
    const QString oldFileName = m_qrcEditor->fileName();
    QString fileName = oldFileName;
    if (fileName.isEmpty()) {
        fileName = QFileDialog::getSaveFileName(this, tr("Save Resource File"),
                                                QString(),
                                                tr("Resource files (*.qrc)"));
        if (fileName.isEmpty())
            return;
    }
    m_qrcEditor->setFileName(fileName);
    if (m_qrcEditor->save()) {
        statusBar()->showMessage(tr("%1 written").arg(fileName));
    } else {
        statusBar()->showMessage(tr("Unable to write %1.").arg(fileName));
        m_qrcEditor->setFileName(oldFileName);
    }
}
void MainWindow::slotAbout()
{
    QMessageBox::about(this, tr("About Qt Resource Editor"),
        tr("Qt Resource Editor") + "\n\n" + tr("Copyright (C) 2016 The Qt Company Ltd."));
}
void MainWindow::slotAboutQt()
{
    QMessageBox::aboutQt(this);
}
void MainWindow::closeEvent(QCloseEvent *e)
{
    if (m_qrcEditor->isDirty()) {
        int ret = fileChangedDialog();
        switch (ret) {
            case QMessageBox::Yes:
                slotSave();
            case QMessageBox::No:
                QMainWindow::close();
            break;
            default:
                e->ignore();
                return;
            break;
        }
    }
    e->accept();
}
int MainWindow::fileChangedDialog()
{
    QMessageBox message(this);
    message.setText(tr("The .qrc file has been modified."));
    message.setWindowTitle("Qt Resource Editor");
    message.setInformativeText(tr("Do you want to save the changes?"));
    message.setStandardButtons(QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
    message.setDefaultButton(QMessageBox::Yes);
    return message.exec();
}
QrcEditor/mainwindow.h
New file
@@ -0,0 +1,65 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QString>
#include <QCloseEvent>
namespace SharedTools {
    class QrcEditor;
}
class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    MainWindow();
    void openFile(QString fileName);
protected:
    void closeEvent(QCloseEvent *e);
private slots:
    void slotOpen();
    void slotSave();
    void slotAbout();
    void slotAboutQt();
private:
    int fileChangedDialog();
private:
    SharedTools::QrcEditor *m_qrcEditor;
    QString                 m_devenvPIDArg;
};
#endif // MAINWINDOW_H
QrcEditor/qrceditor.ico
QrcEditor/qrceditor.rc
New file
@@ -0,0 +1 @@
IDI_ICON1        ICON        DISCARDABLE    "qrceditor.ico"
QrcEditor/qrceditor.vcxproj
New file
@@ -0,0 +1,253 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup Label="ProjectConfigurations">
    <ProjectConfiguration Include="Debug|Win32">
      <Configuration>Debug</Configuration>
      <Platform>Win32</Platform>
    </ProjectConfiguration>
    <ProjectConfiguration Include="Release|Win32">
      <Configuration>Release</Configuration>
      <Platform>Win32</Platform>
    </ProjectConfiguration>
    <ProjectConfiguration Include="Debug|x64">
      <Configuration>Debug</Configuration>
      <Platform>x64</Platform>
    </ProjectConfiguration>
    <ProjectConfiguration Include="Release|x64">
      <Configuration>Release</Configuration>
      <Platform>x64</Platform>
    </ProjectConfiguration>
  </ItemGroup>
  <PropertyGroup Label="Globals">
    <ProjectGuid>{4CEE73C9-FCFA-3A72-A0A3-036BDBB3240F}</ProjectGuid>
    <Keyword>QtVS_v303</Keyword>
    <RootNamespace>QrcEditor</RootNamespace>
    <WindowsTargetPlatformVersion Condition="'$(VisualStudioVersion)'=='15.0'">10.0.17763.0</WindowsTargetPlatformVersion>
    <WindowsTargetPlatformVersion Condition="'$(VisualStudioVersion)'=='16.0'">10.0</WindowsTargetPlatformVersion>
    <WindowsTargetPlatformVersion Condition="'$(VisualStudioVersion)'=='17.0'">10.0</WindowsTargetPlatformVersion>
    <QtMsBuild>$(SolutionDir)\qtmsbuild\QtMsBuild</QtMsBuild>
  </PropertyGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
  <PropertyGroup>
    <PlatformToolset Condition="'$(VisualStudioVersion)'=='15.0'">v141</PlatformToolset>
    <PlatformToolset Condition="'$(VisualStudioVersion)'=='16.0'">v142</PlatformToolset>
    <PlatformToolset Condition="'$(VisualStudioVersion)'=='17.0'">v143</PlatformToolset>
  </PropertyGroup>
  <PropertyGroup Label="Configuration">
    <ConfigurationType>Application</ConfigurationType>
    <OutDir>bin\$(VisualStudioVersion)\$(Platform)\$(Configuration)\</OutDir>
    <IntDir>obj\$(VisualStudioVersion)\$(Platform)\$(Configuration)\</IntDir>
  </PropertyGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
  <ImportGroup Label="ExtensionSettings" />
  <ImportGroup Label="PropertySheets">
    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
    <Import Project="..\QtCppConfig.props" />
  </ImportGroup>
  <PropertyGroup Label="UserMacros" />
  <ImportGroup Condition="Exists('$(QtMsBuild)\qt_defaults.props')">
    <Import Project="$(QtMsBuild)\qt_defaults.props" />
  </ImportGroup>
  <Target Name="QtMsBuildNotFound" BeforeTargets="CustomBuild;ClCompile" Condition="!Exists('$(QtMsBuild)\qt.targets') or !Exists('$(QtMsBuild)\qt.props')">
    <Message Importance="High" Text="QtMsBuild: could not locate qt.targets, qt.props; project may not build correctly." />
  </Target>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
  </PropertyGroup>
  <PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <QtModules>core;xml;gui;widgets</QtModules>
    <QtInstall>$(QtBuild)</QtInstall>
  </PropertyGroup>
  <PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <QtModules>core;xml;gui;widgets</QtModules>
    <QtInstall>$(QtBuild)</QtInstall>
  </PropertyGroup>
  <PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
    <QtModules>core;xml;gui;widgets</QtModules>
    <QtInstall>$(QtBuild)</QtInstall>
  </PropertyGroup>
  <PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
    <QtModules>core;xml;gui;widgets</QtModules>
    <QtInstall>$(QtBuild)</QtInstall>
  </PropertyGroup>
  <ImportGroup Condition="Exists('$(QtMsBuild)\qt.props')">
    <Import Project="$(QtMsBuild)\qt.props" />
  </ImportGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <ClCompile>
      <Optimization>Disabled</Optimization>
      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
      <PreprocessorDefinitions>_WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <MultiProcessorCompilation>true</MultiProcessorCompilation>
      <AdditionalIncludeDirectories>shared;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
      <AdditionalOptions>-Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 %(AdditionalOptions)</AdditionalOptions>
      <BrowseInformation>false</BrowseInformation>
      <DisableSpecificWarnings>4577;4467;%(DisableSpecificWarnings)</DisableSpecificWarnings>
      <ExceptionHandling>Sync</ExceptionHandling>
      <PreprocessToFile>false</PreprocessToFile>
      <SuppressStartupBanner>true</SuppressStartupBanner>
      <WarningLevel>Level3</WarningLevel>
    </ClCompile>
    <Link>
      <SubSystem>Windows</SubSystem>
      <OutputFile>$(OutDir)\QrcEditor.exe</OutputFile>
      <GenerateDebugInformation>true</GenerateDebugInformation>
      <AdditionalOptions>"/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions)</AdditionalOptions>
      <DataExecutionPrevention>true</DataExecutionPrevention>
      <IgnoreImportLibrary>true</IgnoreImportLibrary>
      <RandomizedBaseAddress>true</RandomizedBaseAddress>
      <SuppressStartupBanner>true</SuppressStartupBanner>
    </Link>
    <PostBuildEvent>
      <Command>copy $(TargetPath) bin</Command>
    </PostBuildEvent>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <ClCompile>
      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
      <PreprocessorDefinitions>_WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;NDEBUG;QT_NO_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <MultiProcessorCompilation>true</MultiProcessorCompilation>
      <AdditionalIncludeDirectories>shared;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
      <AdditionalOptions>-Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 %(AdditionalOptions)</AdditionalOptions>
      <BrowseInformation>false</BrowseInformation>
      <DebugInformationFormat>None</DebugInformationFormat>
      <DisableSpecificWarnings>4577;4467;%(DisableSpecificWarnings)</DisableSpecificWarnings>
      <ExceptionHandling>Sync</ExceptionHandling>
      <Optimization>MaxSpeed</Optimization>
      <PreprocessToFile>false</PreprocessToFile>
      <ProgramDataBaseFileName>
      </ProgramDataBaseFileName>
      <SuppressStartupBanner>true</SuppressStartupBanner>
      <WarningLevel>Level3</WarningLevel>
    </ClCompile>
    <Link>
      <SubSystem>Windows</SubSystem>
      <OutputFile>$(OutDir)\QrcEditor.exe</OutputFile>
      <GenerateDebugInformation>false</GenerateDebugInformation>
      <AdditionalOptions>"/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions)</AdditionalOptions>
      <DataExecutionPrevention>true</DataExecutionPrevention>
      <IgnoreImportLibrary>true</IgnoreImportLibrary>
      <LinkIncremental>false</LinkIncremental>
      <OptimizeReferences>true</OptimizeReferences>
      <RandomizedBaseAddress>true</RandomizedBaseAddress>
      <SuppressStartupBanner>true</SuppressStartupBanner>
    </Link>
    <PostBuildEvent>
      <Command>copy $(TargetPath) bin</Command>
    </PostBuildEvent>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
    <ClCompile>
      <Optimization>Disabled</Optimization>
      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
      <PreprocessorDefinitions>_WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <MultiProcessorCompilation>true</MultiProcessorCompilation>
      <AdditionalIncludeDirectories>shared;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
      <AdditionalOptions>-Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 %(AdditionalOptions)</AdditionalOptions>
      <BrowseInformation>false</BrowseInformation>
      <DisableSpecificWarnings>4577;4467;%(DisableSpecificWarnings)</DisableSpecificWarnings>
      <ExceptionHandling>Sync</ExceptionHandling>
      <PreprocessToFile>false</PreprocessToFile>
      <SuppressStartupBanner>true</SuppressStartupBanner>
      <WarningLevel>Level3</WarningLevel>
    </ClCompile>
    <Link>
      <SubSystem>Windows</SubSystem>
      <OutputFile>$(OutDir)\QrcEditor.exe</OutputFile>
      <GenerateDebugInformation>true</GenerateDebugInformation>
      <AdditionalOptions>"/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions)</AdditionalOptions>
      <DataExecutionPrevention>true</DataExecutionPrevention>
      <IgnoreImportLibrary>true</IgnoreImportLibrary>
      <RandomizedBaseAddress>true</RandomizedBaseAddress>
      <SuppressStartupBanner>true</SuppressStartupBanner>
    </Link>
    <PostBuildEvent>
      <Command>copy $(TargetPath) bin</Command>
    </PostBuildEvent>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
    <ClCompile>
      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
      <PreprocessorDefinitions>_WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;NDEBUG;QT_NO_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <MultiProcessorCompilation>true</MultiProcessorCompilation>
      <AdditionalIncludeDirectories>shared;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
      <AdditionalOptions>-Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 %(AdditionalOptions)</AdditionalOptions>
      <BrowseInformation>false</BrowseInformation>
      <DebugInformationFormat>None</DebugInformationFormat>
      <DisableSpecificWarnings>4577;4467;%(DisableSpecificWarnings)</DisableSpecificWarnings>
      <ExceptionHandling>Sync</ExceptionHandling>
      <Optimization>MaxSpeed</Optimization>
      <PreprocessToFile>false</PreprocessToFile>
      <ProgramDataBaseFileName>
      </ProgramDataBaseFileName>
      <SuppressStartupBanner>true</SuppressStartupBanner>
      <WarningLevel>Level3</WarningLevel>
    </ClCompile>
    <Link>
      <SubSystem>Windows</SubSystem>
      <OutputFile>$(OutDir)\QrcEditor.exe</OutputFile>
      <GenerateDebugInformation>false</GenerateDebugInformation>
      <AdditionalOptions>"/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions)</AdditionalOptions>
      <DataExecutionPrevention>true</DataExecutionPrevention>
      <IgnoreImportLibrary>true</IgnoreImportLibrary>
      <LinkIncremental>false</LinkIncremental>
      <OptimizeReferences>true</OptimizeReferences>
      <RandomizedBaseAddress>true</RandomizedBaseAddress>
      <SuppressStartupBanner>true</SuppressStartupBanner>
    </Link>
    <PostBuildEvent>
      <Command>copy $(TargetPath) bin</Command>
    </PostBuildEvent>
  </ItemDefinitionGroup>
  <ItemGroup>
    <ClCompile Include="main.cpp" />
    <ClCompile Include="mainwindow.cpp" />
    <ClCompile Include="shared\qrceditor.cpp" />
    <ClCompile Include="shared\resourcefile.cpp" />
    <ClCompile Include="shared\resourceview.cpp" />
    <ClCompile Include="shared\undocommands.cpp" />
  </ItemGroup>
  <ItemGroup>
    <QtMoc Include="mainwindow.h" />
    <QtMoc Include="shared\qrceditor.h" />
    <QtMoc Include="shared\resourcefile_p.h" />
    <QtMoc Include="shared\resourceview.h" />
    <ClInclude Include="shared\undocommands_p.h" />
  </ItemGroup>
  <ItemGroup>
    <QtUic Include="shared\qrceditor.ui" />
  </ItemGroup>
  <ItemGroup>
    <ResourceCompile Include="qrceditor.rc" />
  </ItemGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
  <Import Project="$(SolutionDir)\transform.targets" />
  <ImportGroup Condition="Exists('$(QtMsBuild)\qt.targets')">
    <Import Project="$(QtMsBuild)\qt.targets" />
  </ImportGroup>
  <ImportGroup Label="ExtensionTargets" />
  <ItemGroup>
    <ProjectReference Include="..\qtmsbuild\QtMSBuild.csproj">
      <Project>{A618D28B-9352-44F4-AA71-609BF68BF871}</Project>
    </ProjectReference>
  </ItemGroup>
  <Target Name="QRCEditor_PreBuild">
    <ItemGroup>
      <ProjectReference Remove="..\qtmsbuild\QtMSBuild.csproj"/>
    </ItemGroup>
  </Target>
  <PropertyGroup>
    <ResolveReferencesDependsOn>QRCEditor_PreBuild;$(ResolveReferencesDependsOn)</ResolveReferencesDependsOn>
  </PropertyGroup>
</Project>
QrcEditor/qrceditor.vcxproj.filters
New file
@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup>
    <Filter Include="Form Files">
      <UniqueIdentifier>{99349809-55BA-4b9d-BF79-8FDBB0286EB3}</UniqueIdentifier>
      <Extensions>ui</Extensions>
      <ParseFiles>false</ParseFiles>
    </Filter>
    <Filter Include="Form Files">
      <UniqueIdentifier>{99349809-55BA-4b9d-BF79-8FDBB0286EB3}</UniqueIdentifier>
      <Extensions>ui</Extensions>
      <ParseFiles>false</ParseFiles>
    </Filter>
    <Filter Include="Generated Files">
      <UniqueIdentifier>{71ED8ED8-ACB9-4CE9-BBE1-E00B30144E11}</UniqueIdentifier>
      <Extensions>cpp;c;cxx;moc;h;def;odl;idl;res;</Extensions>
    </Filter>
    <Filter Include="Header Files">
      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
    </Filter>
    <Filter Include="Header Files">
      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
    </Filter>
    <Filter Include="Source Files">
      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
      <Extensions>cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
    </Filter>
    <Filter Include="Source Files">
      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
      <Extensions>cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
    </Filter>
  </ItemGroup>
  <ItemGroup>
    <ClCompile Include="main.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="mainwindow.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="shared\qrceditor.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="shared\resourcefile.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="shared\resourceview.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="shared\undocommands.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
  </ItemGroup>
  <ItemGroup>
    <QtMoc Include="mainwindow.h">
      <Filter>Header Files</Filter>
    </QtMoc>
    <QtMoc Include="shared\qrceditor.h">
      <Filter>Header Files</Filter>
    </QtMoc>
    <QtMoc Include="shared\resourcefile_p.h">
      <Filter>Header Files</Filter>
    </QtMoc>
    <QtMoc Include="shared\resourceview.h">
      <Filter>Header Files</Filter>
    </QtMoc>
    <ClInclude Include="shared\undocommands_p.h">
      <Filter>Header Files</Filter>
    </ClInclude>
  </ItemGroup>
  <ItemGroup>
    <QtUic Include="shared\qrceditor.ui">
      <Filter>Form Files</Filter>
    </QtUic>
  </ItemGroup>
  <ItemGroup>
    <ResourceCompile Include="qrceditor.rc" />
  </ItemGroup>
</Project>
QrcEditor/shared/qrceditor.cpp
New file
@@ -0,0 +1,423 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qrceditor.h"
#include "undocommands_p.h"
#include <QtCore/QDebug>
#include <QtWidgets/QMenu>
#include <QtWidgets/QFileDialog>
#include <QtWidgets/QMessageBox>
using namespace SharedTools;
QrcEditor::QrcEditor(QWidget *parent)
  : QWidget(parent),
    m_treeview(new ResourceView(&m_history)),
    m_addFileAction(0)
{
    m_ui.setupUi(this);
    QHBoxLayout *layout = new QHBoxLayout;
    layout->setSpacing(0);
    layout->setMargin(0);
    m_ui.centralWidget->setLayout(layout);
    m_treeview->enableContextMenu(false);
    layout->addWidget(m_treeview);
    connect(m_ui.removeButton, SIGNAL(clicked()), this, SLOT(onRemove()));
    // 'Add' button with menu
    QMenu *addMenu = new QMenu(this);
    m_addFileAction = addMenu->addAction(tr("Add Files"), this, SLOT(onAddFiles()));
    addMenu->addAction(tr("Add Prefix"), this, SLOT(onAddPrefix()));
    m_ui.addButton->setMenu(addMenu);
    connect(m_treeview, SIGNAL(addPrefixTriggered()), this, SLOT(onAddPrefix()));
    connect(m_treeview, SIGNAL(addFilesTriggered(QString)), this, SLOT(onAddFiles()));
    connect(m_treeview, SIGNAL(removeItem()), this, SLOT(onRemove()));
    connect(m_treeview, SIGNAL(currentIndexChanged()), this, SLOT(updateCurrent()));
    connect(m_treeview, SIGNAL(dirtyChanged(bool)), this, SIGNAL(dirtyChanged(bool)));
    m_treeview->setFocus();
    connect(m_ui.aliasText, SIGNAL(textEdited(QString)),
            this, SLOT(onAliasChanged(QString)));
    connect(m_ui.prefixText, SIGNAL(textEdited(QString)),
            this, SLOT(onPrefixChanged(QString)));
    connect(m_ui.languageText, SIGNAL(textEdited(QString)),
            this, SLOT(onLanguageChanged(QString)));
    // Prevent undo command merging after a switch of focus:
    // (0) The initial text is "Green".
    // (1) The user appends " is a color." --> text is "Green is a color."
    // (2) The user clicks into some other line edit --> loss of focus
    // (3) The user gives focuse again and substitutes "Green" with "Red"
    //     --> text now is "Red is a color."
    // (4) The user hits undo --> text now is "Green is a color."
    //     Without calling advanceMergeId() it would have been "Green", instead.
    connect(m_ui.aliasText, SIGNAL(editingFinished()),
            m_treeview, SLOT(advanceMergeId()));
    connect(m_ui.prefixText, SIGNAL(editingFinished()),
            m_treeview, SLOT(advanceMergeId()));
    connect(m_ui.languageText, SIGNAL(editingFinished()),
            m_treeview, SLOT(advanceMergeId()));
    connect(m_treeview, SIGNAL(addFilesTriggered(const QString&)),
        this, SIGNAL(addFilesTriggered(const QString&)));
    connect(&m_history, SIGNAL(canRedoChanged(bool)), this, SLOT(updateHistoryControls()));
    connect(&m_history, SIGNAL(canUndoChanged(bool)), this, SLOT(updateHistoryControls()));
    updateHistoryControls();
    updateCurrent();
}
QrcEditor::~QrcEditor()
{
}
QString QrcEditor::fileName() const
{
    return m_treeview->fileName();
}
void QrcEditor::setFileName(const QString &fileName)
{
    m_treeview->setFileName(fileName);
}
bool QrcEditor::load(const QString &fileName)
{
    const bool success = m_treeview->load(fileName);
    if (success) {
        // Set "focus"
        m_treeview->setCurrentIndex(m_treeview->model()->index(0,0));
        // Expand prefix nodes
        m_treeview->expandAll();
    }
    return success;
}
bool QrcEditor::save()
{
    return m_treeview->save();
}
bool QrcEditor::isDirty()
{
    return m_treeview->isDirty();
}
void QrcEditor::setDirty(bool dirty)
{
    m_treeview->setDirty(dirty);
}
// Propagates a change of selection in the tree
// to the alias/prefix/language edit controls
void QrcEditor::updateCurrent()
{
    const bool isValid = m_treeview->currentIndex().isValid();
    const bool isPrefix = m_treeview->isPrefix(m_treeview->currentIndex()) && isValid;
    const bool isFile = !isPrefix && isValid;
    m_ui.aliasLabel->setEnabled(isFile);
    m_ui.aliasText->setEnabled(isFile);
    m_currentAlias = m_treeview->currentAlias();
    m_ui.aliasText->setText(m_currentAlias);
    m_ui.prefixLabel->setEnabled(isPrefix);
    m_ui.prefixText->setEnabled(isPrefix);
    m_currentPrefix = m_treeview->currentPrefix();
    m_ui.prefixText->setText(m_currentPrefix);
    m_ui.languageLabel->setEnabled(isPrefix);
    m_ui.languageText->setEnabled(isPrefix);
    m_currentLanguage = m_treeview->currentLanguage();
    m_ui.languageText->setText(m_currentLanguage);
    m_ui.urlLabel->setEnabled(isFile);
    m_ui.urlText->setEnabled(isFile);
    if (isFile) {
        QString url = QLatin1String(":");
        url += m_currentPrefix;
        if (!url.endsWith(QLatin1Char('/')))
            url += QLatin1Char('/');
        if (m_currentAlias.isEmpty())
            url += m_treeview->currentIndex().data().toString();
        else
            url += m_currentAlias;
        m_ui.urlText->setText(url);
    } else {
        m_ui.urlText->clear();
    }
    m_ui.addButton->setEnabled(true);
    m_addFileAction->setEnabled(isValid);
    m_ui.removeButton->setEnabled(isValid);
}
void QrcEditor::updateHistoryControls()
{
    emit undoStackChanged(m_history.canUndo(), m_history.canRedo());
}
void QrcEditor::resolveLocationIssues(QStringList &files)
{
    const QDir dir = QFileInfo(m_treeview->fileName()).absoluteDir();
    const QString dotdotSlash = QLatin1String("../");
    int i = 0;
    int count = files.count();
    int initialCount = files.count();
    // Find first troublesome file
    for (; i < count; i++) {
        QString const &file = files.at(i);
        const QString relativePath = dir.relativeFilePath(file);
        if (relativePath.startsWith(dotdotSlash))
            break;
    }
    // All paths fine -> no interaction needed
    if (i == count) {
        return;
    }
    // Interact with user from now on
    bool abort = false;
    for (; i < count; i++) {
        // Path fine -> skip file
        QString const &file = files.at(i);
        QString const relativePath = dir.relativeFilePath(file);
        if (!relativePath.startsWith(dotdotSlash)) {
            continue;
        }
        // Path troublesome and aborted -> remove file
        if (abort) {
            files.removeAt(i);
            count--;
            i--;
            continue;
        } else {
            // Path troublesome -> query user
            QMessageBox message(this);
            message.setWindowTitle(tr("Invalid File Location"));
            message.setIcon(QMessageBox::Warning);
            QPushButton * const copyButton = message.addButton(tr("Copy"), QMessageBox::ActionRole);
            QPushButton * skipButton = NULL;
            if (initialCount > 1)
            {
                skipButton = message.addButton(tr("Skip"), QMessageBox::DestructiveRole);
                message.setEscapeButton(skipButton);
            }
            QPushButton * const abortButton = message.addButton(tr("Abort"), QMessageBox::RejectRole);
            message.setDefaultButton(copyButton);
            message.setText(tr("The file %1 is not in a subdirectory of the resource file. You now have the option to copy this file to a valid location.")
                            .arg(QDir::toNativeSeparators(file)));
            message.exec();
            if (message.clickedButton() == skipButton) {
                files.removeAt(i);
                count--;
                i--; // Compensate i++
            } else if (message.clickedButton() == copyButton) {
                const QFileInfo fi(file);
                QFileInfo suggestion;
                QDir tmpTarget(dir.path() + QString(QDir::separator()) + QString("Resources"));;
                if (tmpTarget.exists())
                    suggestion.setFile(tmpTarget, fi.fileName());
                else
                    suggestion.setFile(dir, fi.fileName());
                const QString copyName = QFileDialog::getSaveFileName(this, tr("Choose copy location"),
                                                                suggestion.absoluteFilePath());
                if (!copyName.isEmpty()) {
                    QString relPath = dir.relativeFilePath(copyName);
                    if (relPath.startsWith(dotdotSlash)) {   // directory is still invalid
                        i--; // Compensate i++ and try again
                        continue;
                    }
                    if (QFile::exists(copyName)) {
                        if (!QFile::remove(copyName)) {
                            QMessageBox::critical(this, tr("Overwrite Failed"),
                                                  tr("Could not overwrite file %1.")
                                                  .arg(QDir::toNativeSeparators(copyName)));
                            // Remove file
                            files.removeAt(i);
                            count--;
                            i--; // Compensate i++
                            continue;
                        }
                    }
                    if (!QFile::copy(file, copyName)) {
                        QMessageBox::critical(this, tr("Copying Failed"),
                                              tr("Could not copy the file to %1.")
                                              .arg(QDir::toNativeSeparators(copyName)));
                        // Remove file
                        files.removeAt(i);
                        count--;
                        i--; // Compensate i++
                        continue;
                    }
                    files[i] = copyName;
                } else {
                    // Remove file
                    files.removeAt(i);
                    count--;
                    i--; // Compensate i++
                }
            } else if (message.clickedButton() == abortButton) {
                abort = true;
                files.removeAt(i);
                count--;
                i--; // Compensate i++
            }
        }
    }
}
void QrcEditor::setResourceDragEnabled(bool e)
{
    m_treeview->setResourceDragEnabled(e);
}
bool QrcEditor::resourceDragEnabled() const
{
    return m_treeview->resourceDragEnabled();
}
void QrcEditor::setDefaultAddFileEnabled(bool enable)
{
    m_treeview->setDefaultAddFileEnabled(enable);
}
bool QrcEditor::defaultAddFileEnabled() const
{
    return m_treeview->defaultAddFileEnabled();
}
void QrcEditor::addFile(const QString &prefix, const QString &file)
{
    // TODO: make this function UNDO / REDO aware
    m_treeview->addFile(prefix, file);
}
/*
void QrcEditor::removeFile(const QString &prefix, const QString &file)
{
    m_treeview->removeFile(prefix, file);
}
*/
// Slot for change of line edit content 'alias'
void QrcEditor::onAliasChanged(const QString &alias)
{
    const QString &before = m_currentAlias;
    const QString &after = alias;
    m_treeview->setCurrentAlias(before, after);
    m_currentAlias = alias;
    updateCurrent();
    updateHistoryControls();
}
// Slot for change of line edit content 'prefix'
void QrcEditor::onPrefixChanged(const QString &prefix)
{
    const QString &before = m_currentPrefix;
    const QString &after = prefix;
    m_treeview->setCurrentPrefix(before, after);
    m_currentPrefix = prefix;
    updateCurrent();
    updateHistoryControls();
}
// Slot for change of line edit content 'language'
void QrcEditor::onLanguageChanged(const QString &language)
{
    const QString &before = m_currentLanguage;
    const QString &after = language;
    m_treeview->setCurrentLanguage(before, after);
    m_currentLanguage = language;
    updateHistoryControls();
}
// Slot for 'Remove' button
void QrcEditor::onRemove()
{
    // Find current item, push and execute command
    const QModelIndex current = m_treeview->currentIndex();
    int afterDeletionArrayIndex = current.row();
    QModelIndex afterDeletionParent = current.parent();
    m_treeview->findSamePlacePostDeletionModelIndex(afterDeletionArrayIndex, afterDeletionParent);
    QUndoCommand * const removeCommand = new RemoveEntryCommand(m_treeview, current);
    m_history.push(removeCommand);
    const QModelIndex afterDeletionModelIndex
            = m_treeview->model()->index(afterDeletionArrayIndex, 0, afterDeletionParent);
    m_treeview->setCurrentIndex(afterDeletionModelIndex);
    updateHistoryControls();
}
// Slot for 'Add File' button
void QrcEditor::onAddFiles()
{
    QModelIndex const current = m_treeview->currentIndex();
    int const currentIsPrefixNode = m_treeview->isPrefix(current);
    int const prefixArrayIndex = currentIsPrefixNode ? current.row()
            : m_treeview->model()->parent(current).row();
    int const cursorFileArrayIndex = currentIsPrefixNode ? 0 : current.row();
    QStringList fileNames = m_treeview->fileNamesToAdd();
    resolveLocationIssues(fileNames);
    if (fileNames.isEmpty())
        return;
    QUndoCommand * const addFilesCommand = new AddFilesCommand(
            m_treeview, prefixArrayIndex, cursorFileArrayIndex, fileNames);
    m_history.push(addFilesCommand);
    updateHistoryControls();
}
// Slot for 'Add Prefix' button
void QrcEditor::onAddPrefix()
{
    QUndoCommand * const addEmptyPrefixCommand = new AddEmptyPrefixCommand(m_treeview);
    m_history.push(addEmptyPrefixCommand);
    updateHistoryControls();
}
// Slot for 'Undo' button
void QrcEditor::onUndo()
{
    m_history.undo();
    updateCurrent();
    updateHistoryControls();
}
// Slot for 'Redo' button
void QrcEditor::onRedo()
{
    m_history.redo();
    updateCurrent();
    updateHistoryControls();
}
QrcEditor/shared/qrceditor.h
New file
@@ -0,0 +1,105 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QRCEDITOR_H
#define QRCEDITOR_H
#include "ui_qrceditor.h"
#include "resourceview.h"
#include <QtWidgets/QWidget>
#include <QtWidgets/QUndoStack>
namespace SharedTools {
class QrcEditor : public QWidget
{
    Q_OBJECT
public:
    QrcEditor(QWidget *parent = 0);
    virtual ~QrcEditor();
    bool load(const QString &fileName);
    bool save();
    bool isDirty();
    void setDirty(bool dirty);
    QString fileName() const;
    void setFileName(const QString &fileName);
    void setResourceDragEnabled(bool e);
    bool resourceDragEnabled() const;
    void setDefaultAddFileEnabled(bool enable);
    bool defaultAddFileEnabled() const;
    void addFile(const QString &prefix, const QString &file);
//    void removeFile(const QString &prefix, const QString &file);
signals:
    void dirtyChanged(bool dirty);
    void addFilesTriggered(const QString &prefix);
private slots:
    void updateCurrent();
    void updateHistoryControls();
private:
    void resolveLocationIssues(QStringList &files);
private slots:
    void onAliasChanged(const QString &alias);
    void onPrefixChanged(const QString &prefix);
    void onLanguageChanged(const QString &language);
    void onRemove();
    void onAddFiles();
    void onAddPrefix();
signals:
    void undoStackChanged(bool canUndo, bool canRedo);
public slots:
    void onUndo();
    void onRedo();
private:
    Ui::QrcEditor m_ui;
    QUndoStack m_history;
    ResourceView *m_treeview;
    QAction *m_addFileAction;
    QString m_currentAlias;
    QString m_currentPrefix;
    QString m_currentLanguage;
};
}
#endif
QrcEditor/shared/qrceditor.pri
New file
@@ -0,0 +1,19 @@
INCLUDEPATH *= $$PWD
DEPENDPATH *= $$PWD
QT *= xml
# Input
SOURCES += \
    $$PWD/resourcefile.cpp \
    $$PWD/resourceview.cpp \
    $$PWD/qrceditor.cpp \
    $$PWD/undocommands.cpp
HEADERS += \
    $$PWD/resourcefile_p.h \
    $$PWD/resourceview.h \
    $$PWD/qrceditor.h \
    $$PWD/undocommands_p.h
FORMS += $$PWD/qrceditor.ui
QrcEditor/shared/qrceditor.ui
New file
@@ -0,0 +1,127 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>QrcEditor</class>
 <widget class="QWidget" name="QrcEditor">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>491</width>
    <height>381</height>
   </rect>
  </property>
  <layout class="QVBoxLayout" name="verticalLayout_2">
   <property name="margin">
    <number>6</number>
   </property>
   <item>
    <widget class="QWidget" name="centralWidget" native="true">
     <property name="sizePolicy">
      <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
       <horstretch>0</horstretch>
       <verstretch>0</verstretch>
      </sizepolicy>
     </property>
    </widget>
   </item>
   <item>
    <layout class="QHBoxLayout" name="horizontalLayout">
     <item>
      <widget class="QPushButton" name="addButton">
       <property name="sizePolicy">
        <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
         <horstretch>0</horstretch>
         <verstretch>0</verstretch>
        </sizepolicy>
       </property>
       <property name="text">
        <string>Add</string>
       </property>
      </widget>
     </item>
     <item>
      <widget class="QPushButton" name="removeButton">
       <property name="text">
        <string>Remove</string>
       </property>
      </widget>
     </item>
     <item>
      <spacer name="horizontalSpacer">
       <property name="orientation">
        <enum>Qt::Horizontal</enum>
       </property>
       <property name="sizeHint" stdset="0">
        <size>
         <width>40</width>
         <height>20</height>
        </size>
       </property>
      </spacer>
     </item>
    </layout>
   </item>
   <item>
    <widget class="QGroupBox" name="groupBox">
     <property name="title">
      <string>Properties</string>
     </property>
     <layout class="QFormLayout" name="formLayout">
      <property name="sizeConstraint">
       <enum>QLayout::SetMinAndMaxSize</enum>
      </property>
      <property name="fieldGrowthPolicy">
       <enum>QFormLayout::ExpandingFieldsGrow</enum>
      </property>
      <item row="0" column="0">
       <widget class="QLabel" name="aliasLabel">
        <property name="text">
         <string>Alias:</string>
        </property>
       </widget>
      </item>
      <item row="0" column="1">
       <widget class="QLineEdit" name="aliasText"/>
      </item>
      <item row="1" column="0">
       <widget class="QLabel" name="prefixLabel">
        <property name="text">
         <string>Prefix:</string>
        </property>
       </widget>
      </item>
      <item row="1" column="1">
       <widget class="QLineEdit" name="prefixText"/>
      </item>
      <item row="2" column="0">
       <widget class="QLabel" name="languageLabel">
        <property name="text">
         <string>Language:</string>
        </property>
       </widget>
      </item>
      <item row="2" column="1">
       <widget class="QLineEdit" name="languageText"/>
      </item>
      <item row="3" column="0">
       <widget class="QLabel" name="urlLabel">
        <property name="text">
         <string>Resource URL:</string>
        </property>
       </widget>
      </item>
      <item row="3" column="1">
       <widget class="QLineEdit" name="urlText">
        <property name="readOnly">
         <bool>true</bool>
        </property>
       </widget>
      </item>
     </layout>
    </widget>
   </item>
  </layout>
 </widget>
 <resources/>
 <connections/>
</ui>
QrcEditor/shared/resourcefile.cpp
New file
@@ -0,0 +1,992 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "resourcefile_p.h"
#include <QCoreApplication>
#include <QDebug>
#include <QDir>
#include <QFile>
#include <QMimeData>
#include <QtAlgorithms>
#include <QTextStream>
#include <QIcon>
#include <QImageReader>
#include <QDomDocument>
QT_BEGIN_NAMESPACE
/*
TRANSLATOR qdesigner_internal::ResourceModel
*/
static QString msgFileNameEmpty()
{
    return QCoreApplication::translate("Designer", "The file name is empty.");
}
namespace qdesigner_internal {
/******************************************************************************
** FileList
*/
bool FileList::containsFile(File *file)
{
    foreach (const File *tmpFile, *this)
        if (tmpFile->name == file->name && tmpFile->prefix() == file->prefix())
            return true;
    return false;
}
/******************************************************************************
** ResourceFile
*/
ResourceFile::ResourceFile(const QString &file_name)
{
    setFileName(file_name);
}
ResourceFile::~ResourceFile()
{
    clearPrefixList();
}
bool ResourceFile::load()
{
    m_error_message.clear();
    if (m_file_name.isEmpty()) {
        m_error_message = msgFileNameEmpty();
        return false;
    }
    QFile file(m_file_name);
    if (!file.open(QIODevice::ReadOnly)) {
        m_error_message = file.errorString();
        return false;
    }
    clearPrefixList();
    QDomDocument doc;
    QString error_msg;
    int error_line, error_col;
    if (!doc.setContent(&file, &error_msg, &error_line, &error_col)) {
        m_error_message = QCoreApplication::translate("Designer", "XML error on line %1, col %2: %3")
                    .arg(error_line).arg(error_col).arg(error_msg);
        return false;
    }
    QDomElement root = doc.firstChildElement(QLatin1String("RCC"));
    if (root.isNull()) {
        m_error_message = QCoreApplication::translate("Designer", "The <RCC> root element is missing.");
        return false;
    }
    QDomElement relt = root.firstChildElement(QLatin1String("qresource"));
    for (; !relt.isNull(); relt = relt.nextSiblingElement(QLatin1String("qresource"))) {
        QString prefix = fixPrefix(relt.attribute(QLatin1String("prefix")));
        if (prefix.isEmpty())
            prefix = QString(QLatin1Char('/'));
        const QString language = relt.attribute(QLatin1String("lang"));
        const int idx = indexOfPrefix(prefix);
        Prefix * p = 0;
        if (idx == -1) {
            p = new Prefix(prefix, language);
            m_prefix_list.append(p);
        } else {
            p = m_prefix_list[idx];
        }
        Q_ASSERT(p);
        QDomElement felt = relt.firstChildElement(QLatin1String("file"));
        for (; !felt.isNull(); felt = felt.nextSiblingElement(QLatin1String("file"))) {
            const QString fileName = absolutePath(felt.text());
            const QString alias = felt.attribute(QLatin1String("alias"));
            File * const file = new File(p, fileName, alias);
            p->file_list.append(file);
        }
    }
    return true;
}
bool ResourceFile::save()
{
    m_error_message.clear();
    if (m_file_name.isEmpty()) {
        m_error_message = msgFileNameEmpty();
        return false;
    }
    QFile file(m_file_name);
    if (!file.open(QIODevice::WriteOnly)) {
        m_error_message = file.errorString();
        return false;
    }
    QDomDocument doc;
    QDomElement root = doc.createElement(QLatin1String("RCC"));
    doc.appendChild(root);
    const QStringList name_list = prefixList();
    foreach (const QString &name, name_list) {
        FileList file_list;
        QString lang;
        foreach (const Prefix *pref, m_prefix_list) {
            if (pref->name == name){
                file_list += pref->file_list;
                lang = pref->lang;
            }
        }
        QDomElement relt = doc.createElement(QLatin1String("qresource"));
        root.appendChild(relt);
        relt.setAttribute(QLatin1String("prefix"), name);
        if (!lang.isEmpty())
            relt.setAttribute(QLatin1String("lang"), lang);
        foreach (const File *f, file_list) {
            const File &file = *f;
            QDomElement felt = doc.createElement(QLatin1String("file"));
            relt.appendChild(felt);
            const QString conv_file = relativePath(file.name).replace(QDir::separator(), QLatin1Char('/'));
            const QDomText text = doc.createTextNode(conv_file);
            felt.appendChild(text);
            if (!file.alias.isEmpty())
                felt.setAttribute(QLatin1String("alias"), file.alias);
        }
    }
    QTextStream stream(&file);
    doc.save(stream, 4);
    return true;
}
bool ResourceFile::split(const QString &_path, QString *prefix, QString *file) const
{
    prefix->clear();
    file->clear();
    QString path = _path;
    if (!path.startsWith(QLatin1Char(':')))
        return false;
    path = path.mid(1);
    for (int i = 0; i < m_prefix_list.size(); ++i) {
        Prefix const * const &pref = m_prefix_list.at(i);
        if (!path.startsWith(pref->name))
            continue;
        *prefix = pref->name;
        if (pref->name == QString(QLatin1Char('/')))
            *file = path.mid(1);
        else
            *file = path.mid(pref->name.size() + 1);
        const QString filePath = absolutePath(*file);
        for (int j = 0; j < pref->file_list.count(); j++) {
            File const * const &f = pref->file_list.at(j);
            if (!f->alias.isEmpty()) {
                if (absolutePath(f->alias) == filePath) {
                    *file = f->name;
                    return true;
                }
            } else if (f->name == filePath)
                return true;
        }
    }
    return false;
}
QString ResourceFile::resolvePath(const QString &path) const
{
    QString prefix, file;
    if (split(path, &prefix, &file))
        return absolutePath(file);
    return QString();
}
QStringList ResourceFile::prefixList() const
{
    QStringList result;
    for (int i = 0; i < m_prefix_list.size(); ++i)
        result.append(m_prefix_list.at(i)->name);
    return result;
}
bool ResourceFile::isEmpty() const
{
    return m_file_name.isEmpty() && m_prefix_list.isEmpty();
}
QStringList ResourceFile::fileList(int pref_idx) const
{
    QStringList result;
    Q_ASSERT(pref_idx >= 0 && pref_idx < m_prefix_list.count());
    const FileList &abs_file_list = m_prefix_list.at(pref_idx)->file_list;
    foreach (const File *abs_file, abs_file_list)
        result.append(relativePath(abs_file->name));
    return result;
}
void ResourceFile::addFile(int prefix_idx, const QString &file, int file_idx)
{
    Prefix * const p = m_prefix_list[prefix_idx];
    Q_ASSERT(p);
    FileList &files = p->file_list;
    Q_ASSERT(file_idx >= -1 && file_idx <= files.size());
    if (file_idx == -1)
        file_idx = files.size();
    files.insert(file_idx, new File(p, absolutePath(file)));
}
void ResourceFile::addPrefix(const QString &prefix, int prefix_idx)
{
    QString fixed_prefix = fixPrefix(prefix);
    if (indexOfPrefix(fixed_prefix) != -1)
        return;
    Q_ASSERT(prefix_idx >= -1 && prefix_idx <= m_prefix_list.size());
    if (prefix_idx == -1)
        prefix_idx = m_prefix_list.size();
    m_prefix_list.insert(prefix_idx, new Prefix(fixed_prefix));
}
void ResourceFile::removePrefix(int prefix_idx)
{
    Q_ASSERT(prefix_idx >= 0 && prefix_idx < m_prefix_list.count());
    Prefix * const p = m_prefix_list.at(prefix_idx);
    delete p;
    m_prefix_list.removeAt(prefix_idx);
}
void ResourceFile::removeFile(int prefix_idx, int file_idx)
{
    Q_ASSERT(prefix_idx >= 0 && prefix_idx < m_prefix_list.count());
    FileList &fileList = m_prefix_list[prefix_idx]->file_list;
    Q_ASSERT(file_idx >= 0 && file_idx < fileList.count());
    delete fileList.at(file_idx);
    fileList.removeAt(file_idx);
}
void ResourceFile::replacePrefix(int prefix_idx, const QString &prefix)
{
    Q_ASSERT(prefix_idx >= 0 && prefix_idx < m_prefix_list.count());
    m_prefix_list[prefix_idx]->name = fixPrefix(prefix);
}
void ResourceFile::replaceLang(int prefix_idx, const QString &lang)
{
    Q_ASSERT(prefix_idx >= 0 && prefix_idx < m_prefix_list.count());
    m_prefix_list[prefix_idx]->lang = lang;
}
void ResourceFile::replaceAlias(int prefix_idx, int file_idx, const QString &alias)
{
    Q_ASSERT(prefix_idx >= 0 && prefix_idx < m_prefix_list.count());
    FileList &fileList = m_prefix_list.at(prefix_idx)->file_list;
    Q_ASSERT(file_idx >= 0 && file_idx < fileList.count());
    fileList[file_idx]->alias = alias;
}
void ResourceFile::replaceFile(int pref_idx, int file_idx, const QString &file)
{
    Q_ASSERT(pref_idx >= 0 && pref_idx < m_prefix_list.count());
    FileList &fileList = m_prefix_list.at(pref_idx)->file_list;
    Q_ASSERT(file_idx >= 0 && file_idx < fileList.count());
    fileList[file_idx]->name = file;
}
int ResourceFile::indexOfPrefix(const QString &prefix) const
{
    QString fixed_prefix = fixPrefix(prefix);
    for (int i = 0; i < m_prefix_list.size(); ++i) {
        if (m_prefix_list.at(i)->name == fixed_prefix)
            return i;
    }
    return -1;
}
int ResourceFile::indexOfFile(int pref_idx, const QString &file) const
{
    Q_ASSERT(pref_idx >= 0 && pref_idx < m_prefix_list.count());
    Prefix * const p = m_prefix_list.at(pref_idx);
    File equalFile(p, absolutePath(file));
    return p->file_list.indexOf(&equalFile);
}
QString ResourceFile::relativePath(const QString &abs_path) const
{
    if (m_file_name.isEmpty() || QFileInfo(abs_path).isRelative())
         return abs_path;
    QFileInfo fileInfo(m_file_name);
    return fileInfo.absoluteDir().relativeFilePath(abs_path);
}
QString ResourceFile::absolutePath(const QString &rel_path) const
{
    const QFileInfo fi(rel_path);
    if (fi.isAbsolute())
        return rel_path;
    QString rc = QFileInfo(m_file_name).path();
    rc +=  QDir::separator();
    rc += rel_path;
    return QDir::cleanPath(rc);
}
bool ResourceFile::contains(const QString &prefix, const QString &file) const
{
    int pref_idx = indexOfPrefix(prefix);
    if (pref_idx == -1)
        return false;
    if (file.isEmpty())
        return true;
    Q_ASSERT(pref_idx >= 0 && pref_idx < m_prefix_list.count());
    Prefix * const p = m_prefix_list.at(pref_idx);
    Q_ASSERT(p);
    File equalFile(p, absolutePath(file));
    return p->file_list.containsFile(&equalFile);
}
bool ResourceFile::contains(int pref_idx, const QString &file) const
{
    Q_ASSERT(pref_idx >= 0 && pref_idx < m_prefix_list.count());
    Prefix * const p = m_prefix_list.at(pref_idx);
    File equalFile(p, absolutePath(file));
    return p->file_list.containsFile(&equalFile);
}
/*static*/ QString ResourceFile::fixPrefix(const QString &prefix)
{
    const QChar slash = QLatin1Char('/');
    QString result = QString(slash);
    for (int i = 0; i < prefix.size(); ++i) {
        const QChar c = prefix.at(i);
        if (c == slash && result.at(result.size() - 1) == slash)
            continue;
        result.append(c);
    }
    if (result.size() > 1 && result.endsWith(slash))
        result = result.mid(0, result.size() - 1);
    return result;
}
int ResourceFile::prefixCount() const
{
    return m_prefix_list.size();
}
QString ResourceFile::prefix(int idx) const
{
    Q_ASSERT((idx >= 0) && (idx < m_prefix_list.count()));
    return m_prefix_list.at(idx)->name;
}
QString ResourceFile::lang(int idx) const
{
    Q_ASSERT(idx >= 0 && idx < m_prefix_list.count());
    return m_prefix_list.at(idx)->lang;
}
int ResourceFile::fileCount(int prefix_idx) const
{
    Q_ASSERT(prefix_idx >= 0 && prefix_idx < m_prefix_list.count());
    return m_prefix_list.at(prefix_idx)->file_list.size();
}
QString ResourceFile::file(int prefix_idx, int file_idx) const
{
    Q_ASSERT(prefix_idx >= 0 && prefix_idx < m_prefix_list.count());
    FileList &fileList = m_prefix_list.at(prefix_idx)->file_list;
    Q_ASSERT(file_idx >= 0 && file_idx < fileList.count());
    return fileList.at(file_idx)->name;
}
QString ResourceFile::alias(int prefix_idx, int file_idx) const
{
    Q_ASSERT(prefix_idx >= 0 && prefix_idx < m_prefix_list.count());
    FileList &fileList = m_prefix_list.at(prefix_idx)->file_list;
    Q_ASSERT(file_idx >= 0 && file_idx < fileList.count());
    return fileList.at(file_idx)->alias;
}
void * ResourceFile::prefixPointer(int prefixIndex) const
{
    Q_ASSERT(prefixIndex >= 0 && prefixIndex < m_prefix_list.count());
    return m_prefix_list.at(prefixIndex);
}
void * ResourceFile::filePointer(int prefixIndex, int fileIndex) const
{
    Q_ASSERT(prefixIndex >= 0 && prefixIndex < m_prefix_list.count());
    FileList &fileList = m_prefix_list.at(prefixIndex)->file_list;
    Q_ASSERT(fileIndex >= 0 && fileIndex < fileList.count());
    return fileList.at(fileIndex);
}
int ResourceFile::prefixPointerIndex(const Prefix *prefix) const
{
    int const count = m_prefix_list.count();
    for (int i = 0; i < count; i++) {
        Prefix * const other = m_prefix_list.at(i);
        if (*other == *prefix)
            return i;
    }
    return -1;
}
void ResourceFile::clearPrefixList()
{
    qDeleteAll(m_prefix_list);
    m_prefix_list.clear();
}
/******************************************************************************
** ResourceModel
*/
ResourceModel::ResourceModel(const ResourceFile &resource_file, QObject *parent)
    : QAbstractItemModel(parent), m_resource_file(resource_file),  m_dirty(false)
{
}
void ResourceModel::setDirty(bool b)
{
    if (b == m_dirty)
        return;
    m_dirty = b;
    emit dirtyChanged(b);
}
QModelIndex ResourceModel::index(int row, int column, const QModelIndex &parent) const
{
    if (column != 0)
        return QModelIndex();
    void * internalPointer = 0;
    if (parent.isValid()) {
        void * const pip = parent.internalPointer();
        if (pip == 0)
            return QModelIndex();
        // File node
        Node * const node = reinterpret_cast<Node *>(pip);
        Prefix * const prefix = node->prefix();
        Q_ASSERT(prefix);
        if (row < 0 || row >= prefix->file_list.count())
            return QModelIndex();
        const int prefixIndex = m_resource_file.prefixPointerIndex(prefix);
        const int fileIndex = row;
        internalPointer = m_resource_file.filePointer(prefixIndex, fileIndex);
    } else {
        // Prefix node
        if (row < 0 || row >= m_resource_file.prefixCount())
            return QModelIndex();
        internalPointer = m_resource_file.prefixPointer(row);
    }
    Q_ASSERT(internalPointer);
    return createIndex(row, 0, internalPointer);
}
QModelIndex ResourceModel::parent(const QModelIndex &index) const
{
    if (!index.isValid())
        return QModelIndex();
    void * const internalPointer = index.internalPointer();
    if (internalPointer == 0)
        return QModelIndex();
    Node * const node = reinterpret_cast<Node *>(internalPointer);
    Prefix * const prefix = node->prefix();
    Q_ASSERT(prefix);
    bool const isFileNode = (prefix != node);
    if (isFileNode) {
        const int row = m_resource_file.prefixPointerIndex(prefix);
        Q_ASSERT(row >= 0);
        return createIndex(row, 0, prefix);
    } else {
        return QModelIndex();
    }
}
int ResourceModel::rowCount(const QModelIndex &parent) const
{
    if (parent.isValid()) {
        void * const internalPointer = parent.internalPointer();
        Node * const node = reinterpret_cast<Node *>(internalPointer);
        Prefix * const prefix = node->prefix();
        Q_ASSERT(prefix);
        bool const isFileNode = (prefix != node);
        if (isFileNode) {
            return 0;
        } else {
            return prefix->file_list.count();
        }
    } else {
        return m_resource_file.prefixCount();
    }
}
int ResourceModel::columnCount(const QModelIndex &) const
{
    return 1;
}
bool ResourceModel::hasChildren(const QModelIndex &parent) const
{
    return rowCount(parent) != 0;
}
Qt::DropActions ResourceModel::supportedDropActions() const
{
    // Only action that works for QListWidget and the like.
    return Qt::CopyAction;
}
bool ResourceModel::iconFileExtension(const QString &path)
{
    static QStringList ext_list;
    if (ext_list.isEmpty()) {
        const QList<QByteArray> _ext_list = QImageReader::supportedImageFormats();
        foreach (const QByteArray &ext, _ext_list) {
            QString dotExt = QString(QLatin1Char('.'));
            dotExt  += QString::fromLocal8Bit(ext);
            ext_list.append(dotExt);
        }
    }
    foreach (const QString &ext, ext_list) {
        if (path.endsWith(ext, Qt::CaseInsensitive))
            return true;
    }
    return false;
}
static inline void appendParenthesized(const QString &what, QString &s)
{
    s += QLatin1String(" (");
    s += what;
    s += QLatin1Char(')');
}
QVariant ResourceModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid())
        return QVariant();
    const void *internalPointer = index.internalPointer();
    const Node *node = reinterpret_cast<const Node *>(internalPointer);
    const Prefix *prefix = node->prefix();
    File *file = node->file();
    Q_ASSERT(prefix);
    const bool isFileNode = (prefix != node);
    QVariant result;
    switch (role) {
    case Qt::DisplayRole:
        {
            QString stringRes;
            if (!isFileNode) {
                // Prefix node
                stringRes = prefix->name;
                const QString &lang = prefix->lang;
                if (!lang.isEmpty())
                    appendParenthesized(lang, stringRes);
            } else  {
                // File node
                Q_ASSERT(file);
                QString conv_file = m_resource_file.relativePath(file->name);
                stringRes = conv_file.replace(QDir::separator(), QLatin1Char('/'));
                const QString alias = file->alias;
                if (!alias.isEmpty())
                    appendParenthesized(alias, stringRes);
            }
            result = stringRes;
        }
        break;
    case Qt::DecorationRole:
        if (isFileNode) {
            // File node
            Q_ASSERT(file);
            if (file->icon.isNull()) {
                const QString path = m_resource_file.absolutePath(file->name);
                if (iconFileExtension(path))
                    file->icon = QIcon(path);
            }
            if (!file->icon.isNull())
                result = file->icon;
        }
        break;
    default:
        break;
    }
    return result;
}
void ResourceModel::getItem(const QModelIndex &index, QString &prefix, QString &file) const
{
    prefix.clear();
    file.clear();
    if (!index.isValid())
        return;
    const void *internalPointer = index.internalPointer();
    const Node *node = reinterpret_cast<const Node *>(internalPointer);
    const Prefix *p = node->prefix();
    Q_ASSERT(p);
    const bool isFileNode = (p != node);
    if (isFileNode) {
        const File *f = node->file();
        Q_ASSERT(f);
        if (!f->alias.isEmpty())
            file = f->alias;
        else
            file = f->name;
    } else {
        prefix = p->name;
    }
}
QString ResourceModel::lang(const QModelIndex &index) const
{
    if (!index.isValid())
        return QString();
    return m_resource_file.lang(index.row());
}
QString ResourceModel::alias(const QModelIndex &index) const
{
    if (!index.isValid() || !index.parent().isValid())
        return QString();
    return m_resource_file.alias(index.parent().row(), index.row());
}
QString ResourceModel::file(const QModelIndex &index) const
{
    if (!index.isValid() || !index.parent().isValid())
        return QString();
    return m_resource_file.file(index.parent().row(), index.row());
}
QModelIndex ResourceModel::getIndex(const QString &prefixed_file)
{
    QString prefix, file;
    if (!m_resource_file.split(prefixed_file, &prefix, &file))
        return QModelIndex();
    return getIndex(prefix, file);
}
QModelIndex ResourceModel::getIndex(const QString &prefix, const QString &file)
{
    if (prefix.isEmpty())
        return QModelIndex();
    const int pref_idx = m_resource_file.indexOfPrefix(prefix);
    if (pref_idx == -1)
        return QModelIndex();
    const QModelIndex pref_model_idx = index(pref_idx, 0, QModelIndex());
    if (file.isEmpty())
        return pref_model_idx;
    const int file_idx = m_resource_file.indexOfFile(pref_idx, file);
    if (file_idx == -1)
        return QModelIndex();
    return index(file_idx, 0, pref_model_idx);
}
QModelIndex ResourceModel::prefixIndex(const QModelIndex &sel_idx) const
{
    if (!sel_idx.isValid())
        return QModelIndex();
    const QModelIndex parentIndex = parent(sel_idx);
    return parentIndex.isValid() ? parentIndex : sel_idx;
}
QModelIndex ResourceModel::addNewPrefix()
{
    const QString format = QLatin1String("/new/prefix%1");
    int i = 1;
    QString prefix = format.arg(i);
    for ( ; m_resource_file.contains(prefix); i++)
        prefix = format.arg(i);
    i = rowCount(QModelIndex());
    beginInsertRows(QModelIndex(), i, i);
    m_resource_file.addPrefix(prefix);
    endInsertRows();
    setDirty(true);
    return index(i, 0, QModelIndex());
}
QModelIndex ResourceModel::addFiles(const QModelIndex &model_idx, const QStringList &file_list)
{
    const QModelIndex prefixModelIndex = prefixIndex(model_idx);
    const int prefixArrayIndex = prefixModelIndex.row();
    const int cursorFileArrayIndex = (prefixModelIndex == model_idx) ? 0 : model_idx.row();
    int dummy;
    int lastFileArrayIndex;
    addFiles(prefixArrayIndex, file_list, cursorFileArrayIndex, dummy, lastFileArrayIndex);
    return index(lastFileArrayIndex, 0, prefixModelIndex);
}
void ResourceModel::addFiles(int prefixIndex, const QStringList &fileNames, int cursorFile,
        int &firstFile, int &lastFile)
{
    Q_UNUSED(cursorFile)
    const QModelIndex prefix_model_idx = index(prefixIndex, 0, QModelIndex());
    const QStringList &file_list = fileNames;
    firstFile = -1;
    lastFile = -1;
    if (!prefix_model_idx.isValid()) {
        return;
    }
    const int prefix_idx = prefixIndex;
    QStringList unique_list;
    foreach (const QString &file, file_list) {
        if (!m_resource_file.contains(prefix_idx, file) && !unique_list.contains(file))
            unique_list.append(file);
    }
    if (unique_list.isEmpty()) {
        return;
    }
    const int cnt = m_resource_file.fileCount(prefix_idx);
    beginInsertRows(prefix_model_idx, cnt, cnt + unique_list.count() - 1); // ### FIXME
    foreach (const QString &file, unique_list)
        m_resource_file.addFile(prefix_idx, file);
    const QFileInfo fi(file_list.last());
    m_lastResourceDir = fi.absolutePath();
    endInsertRows();
    setDirty(true);
    firstFile = cnt;
    lastFile = cnt + unique_list.count() - 1;
}
void ResourceModel::insertPrefix(int prefixIndex, const QString &prefix,
        const QString &lang)
{
    beginInsertRows(QModelIndex(), prefixIndex, prefixIndex);
    m_resource_file.addPrefix(prefix, prefixIndex);
    m_resource_file.replaceLang(prefixIndex, lang);
    endInsertRows();
    setDirty(true);
}
void ResourceModel::insertFile(int prefixIndex, int fileIndex,
        const QString &fileName, const QString &alias)
{
    const QModelIndex parent = index(prefixIndex, 0, QModelIndex());
    beginInsertRows(parent, fileIndex, fileIndex);
    m_resource_file.addFile(prefixIndex, fileName, fileIndex);
    m_resource_file.replaceAlias(prefixIndex, fileIndex, alias);
    endInsertRows();
    setDirty(true);
}
void ResourceModel::changePrefix(const QModelIndex &model_idx, const QString &prefix)
{
    if (!model_idx.isValid())
        return;
    const QModelIndex prefix_model_idx = prefixIndex(model_idx);
    const int prefix_idx = model_idx.row();
    if (m_resource_file.prefix(prefix_idx) == ResourceFile::fixPrefix(prefix))
        return;
    if (m_resource_file.contains(prefix))
        return;
    m_resource_file.replacePrefix(prefix_idx, prefix);
    emit dataChanged(prefix_model_idx, prefix_model_idx);
    setDirty(true);
}
void ResourceModel::changeLang(const QModelIndex &model_idx, const QString &lang)
{
    if (!model_idx.isValid())
        return;
    const QModelIndex prefix_model_idx = prefixIndex(model_idx);
    const int prefix_idx = model_idx.row();
    if (m_resource_file.lang(prefix_idx) == lang)
        return;
    m_resource_file.replaceLang(prefix_idx, lang);
    emit dataChanged(prefix_model_idx, prefix_model_idx);
    setDirty(true);
}
void ResourceModel::changeAlias(const QModelIndex &index, const QString &alias)
{
    if (!index.parent().isValid())
        return;
    if (m_resource_file.alias(index.parent().row(), index.row()) == alias)
        return;
    m_resource_file.replaceAlias(index.parent().row(), index.row(), alias);
    emit dataChanged(index, index);
    setDirty(true);
}
QModelIndex ResourceModel::deleteItem(const QModelIndex &idx)
{
    if (!idx.isValid())
        return QModelIndex();
    QString dummy, file;
    getItem(idx, dummy, file);
    int prefix_idx = -1;
    int file_idx = -1;
    beginRemoveRows(parent(idx), idx.row(), idx.row());
    if (file.isEmpty()) {
        // Remove prefix
        prefix_idx = idx.row();
        m_resource_file.removePrefix(prefix_idx);
        if (prefix_idx == m_resource_file.prefixCount())
            --prefix_idx;
    } else {
        // Remove file
        prefix_idx = prefixIndex(idx).row();
        file_idx = idx.row();
        m_resource_file.removeFile(prefix_idx, file_idx);
        if (file_idx == m_resource_file.fileCount(prefix_idx))
            --file_idx;
    }
    endRemoveRows();
    setDirty(true);
    if (prefix_idx == -1)
        return QModelIndex();
    const QModelIndex prefix_model_idx = index(prefix_idx, 0, QModelIndex());
    if (file_idx == -1)
        return prefix_model_idx;
    return index(file_idx, 0, prefix_model_idx);
}
bool ResourceModel::reload()
{
    beginResetModel();
    const bool result = m_resource_file.load();
    if (result)
        setDirty(false);
    endResetModel();
    return result;
}
bool ResourceModel::save()
{
    const bool result = m_resource_file.save();
    if (result)
        setDirty(false);
    return result;
}
QString ResourceModel::lastResourceOpenDirectory() const
{
    if (m_lastResourceDir.isEmpty())
        return absolutePath(QString());
    return m_lastResourceDir;
}
// Create a resource path 'prefix:/file'
QString ResourceModel::resourcePath(const QString &prefix, const QString &file)
{
    QString rc = QString(QLatin1Char(':'));
    rc += prefix;
    rc += QLatin1Char('/');
    rc += file;
    return QDir::cleanPath(rc);
}
QMimeData *ResourceModel::mimeData(const QModelIndexList &indexes) const
{
    if (indexes.size() != 1)
        return 0;
    QString prefix, file;
    getItem(indexes.front(), prefix, file);
    if (prefix.isEmpty() || file.isEmpty())
        return 0;
    // DnD format of Designer 4.4
    QDomDocument doc;
    QDomElement elem = doc.createElement(QLatin1String("resource"));
    elem.setAttribute(QLatin1String("type"), QLatin1String("image"));
    elem.setAttribute(QLatin1String("file"), resourcePath(prefix, file));
    doc.appendChild(elem);
    QMimeData *rc = new QMimeData;
    rc->setText(doc.toString());
    return rc;
}
} // namespace qdesigner_internal
QT_END_NAMESPACE
QrcEditor/shared/resourcefile_p.h
New file
@@ -0,0 +1,262 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef RESOURCEFILE_P_H
#define RESOURCEFILE_P_H
#include <QtCore/QAbstractItemModel>
#include <QtCore/QMap>
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtGui/QIcon>
QT_BEGIN_NAMESPACE
namespace qdesigner_internal {
struct File;
struct Prefix;
/*!
    \class Node
    Forms the base class for nodes in a \l ResourceFile tree.
*/
class Node
{
protected:
    Node(File *file, Prefix *prefix) : m_file(file), m_prefix(prefix)
    {
        Q_ASSERT(m_prefix);
    }
public:
    File *file() const { return m_file; }
    Prefix *prefix() const { return m_prefix; }
private:
    File *m_file;
    Prefix *m_prefix;
};
/*!
    \class File
    Represents a file node in a \l ResourceFile tree.
*/
struct File : public Node {
    File(Prefix *prefix, const QString &_name = QString(), const QString &_alias = QString())
        : Node(this, prefix), name(_name), alias(_alias) {}
    bool operator < (const File &other) const { return name < other.name; }
    bool operator == (const File &other) const { return name == other.name; }
    bool operator != (const File &other) const { return name != other.name; }
    QString name;
    QString alias;
    QIcon icon;
};
class FileList : public QList<File *>
{
public:
    bool containsFile(File *file);
};
/*!
    \class Prefix
    Represents a prefix node in a \l ResourceFile tree.
*/
struct Prefix : public Node
{
    Prefix(const QString &_name = QString(), const QString &_lang = QString(), const FileList &_file_list = FileList())
        : Node(NULL, this), name(_name), lang(_lang), file_list(_file_list) {}
    ~Prefix()
    {
        qDeleteAll(file_list);
        file_list.clear();
    }
    bool operator == (const Prefix &other) const { return (name == other.name) && (lang == other.lang); }
    QString name;
    QString lang;
    FileList file_list;
};
typedef QList<Prefix *> PrefixList;
/*!
    \class ResourceFile
    Represents the structure of a Qt Resource File (.qrc) file.
*/
class ResourceFile
{
public:
    ResourceFile(const QString &file_name = QString());
    ~ResourceFile();
    void setFileName(const QString &file_name) { m_file_name = file_name; }
    QString fileName() const { return m_file_name; }
    bool load();
    bool save();
    QString errorMessage() const { return m_error_message; }
private:
    QString resolvePath(const QString &path) const;
    QStringList prefixList() const;
    QStringList fileList(int pref_idx) const;
public:
    int prefixCount() const;
    QString prefix(int idx) const;
    QString lang(int idx) const;
    int fileCount(int prefix_idx) const;
    QString file(int prefix_idx, int file_idx) const;
    QString alias(int prefix_idx, int file_idx) const;
    void addFile(int prefix_idx, const QString &file, int file_idx = -1);
    void addPrefix(const QString &prefix, int prefix_idx = -1);
    void removePrefix(int prefix_idx);
    void removeFile(int prefix_idx, int file_idx);
    void replacePrefix(int prefix_idx, const QString &prefix);
    void replaceLang(int prefix_idx, const QString &lang);
    void replaceAlias(int prefix_idx, int file_idx, const QString &alias);
private:
    void replaceFile(int pref_idx, int file_idx, const QString &file);
public:
    int indexOfPrefix(const QString &prefix) const;
    int indexOfFile(int pref_idx, const QString &file) const;
    bool contains(const QString &prefix, const QString &file = QString()) const;
    bool contains(int pref_idx, const QString &file) const;
    QString relativePath(const QString &abs_path) const;
    QString absolutePath(const QString &rel_path) const;
    static QString fixPrefix(const QString &prefix);
    bool split(const QString &path, QString *prefix, QString *file) const;
private:
    bool isEmpty() const;
private:
    PrefixList m_prefix_list;
    QString m_file_name;
    QString m_error_message;
public:
    void * prefixPointer(int prefixIndex) const;
    void * filePointer(int prefixIndex, int fileIndex) const;
    int prefixPointerIndex(const Prefix *prefix) const;
private:
    void clearPrefixList();
};
/*!
    \class ResourceModel
    Wraps a \l ResourceFile as a single-column tree model.
*/
class ResourceModel : public QAbstractItemModel
{
    Q_OBJECT
public:
    ResourceModel(const ResourceFile &resource_file, QObject *parent = 0);
    QModelIndex index(int row, int column,
                        const QModelIndex &parent = QModelIndex()) const;
    QModelIndex parent(const QModelIndex &index) const;
    int rowCount(const QModelIndex &parent) const;
    int columnCount(const QModelIndex &parent) const;
    bool hasChildren(const QModelIndex &parent) const;
    Qt::DropActions supportedDropActions() const;
protected:
    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
public:
    QString fileName() const { return m_resource_file.fileName(); }
    void setFileName(const QString &file_name) { m_resource_file.setFileName(file_name); }
    void getItem(const QModelIndex &index, QString &prefix, QString &file) const;
    QString lang(const QModelIndex &index) const;
    QString alias(const QModelIndex &index) const;
    QString file(const QModelIndex &index) const;
    virtual QModelIndex addNewPrefix();
    virtual QModelIndex addFiles(const QModelIndex &idx, const QStringList &file_list);
    void addFiles(int prefixIndex, const QStringList &fileNames, int cursorFile, int &firstFile, int &lastFile);
    void insertPrefix(int prefixIndex, const QString &prefix, const QString &lang);
    void insertFile(int prefixIndex, int fileIndex, const QString &fileName, const QString &alias);
    virtual void changePrefix(const QModelIndex &idx, const QString &prefix);
    virtual void changeLang(const QModelIndex &idx, const QString &lang);
    virtual void changeAlias(const QModelIndex &idx, const QString &alias);
    virtual QModelIndex deleteItem(const QModelIndex &idx);
    QModelIndex getIndex(const QString &prefix, const QString &file);
    QModelIndex getIndex(const QString &prefixed_file);
    QModelIndex prefixIndex(const QModelIndex &sel_idx) const;
    QString absolutePath(const QString &path) const
        { return m_resource_file.absolutePath(path); }
private:
    QString relativePath(const QString &path) const
        { return m_resource_file.relativePath(path); }
    QString lastResourceOpenDirectory() const;
public:
    virtual bool reload();
    virtual bool save();
    // QString errorMessage() const { return m_resource_file.errorMessage(); }
    bool dirty() const { return m_dirty; }
    void setDirty(bool b);
private:
    virtual QMimeData *mimeData (const QModelIndexList & indexes) const;
    static bool iconFileExtension(const QString &path);
    static QString resourcePath(const QString &prefix, const QString &file);
signals:
    void dirtyChanged(bool b);
private:
    ResourceFile m_resource_file;
    bool m_dirty;
    QString m_lastResourceDir;
};
} // namespace qdesigner_internal
QT_END_NAMESPACE
#endif // RESOURCEFILE_P_H
QrcEditor/shared/resourceview.cpp
New file
@@ -0,0 +1,663 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "resourceview.h"
#include "undocommands_p.h"
#include <QtCore/QDebug>
#include <QtWidgets/QAction>
#include <QtWidgets/QApplication>
#include <QtWidgets/QFileDialog>
#include <QtWidgets/QHeaderView>
#include <QtWidgets/QInputDialog>
#include <QtWidgets/QMenu>
#include <QtGui/QMouseEvent>
#include <QtWidgets/QUndoStack>
namespace SharedTools {
/*!
    \class FileEntryBackup
    Backups a file node.
*/
class FileEntryBackup : public EntryBackup
{
private:
    int m_fileIndex;
    QString m_alias;
public:
    FileEntryBackup(ResourceModel &model, int prefixIndex, int fileIndex,
            const QString &fileName, const QString &alias)
            : EntryBackup(model, prefixIndex, fileName), m_fileIndex(fileIndex),
            m_alias(alias) { }
    void restore() const;
};
void FileEntryBackup::restore() const
{
    m_model->insertFile(m_prefixIndex, m_fileIndex, m_name, m_alias);
}
/*!
    \class PrefixEntryBackup
    Backups a prefix node including children.
*/
class PrefixEntryBackup : public EntryBackup
{
private:
    QString m_language;
    QList<FileEntryBackup> m_files;
public:
    PrefixEntryBackup(ResourceModel &model, int prefixIndex, const QString &prefix,
            const QString &language, const QList<FileEntryBackup> &files)
            : EntryBackup(model, prefixIndex, prefix), m_language(language), m_files(files) { }
    void restore() const;
};
void PrefixEntryBackup::restore() const
{
    m_model->insertPrefix(m_prefixIndex, m_name, m_language);
    foreach (const FileEntryBackup &entry, m_files) {
        entry.restore();
    }
}
namespace Internal {
class RelativeResourceModel : public ResourceModel
{
public:
    RelativeResourceModel(const ResourceFile &resource_file, QObject *parent = 0);
    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const
    {
        if (!index.isValid())
            return QVariant();
/*
        void const * const internalPointer = index.internalPointer();
        if ((role == Qt::DisplayRole) && (internalPointer != NULL))
            return ResourceModel::data(index, Qt::ToolTipRole);
*/
        return ResourceModel::data(index, role);
    }
    void setResourceDragEnabled(bool e) { m_resourceDragEnabled = e; }
    bool resourceDragEnabled() const { return m_resourceDragEnabled; }
    virtual Qt::ItemFlags flags(const QModelIndex &index) const;
    EntryBackup * removeEntry(const QModelIndex &index);
private:
    bool m_resourceDragEnabled;
};
RelativeResourceModel::RelativeResourceModel(const ResourceFile &resource_file, QObject *parent)  :
    ResourceModel(resource_file, parent),
    m_resourceDragEnabled(false)
{
}
Qt::ItemFlags RelativeResourceModel::flags(const QModelIndex &index) const
{
    Qt::ItemFlags rc = ResourceModel::flags(index);
    if ((rc & Qt::ItemIsEnabled) && m_resourceDragEnabled)
        rc |= Qt::ItemIsDragEnabled;
    return rc;
}
EntryBackup * RelativeResourceModel::removeEntry(const QModelIndex &index)
{
    const QModelIndex prefixIndex = this->prefixIndex(index);
    const bool isPrefixNode = (prefixIndex == index);
    // Create backup, remove, return backup
    if (isPrefixNode) {
        QString dummy;
        QString prefixBackup;
        getItem(index, prefixBackup, dummy);
        const QString languageBackup = lang(index);
        const int childCount = rowCount(index);
        QList<FileEntryBackup> filesBackup;
        for (int i = 0; i < childCount; i++) {
            const QModelIndex childIndex = this->index(i, 0, index);
            const QString fileNameBackup = file(childIndex);
            const QString aliasBackup = alias(childIndex);
            FileEntryBackup entry(*this, index.row(), i, fileNameBackup, aliasBackup);
            filesBackup << entry;
        }
        deleteItem(index);
        return new PrefixEntryBackup(*this, index.row(), prefixBackup, languageBackup, filesBackup);
    } else {
        const QString fileNameBackup = file(index);
        const QString aliasBackup = alias(index);
        deleteItem(index);
        return new FileEntryBackup(*this, prefixIndex.row(), index.row(), fileNameBackup, aliasBackup);
    }
}
} // namespace Internal
ResourceView::ResourceView(QUndoStack *history, QWidget *parent) :
    QTreeView(parent),
    m_qrcModel(new Internal::RelativeResourceModel(m_qrcFile, this)),
    m_addFile(0),
    m_editAlias(0),
    m_removeItem(0),
    m_addPrefix(0),
    m_editPrefix(0),
    m_editLang(0),
    m_viewMenu(0),
    m_defaultAddFile(false),
    m_history(history),
    m_mergeId(-1)
{
    advanceMergeId();
    setModel(m_qrcModel);
    header()->hide();
    connect(m_qrcModel, SIGNAL(dirtyChanged(bool)),
        this, SIGNAL(dirtyChanged(bool)));
    setupMenu();
    setDefaultAddFileEnabled(true);
    enableContextMenu(true);
}
ResourceView::~ResourceView()
{
}
void ResourceView::currentChanged(const QModelIndex &current, const QModelIndex &previous)
{
    Q_UNUSED(current)
    Q_UNUSED(previous)
    emit currentIndexChanged();
}
bool ResourceView::isDirty() const
{
    return m_qrcModel->dirty();
}
void ResourceView::setDirty(bool dirty)
{
    m_qrcModel->setDirty(dirty);
}
void ResourceView::setDefaultAddFileEnabled(bool enable)
{
    m_defaultAddFile = enable;
}
bool ResourceView::defaultAddFileEnabled() const
{
    return m_defaultAddFile;
}
void ResourceView::findSamePlacePostDeletionModelIndex(int &row, QModelIndex &parent) const
{
    // Concept:
    // - Make selection stay on same Y level
    // - Enable user to hit delete several times in row
    const bool hasLowerBrother = m_qrcModel->hasIndex(row + 1,
            0, parent);
    if (hasLowerBrother) {
        // First or mid child -> lower brother
        //  o
        //  +--o
        //  +-[o]  <-- deleted
        //  +--o   <-- chosen
        //  o
        // --> return unmodified
    } else {
        if (parent == QModelIndex()) {
            // Last prefix node
            if (row == 0) {
                // Last and only prefix node
                // [o]  <-- deleted
                //  +--o
                //  +--o
                row = -1;
                parent = QModelIndex();
            } else {
                const QModelIndex upperBrother = m_qrcModel->index(row - 1,
                        0, parent);
                if (m_qrcModel->hasChildren(upperBrother)) {
                    //  o
                    //  +--o  <-- selected
                    // [o]    <-- deleted
                    row = m_qrcModel->rowCount(upperBrother) - 1;
                    parent = upperBrother;
                } else {
                    //  o
                    //  o  <-- selected
                    // [o] <-- deleted
                    row--;
                }
            }
        } else {
            // Last file node
            const bool hasPrefixBelow = m_qrcModel->hasIndex(parent.row() + 1,
                    parent.column(), QModelIndex());
            if (hasPrefixBelow) {
                // Last child or parent with lower brother -> lower brother of parent
                //  o
                //  +--o
                //  +-[o]  <-- deleted
                //  o      <-- chosen
                row = parent.row() + 1;
                parent = QModelIndex();
            } else {
                const bool onlyChild = row == 0;
                if (onlyChild) {
                    // Last and only child of last parent -> parent
                    //  o      <-- chosen
                    //  +-[o]  <-- deleted
                    row = parent.row();
                    parent = m_qrcModel->parent(parent);
                } else {
                    // Last child of last parent -> upper brother
                    //  o
                    //  +--o   <-- chosen
                    //  +-[o]  <-- deleted
                    row--;
                }
            }
        }
    }
}
EntryBackup * ResourceView::removeEntry(const QModelIndex &index)
{
    Q_ASSERT(m_qrcModel);
    return m_qrcModel->removeEntry(index);
}
void ResourceView::addFiles(int prefixIndex, const QStringList &fileNames, int cursorFile,
        int &firstFile, int &lastFile)
{
    Q_ASSERT(m_qrcModel);
    m_qrcModel->addFiles(prefixIndex, fileNames, cursorFile, firstFile, lastFile);
    // Expand prefix node
    const QModelIndex prefixModelIndex = m_qrcModel->index(prefixIndex, 0, QModelIndex());
    if (prefixModelIndex.isValid()) {
        this->setExpanded(prefixModelIndex, true);
    }
}
void ResourceView::removeFiles(int prefixIndex, int firstFileIndex, int lastFileIndex)
{
    Q_ASSERT(prefixIndex >= 0 && prefixIndex < m_qrcModel->rowCount(QModelIndex()));
    const QModelIndex prefixModelIndex = m_qrcModel->index(prefixIndex, 0, QModelIndex());
    Q_ASSERT(prefixModelIndex != QModelIndex());
    Q_ASSERT(firstFileIndex >= 0 && firstFileIndex < m_qrcModel->rowCount(prefixModelIndex));
    Q_ASSERT(lastFileIndex >= 0 && lastFileIndex < m_qrcModel->rowCount(prefixModelIndex));
    for (int i = lastFileIndex; i >= firstFileIndex; i--) {
        const QModelIndex index = m_qrcModel->index(i, 0, prefixModelIndex);
        delete removeEntry(index);
    }
}
void ResourceView::enableContextMenu(bool enable)
{
    if (enable) {
        connect(this, SIGNAL(clicked(const QModelIndex &)),
            this, SLOT(popupMenu(const QModelIndex &)));
    } else {
        disconnect(this, SIGNAL(clicked(const QModelIndex &)),
            this, SLOT(popupMenu(const QModelIndex &)));
    }
}
void ResourceView::setupMenu()
{
    m_viewMenu = new QMenu(this);
/*
    m_addFile = m_viewMenu->addAction(tr("Add Files..."), this, SIGNAL(addFiles()));
    m_editAlias = m_viewMenu->addAction(tr("Change Alias..."), this, SLOT(onEditAlias()));
    m_addPrefix = m_viewMenu->addAction(tr("Add Prefix..."), this, SLOT(addPrefix()));
    m_editPrefix = m_viewMenu->addAction(tr("Change Prefix..."), this, SLOT(onEditPrefix()));
    m_editLang = m_viewMenu->addAction(tr("Change Language..."), this, SLOT(onEditLang()));
    m_viewMenu->addSeparator();
    m_removeItem = m_viewMenu->addAction(tr("Remove Item"), this, SLOT(removeItem()));
*/
    m_addFile = m_viewMenu->addAction(tr("Add Files..."), this, SLOT(onAddFiles()));
    m_editAlias = m_viewMenu->addAction(tr("Change Alias..."), this, SLOT(onEditAlias()));
    m_addPrefix = m_viewMenu->addAction(tr("Add Prefix..."), this, SIGNAL(addPrefixTriggered()));
    m_editPrefix = m_viewMenu->addAction(tr("Change Prefix..."), this, SLOT(onEditPrefix()));
    m_editLang = m_viewMenu->addAction(tr("Change Language..."), this, SLOT(onEditLang()));
    m_viewMenu->addSeparator();
    m_removeItem = m_viewMenu->addAction(tr("Remove Item"), this, SIGNAL(removeItem()));
}
void ResourceView::mouseReleaseEvent(QMouseEvent *e)
{
    m_releasePos = e->globalPos();
    if (e->button() != Qt::RightButton)
        m_releasePos = QPoint();
    QTreeView::mouseReleaseEvent(e);
}
void ResourceView::keyPressEvent(QKeyEvent *e)
{
    if (e->key() == Qt::Key_Delete)
        removeItem();
    else
        QTreeView::keyPressEvent(e);
}
void ResourceView::popupMenu(const QModelIndex &index)
{
    if (!m_releasePos.isNull()) {
        m_addFile->setEnabled(index.isValid());
        m_editPrefix->setEnabled(index.isValid());
        m_editLang->setEnabled(index.isValid());
        m_removeItem->setEnabled(index.isValid());
        m_viewMenu->popup(m_releasePos);
    }
}
QModelIndex ResourceView::addPrefix()
{
    const QModelIndex idx = m_qrcModel->addNewPrefix();
    selectionModel()->setCurrentIndex(idx, QItemSelectionModel::ClearAndSelect);
    return idx;
}
QStringList ResourceView::fileNamesToAdd()
{
    return QFileDialog::getOpenFileNames(this, tr("Open File"),
            m_qrcModel->absolutePath(QString()),
            tr("All files (*)"));
}
void ResourceView::onAddFiles()
{
    emit addFilesTriggered(currentPrefix());
}
void ResourceView::addFiles(QStringList fileList, const QModelIndex &index)
{
    if (fileList.isEmpty())
        return;
    QModelIndex idx = index;
    if (!m_qrcModel->hasChildren(QModelIndex())) {
        idx = addPrefix();
        expand(idx);
    }
    idx = m_qrcModel->addFiles(idx, fileList);
    if (idx.isValid()) {
        const QModelIndex preindex = m_qrcModel->prefixIndex(index);
        setExpanded(preindex, true);
        selectionModel()->setCurrentIndex(idx, QItemSelectionModel::ClearAndSelect);
        QString prefix, file;
        m_qrcModel->getItem(preindex, prefix, file);
// XXX        emit filesAdded(prefix, fileList);
    }
}
void ResourceView::addFile(const QString &prefix, const QString &file)
{
    const QModelIndex preindex = m_qrcModel->getIndex(prefix, QString());
    addFiles(QStringList(file), preindex);
}
/*
void ResourceView::removeItem()
{
    const QModelIndex index = currentIndex();
    m_qrcModel->deleteItem(index);
}
void ResourceView::removeFile(const QString &prefix, const QString &file)
{
    const QModelIndex index = m_qrcModel->getIndex(prefix, file);
    if (index.isValid())
        m_qrcModel->deleteItem(index);
}
*/
void ResourceView::onEditPrefix()
{
    QModelIndex index = currentIndex();
    changePrefix(index);
}
void ResourceView::onEditLang()
{
    const QModelIndex index = currentIndex();
    changeLang(index);
}
void ResourceView::onEditAlias()
{
    const QModelIndex index = currentIndex();
    changeAlias(index);
}
bool ResourceView::load(const QString &fileName)
{
    const QFileInfo fi(fileName);
    m_qrcModel->setFileName(fi.absoluteFilePath());
    if (!fi.exists())
        return false;
    return m_qrcModel->reload();
}
bool ResourceView::save()
{
    return m_qrcModel->save();
}
void ResourceView::changePrefix(const QModelIndex &index)
{
    bool ok = false;
    const QModelIndex preindex = m_qrcModel->prefixIndex(index);
    QString prefixBefore;
    QString dummy;
    m_qrcModel->getItem(preindex, prefixBefore, dummy);
    QString const prefixAfter = QInputDialog::getText(this, tr("Change Prefix"), tr("Input prefix:"),
        QLineEdit::Normal, prefixBefore, &ok);
    if (ok)
        addUndoCommand(preindex, PrefixProperty, prefixBefore, prefixAfter);
}
void ResourceView::changeLang(const QModelIndex &index)
{
    bool ok = false;
    const QModelIndex preindex = m_qrcModel->prefixIndex(index);
    QString const langBefore = m_qrcModel->lang(preindex);
    QString const langAfter = QInputDialog::getText(this, tr("Change Language"), tr("Language:"),
        QLineEdit::Normal, langBefore, &ok);
    if (ok) {
        addUndoCommand(preindex, LanguageProperty, langBefore, langAfter);
    }
}
void ResourceView::changeAlias(const QModelIndex &index)
{
    if (!index.parent().isValid())
        return;
    bool ok = false;
    QString const aliasBefore = m_qrcModel->alias(index);
    QString const aliasAfter = QInputDialog::getText(this, tr("Change File Alias"), tr("Alias:"),
        QLineEdit::Normal, aliasBefore, &ok);
    if (ok)
        addUndoCommand(index, AliasProperty, aliasBefore, aliasAfter);
}
QString ResourceView::currentAlias() const
{
    const QModelIndex current = currentIndex();
    if (!current.isValid())
        return QString();
    return m_qrcModel->alias(current);
}
QString ResourceView::currentPrefix() const
{
    const QModelIndex current = currentIndex();
    if (!current.isValid())
        return QString();
    const QModelIndex preindex = m_qrcModel->prefixIndex(current);
    QString prefix, file;
    m_qrcModel->getItem(preindex, prefix, file);
    return prefix;
}
QString ResourceView::currentLanguage() const
{
    const QModelIndex current = currentIndex();
    if (!current.isValid())
        return QString();
    const QModelIndex preindex = m_qrcModel->prefixIndex(current);
    return m_qrcModel->lang(preindex);
}
QString ResourceView::getCurrentValue(NodeProperty property) const
{
    switch (property) {
    case AliasProperty: return currentAlias();
    case PrefixProperty: return currentPrefix();
    case LanguageProperty: return currentLanguage();
    default: Q_ASSERT(false); return QString(); // Kill warning
    }
}
void ResourceView::changeValue(const QModelIndex &nodeIndex, NodeProperty property,
        const QString &value)
{
    switch (property) {
    case AliasProperty: m_qrcModel->changeAlias(nodeIndex, value); return;
    case PrefixProperty: m_qrcModel->changePrefix(nodeIndex, value); return;
    case LanguageProperty: m_qrcModel->changeLang(nodeIndex, value); return;
    default: Q_ASSERT(false);
    }
}
void ResourceView::advanceMergeId()
{
    m_mergeId++;
    if (m_mergeId < 0)
        m_mergeId = 0;
}
void ResourceView::addUndoCommand(const QModelIndex &nodeIndex, NodeProperty property,
        const QString &before, const QString &after)
{
    QUndoCommand * const command = new ModifyPropertyCommand(this, nodeIndex, property,
            m_mergeId, before, after);
    m_history->push(command);
}
void ResourceView::setCurrentAlias(const QString &before, const QString &after)
{
    const QModelIndex current = currentIndex();
    if (!current.isValid())
        return;
    addUndoCommand(current, AliasProperty, before, after);
}
void ResourceView::setCurrentPrefix(const QString &before, const QString &after)
{
    const QModelIndex current = currentIndex();
    if (!current.isValid())
        return;
    const QModelIndex preindex = m_qrcModel->prefixIndex(current);
    addUndoCommand(preindex, PrefixProperty, before, after);
}
void ResourceView::setCurrentLanguage(const QString &before, const QString &after)
{
    const QModelIndex current = currentIndex();
    if (!current.isValid())
        return;
    const QModelIndex preindex = m_qrcModel->prefixIndex(current);
    addUndoCommand(preindex, LanguageProperty, before, after);
}
bool ResourceView::isPrefix(const QModelIndex &index) const
{
    if (!index.isValid())
        return false;
    const QModelIndex preindex = m_qrcModel->prefixIndex(index);
    if (preindex == index)
        return true;
    return false;
}
QString ResourceView::fileName() const
{
    return m_qrcModel->fileName();
}
void ResourceView::setFileName(const QString &fileName)
{
    m_qrcModel->setFileName(fileName);
}
void ResourceView::setResourceDragEnabled(bool e)
{
    setDragEnabled(e);
    m_qrcModel->setResourceDragEnabled(e);
}
bool ResourceView::resourceDragEnabled() const
{
    return m_qrcModel->resourceDragEnabled();
}
} // namespace SharedTools
QrcEditor/shared/resourceview.h
New file
@@ -0,0 +1,180 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef RESOURCEVIEW_H
#define RESOURCEVIEW_H
#include "resourcefile_p.h"
#include <QtWidgets/QTreeView>
#include <QtCore/QPoint>
using namespace qdesigner_internal;
QT_BEGIN_NAMESPACE
class QAction;
class QMenu;
class QMouseEvent;
class QUndoStack;
QT_END_NAMESPACE
namespace SharedTools {
/*!
    \class EntryBackup
    Holds the backup of a tree node including children.
*/
class EntryBackup
{
protected:
    ResourceModel *m_model;
    int m_prefixIndex;
    QString m_name;
    EntryBackup(ResourceModel &model, int prefixIndex, const QString &name)
            : m_model(&model), m_prefixIndex(prefixIndex), m_name(name) { }
public:
    virtual void restore() const = 0;
    virtual ~EntryBackup() { }
};
namespace Internal {
    class RelativeResourceModel;
}
class ResourceView : public QTreeView
{
    Q_OBJECT
public:
    enum NodeProperty {
        AliasProperty,
        PrefixProperty,
        LanguageProperty
    };
    ResourceView(QUndoStack *history, QWidget *parent = 0);
    ~ResourceView();
    bool load(const QString &fileName);
    bool save();
    QString fileName() const;
    void setFileName(const QString &fileName);
    bool isDirty() const;
    void setDirty(bool dirty);
    void enableContextMenu(bool enable);
    void addFiles(QStringList fileList, const QModelIndex &index);
    void addFile(const QString &prefix, const QString &file);
//    void removeFile(const QString &prefix, const QString &file);
    bool isPrefix(const QModelIndex &index) const;
    QString currentAlias() const;
    QString currentPrefix() const;
    QString currentLanguage() const;
    void setResourceDragEnabled(bool e);
    bool resourceDragEnabled() const;
    void setDefaultAddFileEnabled(bool enable);
    bool defaultAddFileEnabled() const;
    void findSamePlacePostDeletionModelIndex(int &row, QModelIndex &parent) const;
    EntryBackup *removeEntry(const QModelIndex &index);
    void addFiles(int prefixIndex, const QStringList &fileNames, int cursorFile,
                  int &firstFile, int &lastFile);
    void removeFiles(int prefixIndex, int firstFileIndex, int lastFileIndex);
    QStringList fileNamesToAdd();
    QModelIndex addPrefix();
public slots:
    void onAddFiles();
    void setCurrentAlias(const QString &before, const QString &after);
    void setCurrentPrefix(const QString &before, const QString &after);
    void setCurrentLanguage(const QString &before, const QString &after);
    void advanceMergeId();
protected:
    void setupMenu();
    void changePrefix(const QModelIndex &index);
    void changeLang(const QModelIndex &index);
    void changeAlias(const QModelIndex &index);
    void mouseReleaseEvent(QMouseEvent *e);
    void keyPressEvent(QKeyEvent *e);
signals:
    void removeItem();
    void dirtyChanged(bool b);
    void currentIndexChanged();
    void addFilesTriggered(const QString &prefix);
    void addPrefixTriggered();
protected slots:
    void currentChanged(const QModelIndex &current, const QModelIndex &previous);
private slots:
    void onEditAlias();
    void onEditPrefix();
    void onEditLang();
    void popupMenu(const QModelIndex &index);
public:
    QString getCurrentValue(NodeProperty property) const;
    void changeValue(const QModelIndex &nodeIndex, NodeProperty property, const QString &value);
private:
    void addUndoCommand(const QModelIndex &nodeIndex, NodeProperty property,
                        const QString &before, const QString &after);
    QPoint m_releasePos;
    qdesigner_internal::ResourceFile m_qrcFile;
    Internal::RelativeResourceModel *m_qrcModel;
    QAction *m_addFile;
    QAction *m_editAlias;
    QAction *m_removeItem;
    QAction *m_addPrefix;
    QAction *m_editPrefix;
    QAction *m_editLang;
    QMenu *m_viewMenu;
    bool m_defaultAddFile;
    QUndoStack *m_history;
    int m_mergeId;
};
} // namespace SharedTools
#endif // RESOURCEVIEW_H
QrcEditor/shared/undocommands.cpp
New file
@@ -0,0 +1,185 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "undocommands_p.h"
#include <QtCore/QModelIndex>
namespace SharedTools {
ViewCommand::ViewCommand(ResourceView *view)
        : m_view(view)
{ }
ViewCommand::~ViewCommand()
{ }
ModelIndexViewCommand::ModelIndexViewCommand(ResourceView *view)
        : ViewCommand(view)
{ }
ModelIndexViewCommand::~ModelIndexViewCommand()
{ }
void ModelIndexViewCommand::storeIndex(const QModelIndex &index)
{
    if (m_view->isPrefix(index)) {
        m_prefixArrayIndex = index.row();
        m_fileArrayIndex = -1;
    } else {
        m_fileArrayIndex = index.row();
        m_prefixArrayIndex = m_view->model()->parent(index).row();
    }
}
QModelIndex ModelIndexViewCommand::makeIndex() const
{
    const QModelIndex prefixModelIndex
            = m_view->model()->index(m_prefixArrayIndex, 0, QModelIndex());
    if (m_fileArrayIndex != -1) {
        // File node
        const QModelIndex fileModelIndex
                = m_view->model()->index(m_fileArrayIndex, 0, prefixModelIndex);
        return fileModelIndex;
    } else {
        // Prefix node
        return prefixModelIndex;
    }
}
ModifyPropertyCommand::ModifyPropertyCommand(ResourceView *view, const QModelIndex &nodeIndex,
        ResourceView::NodeProperty property, const int mergeId, const QString &before,
        const QString &after)
        : ModelIndexViewCommand(view), m_property(property), m_before(before), m_after(after),
        m_mergeId(mergeId)
{
    storeIndex(nodeIndex);
}
bool ModifyPropertyCommand::mergeWith(const QUndoCommand * command)
{
    if (command->id() != id() || m_property != static_cast<const ModifyPropertyCommand *>(command)->m_property)
        return false;
    // Choose older command (this) and forgot the other
    return true;
}
void ModifyPropertyCommand::undo()
{
    Q_ASSERT(m_view);
    // Save current text in m_after for redo()
    m_after = m_view->getCurrentValue(m_property);
    // Reset text to m_before
    m_view->changeValue(makeIndex(), m_property, m_before);
}
void ModifyPropertyCommand::redo()
{
    // Prevent execution from within QUndoStack::push
    if (m_after.isNull())
        return;
    // Bring back text before undo
    Q_ASSERT(m_view);
    m_view->changeValue(makeIndex(), m_property, m_after);
}
RemoveEntryCommand::RemoveEntryCommand(ResourceView *view, const QModelIndex &index)
        : ModelIndexViewCommand(view), m_entry(0), m_isExpanded(true)
{
    storeIndex(index);
}
RemoveEntryCommand::~RemoveEntryCommand()
{
    freeEntry();
}
void RemoveEntryCommand::redo()
{
    freeEntry();
    const QModelIndex index = makeIndex();
    m_isExpanded = m_view->isExpanded(index);
    m_entry = m_view->removeEntry(index);
}
void RemoveEntryCommand::undo()
{
    if (m_entry == 0) {
        m_entry->restore();
        Q_ASSERT(m_view != 0);
        const QModelIndex index = makeIndex();
        m_view->setExpanded(index, m_isExpanded);
        m_view->setCurrentIndex(index);
        freeEntry();
    }
}
void RemoveEntryCommand::freeEntry()
{
    delete m_entry;
    m_entry = 0;
}
AddFilesCommand::AddFilesCommand(ResourceView *view, int prefixIndex, int cursorFileIndex,
        const QStringList &fileNames)
        : ViewCommand(view), m_prefixIndex(prefixIndex), m_cursorFileIndex(cursorFileIndex),
        m_fileNames(fileNames), m_firstFile(-1), m_lastFile(-1)
{ }
void AddFilesCommand::redo()
{
    m_view->addFiles(m_prefixIndex, m_fileNames, m_cursorFileIndex, m_firstFile, m_lastFile);
}
void AddFilesCommand::undo()
{
    m_view->removeFiles(m_prefixIndex, m_firstFile, m_lastFile);
}
AddEmptyPrefixCommand::AddEmptyPrefixCommand(ResourceView *view)
        : ViewCommand(view)
{ }
void AddEmptyPrefixCommand::redo()
{
    m_prefixArrayIndex = m_view->addPrefix().row();
}
void AddEmptyPrefixCommand::undo()
{
    const QModelIndex prefixModelIndex = m_view->model()->index(
            m_prefixArrayIndex, 0, QModelIndex());
    delete m_view->removeEntry(prefixModelIndex);
}
} // namespace SharedTools
QrcEditor/shared/undocommands_p.h
New file
@@ -0,0 +1,160 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef UNDO_COMMANDS_H
#define UNDO_COMMANDS_H
#include "resourceview.h"
#include <QtCore/QString>
#include <QtWidgets/QUndoCommand>
QT_BEGIN_NAMESPACE
class QModelIndex;
QT_END_NAMESPACE
namespace SharedTools {
/*!
    \class ViewCommand
    Provides a base for \l ResourceView-related commands.
*/
class ViewCommand : public QUndoCommand
{
protected:
    ResourceView *m_view;
    ViewCommand(ResourceView *view);
    virtual ~ViewCommand();
};
/*!
    \class ModelIndexViewCommand
    Provides a mean to store/restore a \l QModelIndex as it cannot
    be stored safely in most cases. This is an abstract class.
*/
class ModelIndexViewCommand : public ViewCommand
{
    int m_prefixArrayIndex;
    int m_fileArrayIndex;
protected:
    ModelIndexViewCommand(ResourceView *view);
    virtual ~ModelIndexViewCommand();
    void storeIndex(const QModelIndex &index);
    QModelIndex makeIndex() const;
};
/*!
    \class ModifyPropertyCommand
    Modifies the name/prefix/language property of a prefix/file node.
*/
class ModifyPropertyCommand : public ModelIndexViewCommand
{
    ResourceView::NodeProperty m_property;
    QString m_before;
    QString m_after;
    int m_mergeId;
public:
    ModifyPropertyCommand(ResourceView *view, const QModelIndex &nodeIndex,
            ResourceView::NodeProperty property, const int mergeId, const QString &before,
            const QString &after = QString());
private:
    int id() const { return m_mergeId; }
    bool mergeWith(const QUndoCommand * command);
    void undo();
    void redo();
};
/*!
    \class RemoveEntryCommand
    Removes a \l QModelIndex including all children from a \l ResourceView.
*/
class RemoveEntryCommand : public ModelIndexViewCommand
{
    EntryBackup *m_entry;
    bool m_isExpanded;
public:
    RemoveEntryCommand(ResourceView *view, const QModelIndex &index);
    ~RemoveEntryCommand();
private:
    void redo();
    void undo();
    void freeEntry();
};
/*!
    \class AddFilesCommand
    Adds a list of files to a given prefix node.
*/
class AddFilesCommand : public ViewCommand
{
    int m_prefixIndex;
    int m_cursorFileIndex;
    int m_firstFile;
    int m_lastFile;
    const QStringList m_fileNames;
public:
    AddFilesCommand(ResourceView *view, int prefixIndex, int cursorFileIndex,
            const QStringList &fileNames);
private:
    void redo();
    void undo();
};
/*!
    \class AddEmptyPrefixCommand
    Adds a new, empty prefix node.
*/
class AddEmptyPrefixCommand : public ViewCommand
{
    int m_prefixArrayIndex;
public:
    AddEmptyPrefixCommand(ResourceView *view);
private:
    void redo();
    void undo();
};
} // namespace SharedTools
#endif // UNDO_COMMANDS_H
QtCppConfig.props
New file
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ImportGroup Label="PropertySheets" />
  <PropertyGroup Label="UserMacros" />
  <PropertyGroup Condition="'$(QtBuild_Static_Vs2017)'==''">
    <QtBuild_Static_Vs2017>..\..\..\install\qt5-x86-vs2017-static</QtBuild_Static_Vs2017>
  </PropertyGroup>
  <PropertyGroup Condition="'$(QtBuild_Static_Vs2019)'==''">
    <QtBuild_Static_Vs2019>..\..\..\install\qt5-x86-vs2019-static</QtBuild_Static_Vs2019>
  </PropertyGroup>
  <PropertyGroup Condition="'$(QtBuild_Static_Vs2022)'==''">
    <QtBuild_Static_Vs2022>..\..\..\install\qt5-x86-vs2022-static</QtBuild_Static_Vs2022>
  </PropertyGroup>
  <PropertyGroup Condition="'$(VisualStudioVersion)'=='15.0'">
    <QtBuild>$(QtBuild_Static_Vs2017)</QtBuild>
  </PropertyGroup>
  <PropertyGroup Condition="'$(VisualStudioVersion)'=='16.0'">
    <QtBuild>$(QtBuild_Static_Vs2019)</QtBuild>
  </PropertyGroup>
  <PropertyGroup Condition="'$(VisualStudioVersion)'=='17.0'">
    <QtBuild>$(QtBuild_Static_Vs2022)</QtBuild>
  </PropertyGroup>
  <PropertyGroup>
    <QtBuild>$([System.IO.Path]::Combine($(ProjectDir),$(QtBuild)))</QtBuild>
    <QtBuild>$([System.IO.Path]::GetFullPath($(QtBuild)))</QtBuild>
  </PropertyGroup>
</Project>
QtMSBuild/ITaskLoggingHelper.cs
New file
@@ -0,0 +1,263 @@
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.Build.Framework;
namespace QtVsTools.QtMSBuild
{
    public interface ITaskLoggingHelper
    {
        bool HasLoggedErrors { get; }
        void LogCommandLine(
            string commandLine);
        void LogCommandLine(
            MessageImportance importance,
            string commandLine);
        void LogCriticalMessage(
            string subcategory,
            string code,
            string helpKeyword,
            string file,
            int lineNumber,
            int columnNumber,
            int endLineNumber,
            int endColumnNumber,
            string message,
            params object[] messageArgs);
        void LogError(
            string message,
            params object[] messageArgs);
        void LogError(
            string subcategory,
            string errorCode,
            string helpKeyword,
            string file,
            int lineNumber,
            int columnNumber,
            int endLineNumber,
            int endColumnNumber,
            string message,
            params object[] messageArgs);
        void LogError(
            string subcategory,
            string errorCode,
            string helpKeyword,
            string helpLink,
            string file,
            int lineNumber,
            int columnNumber,
            int endLineNumber,
            int endColumnNumber,
            string message,
            params object[] messageArgs);
        void LogErrorFromException(
            Exception exception);
        void LogErrorFromException(
            Exception exception,
            bool showStackTrace);
        void LogErrorFromException(
            Exception exception,
            bool showStackTrace,
            bool showDetail,
            string file);
        void LogErrorFromResources(
            string messageResourceName,
            params object[] messageArgs);
        void LogErrorFromResources(
            string subcategoryResourceName,
            string errorCode,
            string helpKeyword,
            string file,
            int lineNumber,
            int columnNumber,
            int endLineNumber,
            int endColumnNumber,
            string messageResourceName,
            params object[] messageArgs);
        void LogErrorWithCodeFromResources(
            string messageResourceName,
            params object[] messageArgs);
        void LogErrorWithCodeFromResources(
            string subcategoryResourceName,
            string file,
            int lineNumber,
            int columnNumber,
            int endLineNumber,
            int endColumnNumber,
            string messageResourceName,
            params object[] messageArgs);
        void LogExternalProjectFinished(
            string message,
            string helpKeyword,
            string projectFile,
            bool succeeded);
        void LogExternalProjectStarted(
            string message,
            string helpKeyword,
            string projectFile,
            string targetNames);
        void LogMessage(
            string message,
            params object[] messageArgs);
        void LogMessage(
            MessageImportance importance,
            string message,
            params object[] messageArgs);
        void LogMessage(
            string subcategory,
            string code,
            string helpKeyword,
            string file,
            int lineNumber,
            int columnNumber,
            int endLineNumber,
            int endColumnNumber,
            MessageImportance importance,
            string message,
            params object[] messageArgs);
        void LogMessageFromResources(
            string messageResourceName,
            params object[] messageArgs);
        void LogMessageFromResources(
            MessageImportance importance,
            string messageResourceName,
            params object[] messageArgs);
        bool LogMessageFromText(
            string lineOfText,
            MessageImportance messageImportance);
        bool LogMessagesFromFile(
            string fileName);
        bool LogMessagesFromFile(
            string fileName,
            MessageImportance messageImportance);
        bool LogMessagesFromStream(
            TextReader stream,
            MessageImportance messageImportance);
        bool LogsMessagesOfImportance(
            MessageImportance importance);
        void LogTelemetry(
            string eventName,
            IDictionary<string,
            string> properties);
        void LogWarning(
            string message,
            params object[] messageArgs);
        void LogWarning(
            string subcategory,
            string warningCode,
            string helpKeyword,
            string file,
            int lineNumber,
            int columnNumber,
            int endLineNumber,
            int endColumnNumber,
            string message,
            params object[] messageArgs);
        void LogWarning(
            string subcategory,
            string warningCode,
            string helpKeyword,
            string helpLink,
            string file,
            int lineNumber,
            int columnNumber,
            int endLineNumber,
            int endColumnNumber,
            string message,
            params object[] messageArgs);
        void LogWarningFromException(
            Exception exception);
        void LogWarningFromException(
            Exception exception,
            bool showStackTrace);
        void LogWarningFromResources(
            string messageResourceName,
            params object[] messageArgs);
        void LogWarningFromResources(
            string subcategoryResourceName,
            string warningCode,
            string helpKeyword,
            string file,
            int lineNumber,
            int columnNumber,
            int endLineNumber,
            int endColumnNumber,
            string messageResourceName,
            params object[] messageArgs);
        void LogWarningWithCodeFromResources(
            string messageResourceName,
            params object[] messageArgs);
        void LogWarningWithCodeFromResources(
            string subcategoryResourceName,
            string file,
            int lineNumber,
            int columnNumber,
            int endLineNumber,
            int endColumnNumber,
            string messageResourceName,
            params object[] messageArgs);
    }
}
QtMSBuild/Properties/AssemblyInfo.cs
New file
@@ -0,0 +1,68 @@
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************
<#@output extension="tt.cs" #>
<#@include file="$(SolutionDir)\version.tt" #>
**              <#=WARNING_GENERATED_FILE#>
****************************************************************************/
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("QtMSBuild")]
[assembly: AssemblyDescription("The Qt Visual Studio Tools allow developers to use the standard development environment without having to worry about any Qt-related build steps or tools.")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("The Qt Company Ltd.")]
[assembly: AssemblyProduct("Qt Visual Studio Tools")]
[assembly: AssemblyCopyright("Copyright (C) 2016-2021 The Qt Company Ltd.")]
[assembly: AssemblyTrademark("The Qt Company Ltd. Qt and their respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components.  If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("a618d28b-9352-44f4-aa71-609bf68bf871")]
// Version information for an assembly consists of the following four values:
//
//      Major Version
//      Minor Version
//      Build Number
//      Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("<#=QT_VS_TOOLS_VERSION_ASSEMBLY#>")]
[assembly: AssemblyFileVersion("<#=QT_VS_TOOLS_VERSION_ASSEMBLY_FILE#>")]
QtMSBuild/QtMSBuild.csproj
New file
@@ -0,0 +1,432 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
-->
<Project ToolsVersion="$(VisualStudioVersion)" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    <SchemaVersion>2.0</SchemaVersion>
    <OutputType>Library</OutputType>
    <AppDesignerFolder>Properties</AppDesignerFolder>
    <TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
    <RootNamespace>QtMSBuild</RootNamespace>
    <AssemblyName>QtMSBuild</AssemblyName>
    <ProjectGuid>{A618D28B-9352-44F4-AA71-609BF68BF871}</ProjectGuid>
    <FileAlignment>512</FileAlignment>
    <Deterministic>true</Deterministic>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
    <DebugSymbols>true</DebugSymbols>
    <DebugType>full</DebugType>
    <Optimize>false</Optimize>
    <OutputPath>bin\Debug\</OutputPath>
    <DefineConstants>DEBUG;TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
    <DebugType>pdbonly</DebugType>
    <Optimize>true</Optimize>
    <OutputPath>bin\Release\</OutputPath>
    <DefineConstants>TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
  </PropertyGroup>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Global references
  // -->
  <ItemGroup>
    <Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
    <Reference Include="System" />
    <Reference Include="$(VCTargetsPath)\Application Type\Linux\1.0\Microsoft.Build.Linux.Tasks.dll" />
    <Reference Include="$(VCTargetsPath)\Application Type\Linux\1.0\liblinux.dll" />
  </ItemGroup>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Version specific references
  // -->
  <Import Project="$(SolutionDir)\references.props" />
  <ItemGroup>
    <PackageReference Include="Microsoft.Build"
      Version="$(Version_Microsoft_Build)" />
    <PackageReference Include="Microsoft.Build.Framework"
      Version="$(Version_Microsoft_Build_Framework)" />
    <PackageReference Include="Microsoft.Build.Tasks.Core"
      Version="$(Version_Microsoft_Build_Tasks_Core)" />
    <PackageReference Include="Microsoft.Bcl.AsyncInterfaces"
      Version="$(Version_Microsoft_Bcl_AsyncInterfaces)" />
  </ItemGroup>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Solution project references
  // -->
  <ItemGroup>
    <ProjectReference Include="..\QtVsTools.RegExpr\QtVsTools.RegExpr.csproj">
      <Project>{a2831b9b-4d3b-46cb-85df-1b5c277c17db}</Project>
      <Name>QtVsTools.RegExpr</Name>
    </ProjectReference>
  </ItemGroup>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Project items
  // -->
  <ItemGroup>
    <T4Template Include="Properties\AssemblyInfo.cs">
      <Generator>TextTemplatingFileGenerator</Generator>
      <OutputFile>Properties\AssemblyInfo.tt.cs</OutputFile>
      <DependsOn>$(SolutionDir)\version.tt;$(SolutionDir)\common.tt</DependsOn>
      <LastGenOutput>AssemblyInfo.tt.cs</LastGenOutput>
    </T4Template>
    <Compile Include="ITaskLoggingHelper.cs" />
    <Compile Include="Properties\AssemblyInfo.tt.cs">
      <AutoGen>True</AutoGen>
      <DesignTime>True</DesignTime>
      <DependentUpon>AssemblyInfo.cs</DependentUpon>
    </Compile>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Qt/MSBuild common property pages and targets
    // -->
    <Content Include="QtMSBuild\qt_defaults.props">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
      <SubType>Designer</SubType>
    </Content>
    <Content Include="QtMSBuild\Qt.props">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
      <SubType>Designer</SubType>
    </Content>
    <Content Include="QtMSBuild\qt_private.props">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
      <SubType>Designer</SubType>
    </Content>
    <Content Include="QtMSBuild\qt.targets">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
      <SubType>Designer</SubType>
    </Content>
    <Content Include="QtMSBuild\qt_settings.xml">
      <SubType>Designer</SubType>
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
    <Content Include="QtMSBuild\qt_settings.targets">
      <SubType>Designer</SubType>
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
    <Content Include="QtMSBuild\qt_globals.targets">
      <SubType>Designer</SubType>
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
    <Content Include="QtMSBuild\qt_vars.targets">
      <SubType>Designer</SubType>
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Qt/MSBuild moc property pages and targets
    // -->
    <Content Include="QtMSBuild\moc\qt_import.props">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
      <SubType>Designer</SubType>
    </Content>
    <Content Include="QtMSBuild\moc\qtmoc.props">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
      <SubType>Designer</SubType>
    </Content>
    <Content Include="QtMSBuild\moc\qtmoc.targets">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
      <SubType>Designer</SubType>
    </Content>
    <Content Include="QtMSBuild\moc\qtmoc.xml">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
      <SubType>Designer</SubType>
    </Content>
    <T4Template Include="QtMSBuild\moc\qtmoc_v3.xml_TT">
      <Generator>TextTemplatingFileGenerator</Generator>
      <OutputFile>moc\qtmoc_v3.xml</OutputFile>
      <DependsOn>$(SolutionDir)\version.targets;$(SolutionDir)\version.tt;$(SolutionDir)\common.tt</DependsOn>
      <LastGenOutput>qtmoc_v3.xml</LastGenOutput>
      <SubType>Designer</SubType>
    </T4Template>
    <Content Include="QtMSBuild\moc\qtmoc_v3.xml">
      <AutoGen>True</AutoGen>
      <DesignTime>True</DesignTime>
      <DependentUpon>qtmoc_v3.xml_TT</DependentUpon>
      <SubType>Designer</SubType>
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
    <T4Template Include="QtMSBuild\moc\qtmoc_cl.targets_TT">
      <Generator>TextTemplatingFileGenerator</Generator>
      <OutputFile>moc\qtmoc_cl.targets</OutputFile>
      <DependsOn>$(SolutionDir)\version.targets;$(SolutionDir)\version.tt;$(SolutionDir)\common.tt</DependsOn>
      <SubType>Designer</SubType>
      <LastGenOutput>qtmoc_cl.targets</LastGenOutput>
    </T4Template>
    <Content Include="QtMSBuild\moc\qtmoc_cl.targets">
      <AutoGen>True</AutoGen>
      <DesignTime>True</DesignTime>
      <DependentUpon>qtmoc_cl.targets_TT</DependentUpon>
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Qt/MSBuild qml property pages and targets
    // -->
    <Content Include="QtMSBuild\qml\qt_import.props">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
      <SubType>Designer</SubType>
    </Content>
    <Content Include="QtMSBuild\qml\qtqml.props">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
      <SubType>Designer</SubType>
    </Content>
    <Content Include="QtMSBuild\qml\qtqml.targets">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
      <SubType>Designer</SubType>
    </Content>
    <Content Include="QtMSBuild\qml\qtqml_cache.props">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
      <SubType>Designer</SubType>
    </Content>
    <Content Include="QtMSBuild\qml\qtqml_cache.targets">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
      <SubType>Designer</SubType>
    </Content>
    <Content Include="QtMSBuild\qml\qtqml_static.props">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
      <SubType>Designer</SubType>
    </Content>
    <Content Include="QtMSBuild\qml\qtqml_static.targets">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
      <SubType>Designer</SubType>
    </Content>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Qt/MSBuild rcc property pages and targets
    // -->
    <Content Include="QtMSBuild\rcc\qt_import.props">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
      <SubType>Designer</SubType>
    </Content>
    <Content Include="QtMSBuild\rcc\qtrcc.props">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
      <SubType>Designer</SubType>
    </Content>
    <Content Include="QtMSBuild\rcc\qtrcc.targets">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
      <SubType>Designer</SubType>
    </Content>
    <Content Include="QtMSBuild\rcc\qtrcc.xml">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
    <T4Template Include="QtMSBuild\rcc\qtrcc_v3.xml_TT">
      <Generator>TextTemplatingFileGenerator</Generator>
      <OutputFile>rcc\qtrcc_v3.xml</OutputFile>
      <DependsOn>$(SolutionDir)\version.targets;$(SolutionDir)\version.tt;$(SolutionDir)\common.tt</DependsOn>
      <LastGenOutput>qtrcc_v3.xml</LastGenOutput>
      <SubType>Designer</SubType>
    </T4Template>
    <Content Include="QtMSBuild\rcc\qtrcc_v3.xml">
      <AutoGen>True</AutoGen>
      <DesignTime>True</DesignTime>
      <DependentUpon>qtrcc_v3.xml_TT</DependentUpon>
      <SubType>Designer</SubType>
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
    <T4Template Include="QtMSBuild\rcc\qtrcc_cl.targets_TT">
      <Generator>TextTemplatingFileGenerator</Generator>
      <OutputFile>rcc\qtrcc_cl.targets</OutputFile>
      <DependsOn>$(SolutionDir)\version.targets;$(SolutionDir)\version.tt;$(SolutionDir)\common.tt</DependsOn>
      <SubType>Designer</SubType>
      <LastGenOutput>qtrcc_cl.targets</LastGenOutput>
    </T4Template>
    <Content Include="QtMSBuild\rcc\qtrcc_cl.targets">
      <AutoGen>True</AutoGen>
      <DesignTime>True</DesignTime>
      <DependentUpon>qtrcc_cl.targets_TT</DependentUpon>
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Qt/MSBuild repc property pages and targets
    // -->
    <Content Include="QtMSBuild\repc\qt_import.props">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
      <SubType>Designer</SubType>
    </Content>
    <Content Include="QtMSBuild\repc\qtrepc.props">
      <SubType>Designer</SubType>
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
    <Content Include="QtMSBuild\repc\qtrepc.targets">
      <SubType>Designer</SubType>
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
    <Content Include="QtMSBuild\repc\qtrepc.xml">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
      <SubType>Designer</SubType>
    </Content>
    <T4Template Include="QtMSBuild\repc\qtrepc_v3.xml_TT">
      <Generator>TextTemplatingFileGenerator</Generator>
      <OutputFile>repc\qtrepc_v3.xml</OutputFile>
      <DependsOn>$(SolutionDir)\version.targets;$(SolutionDir)\version.tt;$(SolutionDir)\common.tt</DependsOn>
      <LastGenOutput>qtrepc_v3.xml</LastGenOutput>
      <SubType>Designer</SubType>
    </T4Template>
    <Content Include="QtMSBuild\repc\qtrepc_v3.xml">
      <AutoGen>True</AutoGen>
      <DesignTime>True</DesignTime>
      <DependentUpon>qtrepc_v3.xml_TT</DependentUpon>
      <SubType>Designer</SubType>
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
    <T4Template Include="QtMSBuild\repc\qtrepc_cl.targets_TT">
      <Generator>TextTemplatingFileGenerator</Generator>
      <OutputFile>repc\qtrepc_cl.targets</OutputFile>
      <DependsOn>$(SolutionDir)\version.targets;$(SolutionDir)\version.tt;$(SolutionDir)\common.tt</DependsOn>
      <SubType>Designer</SubType>
      <LastGenOutput>qtrepc_cl.targets</LastGenOutput>
    </T4Template>
    <Content Include="QtMSBuild\repc\qtrepc_cl.targets">
      <AutoGen>True</AutoGen>
      <DesignTime>True</DesignTime>
      <DependentUpon>qtrepc_cl.targets_TT</DependentUpon>
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Qt/MSBuild uic property pages and targets
    // -->
    <Content Include="QtMSBuild\uic\qt_import.props">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
      <SubType>Designer</SubType>
    </Content>
    <Content Include="QtMSBuild\uic\qtuic.props">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
    <Content Include="QtMSBuild\uic\qtuic.targets">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
    <Content Include="QtMSBuild\uic\qtuic.xml">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
    <Content Include="QtMSBuild\uic\qtuic_v3.xml">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
      <SubType>Designer</SubType>
    </Content>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Qt/MSBuild deploy properties and targets
    // -->
    <Content Include="QtMSBuild\deploy\qt_import.props">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
      <SubType>Designer</SubType>
    </Content>
    <Content Include="QtMSBuild\deploy\qtdeploy.props">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
    <Content Include="QtMSBuild\deploy\qtdeploy.targets">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
    <Content Include="QtMSBuild\deploy\qtdeploy.xml">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
      <SubType>Designer</SubType>
    </Content>
  <!--
  ///////////////////////////////////////////////////////////////////////////////////////////////
  // Qt/MSBuild translation tools property pages and targets
  // -->
    <Content Include="QtMSBuild\translation\qttranslation.props">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
    <Content Include="QtMSBuild\translation\qttranslation.targets">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
    <Content Include="QtMSBuild\translation\qttranslation.xml">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
    <Content Include="QtMSBuild\translation\qt_import.props">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Inline tasks
    // -->
    <Compile Include="Tasks\CriticalSection.cs" />
    <Compile Include="Tasks\GetVarsFromMSBuild.cs" />
    <Compile Include="Tasks\HostExec_LinuxWSL_Error.cs" />
    <Compile Include="Tasks\HostTranslatePaths_LinuxWSL_Error.cs" />
    <Compile Include="Tasks\ListQrc.cs" />
    <Compile Include="Tasks\ParseVarDefs.cs" />
    <Compile Include="Tasks\GetVarsFromMakefile.cs" />
    <Compile Include="Tasks\QtRunWork.cs" />
    <Compile Include="Tasks\GetItemHash.cs" />
    <Compile Include="Tasks\Flatten.cs" />
    <Compile Include="Tasks\Expand.cs" />
    <Compile Include="Tasks\Join.cs" />
    <Compile Include="Tasks\DumpItems.cs" />
    <Compile Include="Tasks\HostTranslatePaths_Windows.cs" />
    <Compile Include="Tasks\HostExec_Windows.cs" />
    <Compile Include="Tasks\HostTranslatePaths_LinuxSSL.cs" />
    <Compile Include="Tasks\HostExec_LinuxSSL.cs" />
    <Compile Include="Tasks\HostTranslatePaths_LinuxWSL.cs" />
    <Compile Include="Tasks\HostExec_LinuxWSL.cs" />
    <T4Template Include="QtMSBuild\qt_tasks.targets_TT">
      <Generator>TextTemplatingFileGenerator</Generator>
      <OutputFile>qt_tasks.targets</OutputFile>
      <DependsOn>$(SolutionDir)\version.targets;$(SolutionDir)\version.tt;$(SolutionDir)\common.tt</DependsOn>
      <SubType>Designer</SubType>
      <LastGenOutput>qt_tasks.targets</LastGenOutput>
    </T4Template>
    <Content Include="QtMSBuild\qt_tasks.targets">
      <AutoGen>True</AutoGen>
      <DesignTime>True</DesignTime>
      <DependentUpon>qt_tasks.targets_TT</DependentUpon>
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
    <T4Template Include="$(SolutionDir)\vstools.pri_TT">
      <Link>vstools.pri_TT</Link>
      <Generator>TextTemplatingFileGenerator</Generator>
      <OutputFile>$(SolutionDir)\vstools.pri</OutputFile>
      <DependsOn>$(SolutionDir)\version.targets;$(SolutionDir)\version.tt;$(SolutionDir)\common.tt</DependsOn>
      <LastGenOutput>vstools.pri</LastGenOutput>
      <SubType>Designer</SubType>
    </T4Template>
    <None Include="$(SolutionDir)\vstools.pri">
      <Link>vstools.pri</Link>
      <AutoGen>True</AutoGen>
      <DesignTime>True</DesignTime>
      <DependentUpon>vstools.pri_TT</DependentUpon>
      <SubType>Designer</SubType>
    </None>
  </ItemGroup>
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
  <Import Project="$(SolutionDir)\transform.targets" />
</Project>
QtMSBuild/QtMsBuild/Qt.props
New file
@@ -0,0 +1,59 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
-->
<!--
///////////////////////////////////////////////////////////////////////////////////////////////////
// Item type definition and default values
// -->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Import private Qt property definitions
  // -->
  <ImportGroup Label="Qt">
    <Import Project="$(MSBuildThisFileDirectory)\qt_private.props"/>
  </ImportGroup>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // User-defined settings
  // -->
  <PropertyGroup Label="UserMacros">
    <!-- Placeholder for user macros written by VS Property Manager -->
  </PropertyGroup>
  <PropertyGroup>
    <!-- Placeholder for properties written by VS Property Manager -->
  </PropertyGroup>
  <ItemDefinitionGroup>
    <!-- Placeholder for default metadata written by VS Property Manager -->
  </ItemDefinitionGroup>
  <ItemGroup>
    <!-- Placeholder for items written by VS Property Manager -->
  </ItemGroup>
</Project>
QtMSBuild/QtMsBuild/deploy/qt_import.props
New file
@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
-->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Qt/MSBuild import
  // -->
  <PropertyGroup>
    <QtMsBuildProps>
      $(QtMsBuildProps);
      $(MSBuildThisFileDirectory)qtdeploy.props
    </QtMsBuildProps>
    <QtMsBuildTargets>
      $(QtMsBuildTargets);
      $(MSBuildThisFileDirectory)qtdeploy.targets
    </QtMsBuildTargets>
  </PropertyGroup>
</Project>
QtMSBuild/QtMsBuild/deploy/qtdeploy.props
New file
@@ -0,0 +1,73 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
-->
<!--
///////////////////////////////////////////////////////////////////////////////////////////////////
// Deployment of Qt dependencies
// -->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <QtDeploy Condition="'$(QtDeploy)' == ''">false</QtDeploy>
  </PropertyGroup>
  <ItemDefinitionGroup>
    <QtDeploy>
      <QtDeployFiles>$(TargetPath)</QtDeployFiles>
      <QtDeployDir Condition="'$(QtDeployToProjectDir)' == 'true'">$(ProjectDir)</QtDeployDir>
      <QtDeployDir Condition="'$(QtDeployToProjectDir)' != 'true'">$(OutDir)</QtDeployDir>
      <QtDeployLibDir/>
      <QtDeployPluginDir/>
      <QtDeployDebugRelease>false</QtDeployDebugRelease>
      <QtDeployPdb>false</QtDeployPdb>
      <QtDeployForce>false</QtDeployForce>
      <QtDeployNoPatchQt>false</QtDeployNoPatchQt>
      <QtDeployNoPlugins>false</QtDeployNoPlugins>
      <QtDeployNoLibraries>false</QtDeployNoLibraries>
      <QtDeployQmlDir/>
      <QtDeployQmlImport/>
      <QtDeployNoQuickImport>false</QtDeployNoQuickImport>
      <QtDeployNoTranslations>false</QtDeployNoTranslations>
      <QtDeployNoSystemD3dCompiler>false</QtDeployNoSystemD3dCompiler>
      <QtDeployNoVirtualKeyboard>false</QtDeployNoVirtualKeyboard>
      <QtDeployCompilerRuntime>false</QtDeployCompilerRuntime>
      <QtDeployWebkit2>false</QtDeployWebkit2>
      <QtDeployAngle>false</QtDeployAngle>
      <QtDeployNoOpenglSw>false</QtDeployNoOpenglSw>
      <QtDeployIncludeModules/>
      <QtDeployExcludeModules/>
      <QtDeployVerbose>false</QtDeployVerbose>
      <QtDeployVsContent Condition="'$(QtDeployVsContent)' == 'true'">true</QtDeployVsContent>
      <QtDeployVsContent Condition="'$(QtDeployVsContent)' != 'true'">false</QtDeployVsContent>
    </QtDeploy>
  </ItemDefinitionGroup>
  <ItemGroup Condition="'$(QtDeploy)' == 'true'">
    <ProjectTools Include="QtDeploy"/>
  </ItemGroup>
</Project>
QtMSBuild/QtMsBuild/deploy/qtdeploy.targets
New file
@@ -0,0 +1,342 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
-->
<!--
///////////////////////////////////////////////////////////////////////////////////////////////////
// Deployment of Qt dependencies
// -->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Setup property page
  // -->
  <ItemGroup>
    <PropertyPageSchema
      Include="$(MSBuildThisFileDirectory)qtdeploy.xml" />
  </ItemGroup>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Default deploy log location
  // -->
  <PropertyGroup>
    <QtDeployLog Condition="'$(QtDeployLog)' == ''">$(IntDir)windeployqt.log</QtDeployLog>
  </PropertyGroup>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Schedule QtDeploy target to run after Link
  // -->
  <PropertyGroup Condition="'$(QtDeploy)' == 'true' AND '$(ApplicationType)' != 'Linux'">
    <BuildLinkTargets>$(BuildLinkTargets);QtDeploy</BuildLinkTargets>
  </PropertyGroup>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Deploy Qt files
  // -->
  <Target Name="QtDeploy"
    AfterTargets="Link"
    Inputs="$(TargetPath)" Outputs="$(QtDeployLog)"
    Condition="'$(QtDeploy)' == 'true' AND '$(ApplicationType)' != 'Linux'">
    <ItemGroup>
      <QtDeploy Include="$(TargetPath)"/>
    </ItemGroup>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Convert string lists in source item properties to lists of items
    // -->
    <Flatten Items="@(QtDeploy)"
      Metadata="QtDeployFiles;
                QtDeployDir;
                QtDeployLibDir;
                QtDeployPluginDir;
                QtDeployDebugRelease;
                QtDeployPdb;
                QtDeployForce;
                QtDeployNoPatchQt;
                QtDeployNoPlugins;
                QtDeployNoLibraries;
                QtDeployQmlDir;
                QtDeployQmlImport;
                QtDeployNoQuickImport;
                QtDeployNoTranslations;
                QtDeployNoSystemD3dCompiler;
                QtDeployNoVirtualKeyboard;
                QtDeployCompilerRuntime;
                QtDeployWebkit2;
                QtDeployAngle;
                QtDeployNoOpenglSw;
                QtDeployIncludeModules;
                QtDeployExcludeModules;
                QtDeployVerbose">
      <Output
        TaskParameter="Result" ItemName="Options" />
    </Flatten>
    <ItemGroup>
      <!--
      /////////////////////////////////////////////////////////////////////////////////////////////
      // Remove quotes from all paths
      // -->
      <Options>
        <Value Condition="( '%(Name)' == 'QtDeployFiles'
                         OR '%(Name)' == 'QtDeployDir'
                         OR '%(Name)' == 'QtDeployLibDir'
                         OR '%(Name)' == 'QtDeployPluginDir'
                         OR '%(Name)' == 'QtDeployQmlDir'
                         OR '%(Name)' == 'QtDeployQmlImport' )"
          >$([System.String]::Copy('%(Value)').Replace('&quot;', ''))</Value>
      </Options>
      <!--
        ///////////////////////////////////////////////////////////////////////////////////////////
        // Escape trailing back-slash in paths
        // -->
      <Options>
        <Value Condition="( '%(Name)' == 'QtDeployFiles'
                         OR '%(Name)' == 'QtDeployDir'
                         OR '%(Name)' == 'QtDeployLibDir'
                         OR '%(Name)' == 'QtDeployPluginDir'
                         OR '%(Name)' == 'QtDeployQmlDir'
                         OR '%(Name)' == 'QtDeployQmlImport' )
                        AND $([System.String]::Copy('%(Value)').Contains(' '))
                        AND $([System.String]::Copy('%(Value)').EndsWith('\'))"
          >%(Value)\</Value>
      </Options>
      <!--
        ///////////////////////////////////////////////////////////////////////////////////////////
        // Add quotes to paths containing spaces
        // -->
      <Options>
        <Value Condition="( '%(Name)' == 'QtDeployFiles'
                         OR '%(Name)' == 'QtDeployDir'
                         OR '%(Name)' == 'QtDeployLibDir'
                         OR '%(Name)' == 'QtDeployPluginDir'
                         OR '%(Name)' == 'QtDeployQmlDir'
                         OR '%(Name)' == 'QtDeployQmlImport' )
                        AND $([System.String]::Copy('%(Value)').Contains(' '))"
          >&quot;%(Value)&quot;</Value>
      </Options>
      <!--
      /////////////////////////////////////////////////////////////////////////////////////////////
      // Generate tool command line arguments
      // -->
      <Options>
        <!-- [files]                  Binaries or directory containing the binary. -->
        <PosArg Condition="'%(Name)' == 'QtDeployFiles'">%(Value)</PosArg>
      </Options>
      <Options>
        <!-- -dir <directory>         Use directory instead of binary directory. -->
        <Arg Condition="'%(Name)' == 'QtDeployDir'">--dir %(Value)</Arg>
      </Options>
      <Options>
        <!-- -libdir <path>           Copy libraries to path. -->
        <Arg Condition="'%(Name)' == 'QtDeployLibDir'">--libdir %(Value)</Arg>
      </Options>
      <Options>
        <!-- -plugindir <path>        Copy plugins to path. -->
        <Arg Condition="'%(Name)' == 'QtDeployPluginDir'">--plugindir %(Value)</Arg>
      </Options>
      <Options>
        <!-- -debug                   Assume debug binaries.
             -release                 Assume release binaries.-->
        <Arg Condition="'%(Name)' == 'QtDeployDebugRelease' AND '%(Value)' == 'debug'"
               >--debug</Arg>
        <Arg Condition="'%(Name)' == 'QtDeployDebugRelease' AND '%(Value)' == 'release'"
               >--release</Arg>
      </Options>
      <Options>
        <!-- -pdb                     Deploy .pdb files (MSVC). -->
        <Arg Condition="'%(Name)' == 'QtDeployPdb' AND '%(Value)' == 'true'"
               >--pdb</Arg>
      </Options>
      <Options>
        <!-- -force                   Force updating files. -->
        <Arg Condition="'%(Name)' == 'QtDeployForce' AND '%(Value)' == 'true'"
               >--force</Arg>
      </Options>
      <Options>
        <!-- -no-patchqt              Do not patch the Qt5Core library. -->
        <Arg Condition="'%(Name)' == 'QtDeployNoPatchQt' AND '%(Value)' == 'true'"
               >--no-patchqt</Arg>
      </Options>
      <Options>
        <!-- -no-plugins              Skip plugin deployment. -->
        <Arg Condition="'%(Name)' == 'QtDeployNoPlugins' AND '%(Value)' == 'true'"
               >--no-plugins</Arg>
      </Options>
      <Options>
        <!-- -no-libraries            Skip library deployment. -->
        <Arg Condition="'%(Name)' == 'QtDeployNoLibraries' AND '%(Value)' == 'true'"
               >--no-libraries</Arg>
      </Options>
      <Options>
        <!-- -qmldir <directory>      Scan for QML-imports starting from directory. -->
        <Arg Condition="'%(Name)' == 'QtDeployQmlDir'">--qmldir %(Value)</Arg>
      </Options>
      <Options>
        <!-- -qmlimport <directory>   Add the given path to the QML module search
                                      locations. -->
        <Arg Condition="'%(Name)' == 'QtDeployQmlImport'">--qmlimport %(Value)</Arg>
      </Options>
      <Options>
        <!-- -no-quick-import         Skip deployment of Qt Quick imports. -->
        <Arg Condition="'%(Name)' == 'QtDeployNoQuickImport' AND '%(Value)' == 'true'"
               >--no-quick-import</Arg>
      </Options>
      <Options>
        <!-- -no-translations         Skip deployment of translations. -->
        <Arg Condition="'%(Name)' == 'QtDeployNoTranslations' AND '%(Value)' == 'true'"
               >--no-translations</Arg>
      </Options>
      <Options>
        <!-- -no-system-d3d-compiler  Skip deployment of the system D3D compiler. -->
        <Arg Condition="'%(Name)' == 'QtDeployNoSystemD3dCompiler' AND '%(Value)' == 'true'"
               >--no-system-d3d-compiler</Arg>
      </Options>
      <Options>
        <!-- -no-virtualkeyboard      Disable deployment of the Virtual Keyboard. -->
        <Arg Condition="'%(Name)' == 'QtDeployNoVirtualKeyboard' AND '%(Value)' == 'true'"
               >--no-virtualkeyboard</Arg>
      </Options>
      <Options>
        <!-- -compiler-runtime        Deploy compiler runtime (Desktop only).
             -no-compiler-runtime     Do not deploy compiler runtime (Desktop only). -->
        <Arg Condition="'%(Name)' == 'QtDeployCompilerRuntime' AND '%(Value)' == 'deploy'"
               >--compiler-runtime</Arg>
        <Arg Condition="'%(Name)' == 'QtDeployCompilerRuntime' AND '%(Value)' == 'skip'"
               >--no-compiler-runtime</Arg>
      </Options>
      <Options>
        <!-- -webkit2                 Deployment of WebKit2 (web process).
             -no-webkit2              Skip deployment of WebKit2. -->
        <Arg Condition="'%(Name)' == 'QtDeployWebkit2' AND '%(Value)' == 'deploy'"
               >--webkit2</Arg>
        <Arg Condition="'%(Name)' == 'QtDeployWebkit2' AND '%(Value)' == 'skip'"
               >--no-webkit2</Arg>
      </Options>
      <Options>
        <!-- -angle                   Force deployment of ANGLE.
             -no-angle                Disable deployment of ANGLE. -->
        <Arg Condition="'%(Name)' == 'QtDeployAngle' AND '%(Value)' == 'deploy'"
               >--angle</Arg>
        <Arg Condition="'%(Name)' == 'QtDeployAngle' AND '%(Value)' == 'skip'"
               >--no-angle</Arg>
      </Options>
      <Options>
        <!-- -no-opengl-sw            Do not deploy the software rasterizer library. -->
        <Arg Condition="'%(Name)' == 'QtDeployNoOpenglSw' AND '%(Value)' == 'true'"
               >--no-opengl-sw</Arg>
      </Options>
      <Options>
        <!-- Qt libraries can be added by passing their name (-xml) ... -->
        <Arg Condition="'%(Name)' == 'QtDeployIncludeModules'">-%(Value)</Arg>
      </Options>
      <Options>
        <!-- ... or removed by passing the name prepended by -no- (-no-xml). -->
        <Arg Condition="'%(Name)' == 'QtDeployExcludeModules'">--no-%(Value)</Arg>
      </Options>
    </ItemGroup>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Run windeployqt
    // -->
    <PropertyGroup>
      <Cmd><![CDATA["$(QtToolsPath)\windeployqt.exe"]]></Cmd>
      <Cmd>$(Cmd) --list target</Cmd>
      <Cmd Condition="'%(Options.Arg)' != ''">$(Cmd) %(Options.Arg)</Cmd>
      <Cmd Condition="'%(Options.PosArg)' != ''">$(Cmd) %(Options.PosArg)</Cmd>
    </PropertyGroup>
    <Message Importance="high" Text="windeployqt: $(Cmd)" />
    <Exec Command="$(Cmd) > &quot;$(QtDeployLog)&quot;" />
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Read deploy log into QtDeployed list
    // -->
    <ReadLinesFromFile File="$(QtDeployLog)">
      <Output TaskParameter="Lines" ItemName="QtDeployed" />
    </ReadLinesFromFile>
    <ItemGroup>
      <QtDeployed Remove="@(QtDeployed)" Condition="!Exists('%(Fullpath)')"/>
    </ItemGroup>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Mark deployed files as source content for VS deployment project
    // -->
    <ItemGroup>
      <None Include="@(QtDeployed)" Condition="'%(QtDeploy.QtDeployVsContent)' == 'true'">
        <DeploymentContent>true</DeploymentContent>
        <RootFolder>$(ProjectDir)</RootFolder>
      </None>
    </ItemGroup>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Log output files; used by VS on clean and up-to-date check
    // -->
    <ItemGroup>
      <QtDeployLog Include="$(QtDeployLog)"/>
      <QtDeployed Include="$(QtDeployLog)"/>
    </ItemGroup>
    <WriteLinesToFile
      File="$(TLogLocation)windeployqt.read.1u.tlog"
      Lines="^$(ProjectPath)"
      Overwrite="true" Encoding="Unicode"/>
    <WriteLinesToFile
      File="$(TLogLocation)windeployqt.write.1u.tlog"
      Lines="^$(ProjectPath);@(QtDeployLog->'%(Fullpath)')"
      Overwrite="true" Encoding="Unicode"/>
    <WriteLinesToFile
      File="$(TLogLocation)$(ProjectName).write.1u.tlog"
      Lines="^$(ProjectFileName);@(QtDeployed->'%(Fullpath)')"
      Overwrite="false" Encoding="Unicode"/>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Clean-up
    // -->
    <PropertyGroup>
      <Cmd/>
    </PropertyGroup>
    <ItemGroup>
      <Options Remove="@(Options)"/>
      <QtDeploy Remove="@(QtDeploy)"/>
      <QtDeployLog Remove="@(QtDeployLog)"/>
      <QtDeployed Remove="@(QtDeployed)"/>
    </ItemGroup>
  </Target>
</Project>
QtMSBuild/QtMsBuild/deploy/qtdeploy.xml
New file
@@ -0,0 +1,366 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
-->
<!--
///////////////////////////////////////////////////////////////////////////////////////////////////
// windeployqt Property Page
//
// -->
<ProjectSchemaDefinitions
  xmlns="http://schemas.microsoft.com/build/2009/properties"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:sys="clr-namespace:System;assembly=mscorlib">
  <Rule
    Name="QtRule70_Deploy"
    PageTemplate="tool"
    DisplayName="Qt Deploy Tool"
    Order="999">
    <Rule.DataSource>
      <DataSource
        Persistence="UserFile"
        ItemType="QtDeploy"
        HasConfigurationCondition="true"/>
    </Rule.DataSource>
    <Rule.Categories>
      <Category Name="General" DisplayName="windeployqt"/>
    </Rule.Categories>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Application Binary
    // -->
    <StringListProperty
      Name="QtDeployFiles" DisplayName="Application Binary">
      <StringListProperty.Description>
        <sys:String>
          <![CDATA[Binaries or directory containing the application binary ( [files] ).]]>
        </sys:String>
      </StringListProperty.Description>
    </StringListProperty>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Deployment Directory
    // -->
    <StringProperty
      Name="QtDeployDir" DisplayName="Deployment Directory">
      <StringProperty.Description>
        <sys:String>
          <![CDATA[Use directory instead of binary directory ( --dir <directory> ).]]>
        </sys:String>
      </StringProperty.Description>
    </StringProperty>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Library Directory
    // -->
    <StringProperty
      Name="QtDeployLibDir" DisplayName="Library Directory">
      <StringProperty.Description>
        <sys:String>
          <![CDATA[Copy libraries to path ( --libdir <path> ).]]>
        </sys:String>
      </StringProperty.Description>
    </StringProperty>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Plugin Directory
    // -->
    <StringProperty
      Name="QtDeployPluginDir" DisplayName="Plugin Directory">
      <StringProperty.Description>
        <sys:String>
          <![CDATA[Copy plugins to path ( --plugindir <path> ).]]>
        </sys:String>
      </StringProperty.Description>
    </StringProperty>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Debug/Release Binaries
    // -->
    <EnumProperty
      Name="QtDeployDebugRelease" DisplayName="Debug/Release Binaries">
      <EnumProperty.Description>
        <sys:String>
          <![CDATA[Assume debug or release binaries ( --debug | --release ).]]>
        </sys:String>
      </EnumProperty.Description>
      <EnumValue Name="false" DisplayName="Default"/>
      <EnumValue Name="debug" DisplayName="Debug ( --debug )"/>
      <EnumValue Name="release" DisplayName="Release ( --release )"/>
    </EnumProperty>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Deploy PDB Files
    // -->
    <EnumProperty
      Name="QtDeployPdb" DisplayName="Deploy PDB Files">
      <EnumProperty.Description>
        <sys:String>
          <![CDATA[Deploy .pdb files (MSVC) ( --pdb ).]]>
        </sys:String>
      </EnumProperty.Description>
      <EnumValue Name="false" DisplayName="Disabled"/>
      <EnumValue Name="true" DisplayName="Enabled ( --pdb )"/>
    </EnumProperty>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    //
    // -->
    <EnumProperty
      Name="QtDeployForce" DisplayName="Force Update">
      <EnumProperty.Description>
        <sys:String>
          <![CDATA[Force updating files ( --force ).]]>
        </sys:String>
      </EnumProperty.Description>
      <EnumValue Name="false" DisplayName="Disabled"/>
      <EnumValue Name="true" DisplayName="Enabled ( --force )"/>
    </EnumProperty>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Skip Qt5Core Patch
    // -->
    <EnumProperty
      Name="QtDeployNoPatchQt" DisplayName="Skip Qt5Core Patch">
      <EnumProperty.Description>
        <sys:String>
          <![CDATA[Do not patch the Qt5Core library ( --no-patchqt ).]]>
        </sys:String>
      </EnumProperty.Description>
      <EnumValue Name="false" DisplayName="Disabled"/>
      <EnumValue Name="true" DisplayName="Enabled ( --no-patchqt )"/>
    </EnumProperty>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Skip Plugins
    // -->
    <EnumProperty
      Name="QtDeployNoPlugins" DisplayName="Skip Plugins">
      <EnumProperty.Description>
        <sys:String>
          <![CDATA[Skip plugin deployment ( --no-plugins ).]]>
        </sys:String>
      </EnumProperty.Description>
      <EnumValue Name="false" DisplayName="Disabled"/>
      <EnumValue Name="true" DisplayName="Enabled ( --no-plugins )"/>
    </EnumProperty>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Skip Libraries
    // -->
    <EnumProperty
      Name="QtDeployNoLibraries" DisplayName="Skip Libraries">
      <EnumProperty.Description>
        <sys:String>
          <![CDATA[Skip library deployment ( --no-libraries ).]]>
        </sys:String>
      </EnumProperty.Description>
      <EnumValue Name="false" DisplayName="Disabled"/>
      <EnumValue Name="true" DisplayName="Enabled ( --no-libraries )"/>
    </EnumProperty>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // QML Directories Root
    // -->
    <StringProperty
      Name="QtDeployQmlDir" DisplayName="QML Directories Root">
      <StringProperty.Description>
        <sys:String>
          <![CDATA[Scan for QML-imports starting from directory ( --qmldir <directory> ).]]>
        </sys:String>
      </StringProperty.Description>
    </StringProperty>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // QML Modules Path
    // -->
    <StringListProperty
      Name="QtDeployQmlImport" DisplayName="QML Modules Path">
      <StringListProperty.Description>
        <sys:String>
          <![CDATA[Add the given path to the QML module search locations ( --qmlimport <directory> ).]]>
        </sys:String>
      </StringListProperty.Description>
    </StringListProperty>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Skip Qt Quick Imports
    // -->
    <EnumProperty
      Name="QtDeployNoQuickImport" DisplayName="Skip Qt Quick Imports">
      <EnumProperty.Description>
        <sys:String>
          <![CDATA[Skip deployment of Qt Quick imports ( --no-quick-import ).]]>
        </sys:String>
      </EnumProperty.Description>
      <EnumValue Name="false" DisplayName="Disabled"/>
      <EnumValue Name="true" DisplayName="Enabled ( --no-quick-import )"/>
    </EnumProperty>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Skip Translations
    // -->
    <EnumProperty
      Name="QtDeployNoTranslations" DisplayName="Skip Translations">
      <EnumProperty.Description>
        <sys:String>
          <![CDATA[Skip deployment of translations ( --no-translations ).]]>
        </sys:String>
      </EnumProperty.Description>
      <EnumValue Name="false" DisplayName="Disabled"/>
      <EnumValue Name="true" DisplayName="Enabled ( --no-translations )"/>
    </EnumProperty>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Skip Direct3D Compiler
    // -->
    <EnumProperty
      Name="QtDeployNoSystemD3dCompiler" DisplayName="Skip Direct3D Compiler">
      <EnumProperty.Description>
        <sys:String>
          <![CDATA[Skip deployment of the system D3D compiler ( --no-system-d3d-compiler ).]]>
        </sys:String>
      </EnumProperty.Description>
      <EnumValue Name="false" DisplayName="Disabled"/>
      <EnumValue Name="true" DisplayName="Enabled ( --no-system-d3d-compiler )"/>
    </EnumProperty>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Skip Virtual Keyboard
    // -->
    <EnumProperty
      Name="QtDeployNoVirtualKeyboard" DisplayName="Skip Virtual Keyboard">
      <EnumProperty.Description>
        <sys:String>
          <![CDATA[Disable deployment of the Virtual Keyboard ( --no-virtualkeyboard ).]]>
        </sys:String>
      </EnumProperty.Description>
      <EnumValue Name="false" DisplayName="Disabled"/>
      <EnumValue Name="true" DisplayName="Enabled ( --no-virtualkeyboard )"/>
    </EnumProperty>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Compiler Runtime
    // -->
    <EnumProperty
      Name="QtDeployCompilerRuntime" DisplayName="Compiler Runtime">
      <EnumProperty.Description>
        <sys:String>
          <![CDATA[Deploy compiler runtime (Desktop only).]]>
        </sys:String>
      </EnumProperty.Description>
      <EnumValue Name="false" DisplayName="Default"/>
      <EnumValue Name="deploy" DisplayName="Deploy ( --compiler-runtime )"/>
      <EnumValue Name="skip" DisplayName="Do Not Deploy ( --no-compiler-runtime )"/>
    </EnumProperty>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // WebKit2 Deployment
    // -->
    <EnumProperty
      Name="QtDeployWebkit2" DisplayName="WebKit2 Deployment">
      <EnumProperty.Description>
        <sys:String>
          <![CDATA[Deployment of WebKit2 (web process).]]>
        </sys:String>
      </EnumProperty.Description>
      <EnumValue Name="false" DisplayName="Default"/>
      <EnumValue Name="deploy" DisplayName="Deploy ( --webkit2 )"/>
      <EnumValue Name="skip" DisplayName="Do Not Deploy ( --no-webkit2 )"/>
    </EnumProperty>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // ANGLE Deployment
    // -->
    <EnumProperty
      Name="QtDeployAngle" DisplayName="ANGLE Deployment">
      <EnumProperty.Description>
        <sys:String>
          <![CDATA[Deployment of ANGLE.]]>
        </sys:String>
      </EnumProperty.Description>
      <EnumValue Name="false" DisplayName="Default"/>
      <EnumValue Name="deploy" DisplayName="Deploy ( --angle )"/>
      <EnumValue Name="skip" DisplayName="Do Not Deploy ( --no-angle )"/>
    </EnumProperty>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Skip Rasterizer Library
    // -->
    <EnumProperty
      Name="QtDeployNoOpenglSw" DisplayName="Skip Rasterizer Library">
      <EnumProperty.Description>
        <sys:String>
          <![CDATA[Do not deploy the software rasterizer library ( --no-opengl-sw ).]]>
        </sys:String>
      </EnumProperty.Description>
      <EnumValue Name="false" DisplayName="Disabled"/>
      <EnumValue Name="true" DisplayName="Enabled ( --no-opengl-sw )"/>
    </EnumProperty>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Include Qt Libraries
    // -->
    <StringListProperty
      Name="QtDeployIncludeModules" DisplayName="Include Qt Libraries">
      <StringListProperty.Description>
        <sys:String>
          <![CDATA[Qt libraries can be added by passing their name ( -<name> ).]]>
        </sys:String>
      </StringListProperty.Description>
    </StringListProperty>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Exclude Qt Libraries
    // -->
    <StringListProperty
      Name="QtDeployExcludeModules" DisplayName="Exclude Qt Libraries">
      <StringListProperty.Description>
        <sys:String>
          <![CDATA[Qt libraries can be removed by passing their prepended by --no- ( --no-<name> ).]]>
        </sys:String>
      </StringListProperty.Description>
    </StringListProperty>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Set As Solution Deployment Content
    // -->
    <EnumProperty
      Name="QtDeployVsContent" DisplayName="Set As Solution Deployment Content">
      <EnumProperty.Description>
        <sys:String>
          <![CDATA[Mark deployed files as solution deployment content.]]>
        </sys:String>
      </EnumProperty.Description>
      <EnumValue Name="false" DisplayName="Disabled"/>
      <EnumValue Name="true" DisplayName="Enable"/>
    </EnumProperty>
  </Rule>
</ProjectSchemaDefinitions>
QtMSBuild/QtMsBuild/moc/qt_import.props
New file
@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/****************************************************************************
**
** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
-->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Qt/MSBuild import
  // -->
  <PropertyGroup>
    <QtMsBuildProps>
      $(QtMsBuildProps);
      $(MSBuildThisFileDirectory)qtmoc.props
    </QtMsBuildProps>
    <QtMsBuildTargets>
      $(QtMsBuildTargets);
      $(MSBuildThisFileDirectory)qtmoc.targets
    </QtMsBuildTargets>
  </PropertyGroup>
</Project>
QtMSBuild/QtMsBuild/moc/qtmoc.props
New file
@@ -0,0 +1,83 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/****************************************************************************
**
** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
-->
<!--
///////////////////////////////////////////////////////////////////////////////////////////////////
// Qt/MSBuild moc property definitions
// -->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Import pre-requisites
  // -->
  <Import
    Condition="'$(QtMsBuildProps_BeforeMoc)' != ''"
    Project="$(QtMsBuildProps_BeforeMoc)"/>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // QtMoc item template
  // -->
  <ItemDefinitionGroup>
    <QtMoc>
      <ExecutionDescription>moc %(Identity)</ExecutionDescription>
      <QTDIR Condition="'$(QtVsProjectSettings)' != 'true'"
        >$(QTDIR)</QTDIR>
      <QTDIR Condition="'$(QtVsProjectSettings)' == 'true'"
        >$(QtInstallDir)</QTDIR>
      <InputFile>%(FullPath)</InputFile>
      <OutputFile Condition="'$(QtVsProjectSettings)' != 'true'"
        >$(ProjectDir)GeneratedFiles\$(Configuration)\moc_%(Filename).cpp</OutputFile>
      <QtMocDir Condition="'$(QtVsProjectSettings)' == 'true'"
        >$(IntDir)moc\</QtMocDir>
      <QtMocFileName Condition="'$(QtVsProjectSettings)' == 'true'"
        >moc_%(Filename).cpp</QtMocFileName>
      <DynamicSource>output</DynamicSource>
      <ParallelProcess>true</ParallelProcess>
      <CommandLineTemplate>[AllOptions] [AdditionalOptions]</CommandLineTemplate>
      <Outputs>%(OutputFile)</Outputs>
      <OverrideClCompile>false</OverrideClCompile>
    </QtMoc>
  </ItemDefinitionGroup>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Import dependants
  // -->
  <Import
    Condition="'$(QtMsBuildProps_AfterMoc)' != ''"
    Project="$(QtMsBuildProps_AfterMoc)"/>
</Project>
QtMSBuild/QtMsBuild/moc/qtmoc.targets
New file
@@ -0,0 +1,510 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
-->
<!--
///////////////////////////////////////////////////////////////////////////////////////////////////
// Definitions specific to moc
///////////////////////////////////////////////////////////////////////////////////////////////////
// -->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Import pre-requisites
  // -->
  <Import
    Condition="'$(QtMsBuildTargets_BeforeMoc)' != ''"
    Project="$(QtMsBuildTargets_BeforeMoc)"/>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Qt/MSBuild global properties
  // -->
  <PropertyGroup>
    <QtBuildTargets>QtMoc;$(QtBuildTargets)</QtBuildTargets>
  </PropertyGroup>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Setup item type and property page
  // -->
  <Choose>
    <When Condition="'$(QtVsProjectSettings)' == 'true' AND '$(QtVsProjectClProperties)' == 'true'">
      <ItemGroup>
        <PropertyPageSchema
          Include="$(MSBuildThisFileDirectory)qtmoc_v3.xml" />
      </ItemGroup>
    </When>
    <Otherwise>
      <ItemGroup Condition="'$(QtVsProjectSettings)' == 'false'">
        <PropertyPageSchema
          Include="$(MSBuildThisFileDirectory)qtmoc.xml" />
      </ItemGroup>
    </Otherwise>
  </Choose>
  <ItemGroup>
    <AvailableItemName Include="QtMoc">
      <Targets>Qt;_ClCompile</Targets>
    </AvailableItemName>
  </ItemGroup>
  <PropertyGroup>
    <QtMocRuleName>QtRule30_Moc</QtMocRuleName>
  </PropertyGroup>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  /// TARGET QtMocInit
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Initialize default metadata
  // -->
  <Target Name="QtMocInit">
    <!--// Initialize %(OutputFile) -->
    <ItemGroup Condition="'$(QtVsProjectSettings)' == 'true' AND '@(QtMoc)' != ''">
      <QtMocAux Include="@(QtMoc)">
        <OutputFile
          >$([System.IO.Path]::Combine('%(QtMoc.QtMocDir)','%(QtMoc.QtMocFileName)'))</OutputFile>
      </QtMocAux>
      <QtMoc Remove="@(QtMoc)"/>
      <QtMoc Include="@(QtMocAux)"/>
      <QtMocAux Remove="@(QtMocAux)"/>
    </ItemGroup>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Add moc output dir to C++ include path
    // -->
    <ItemGroup Condition="'@(QtMoc)' != ''">
      <QtIncludePath Include="$([System.IO.Path]::GetDirectoryName('%(QtMoc.OutputFile)'))"/>
    </ItemGroup>
  </Target>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  /// TARGET QtMocPrepare
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Prepare to process sources
  // -->
  <Target Name="QtMocPrepare" DependsOnTargets="QtMocInit"
    Inputs="%(QtMoc.Identity)" Outputs="@(QtMoc->'####### Don't skip this target #######')">
    <ItemGroup>
      <selected_files Include="$(SelectedFiles)"/>
    </ItemGroup>
    <Message Importance="High" Condition="'$(QtDebug)' == 'true'"
        Text="## QtMocPrepare @(QtMoc)"/>
    <PropertyGroup>
      <selected_files>[@(selected_files->'%(Identity)','][')]</selected_files>
      <file>[@(QtMoc->'%(Identity)')]</file>
      <output_file>@(QtMoc->'%(OutputFile)')</output_file>
      <is_selected Condition="$(selected_files.Contains('$(file)'))">true</is_selected>
      <is_selected Condition="!$(selected_files.Contains('$(file)'))">false</is_selected>
    </PropertyGroup>
    <!--// Delete output file to force build of source if it was manually selected to build
        //  (e.g. by the 'Compile' option in the context menu for the file) -->
    <Delete Files="$(output_file)"
      Condition="'$(SelectedFiles)' != '' AND '$(is_selected)' == 'true'" />
    <!--// If a source was manually selected to build, remove all other sources -->
    <ItemGroup Condition="'@(selected_files)' != ''">
      <QtMoc Remove="@(QtMoc)"
        Condition="'$(SelectedFiles)' != '' AND '$(is_selected)' != 'true'" />
    </ItemGroup>
    <!--// Remove sources excluded from build -->
    <ItemGroup>
      <QtMoc Remove="@(QtMoc)"
        Condition="'$(SelectedFiles)' == '' AND '%(QtMoc.ExcludedFromBuild)' == 'true'"/>
    </ItemGroup>
    <PropertyGroup>
      <selected_files/>
      <file/>
      <output_file/>
      <is_selected/>
    </PropertyGroup>
  </Target>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  /// TARGET QtMocSetModified
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Set InputChanged flag if source file or dependencies have been modified
  // -->
  <Target Name="QtMocSetModified" DependsOnTargets="QtMocPrepare"
    Condition="'@(QtMoc)' != ''"
    Inputs="%(QtMoc.FullPath);%(QtMoc.AdditionalDependencies)" Outputs="@(QtMoc->'%(OutputFile)')">
    <Message Importance="High" Condition="'$(QtDebug)' == 'true'"
      Text="## QtMocSetModified @(QtMoc)" />
    <CreateProperty Value="true">
      <Output TaskParameter="ValueSetByTask" PropertyName="input_changed" />
    </CreateProperty>
    <ItemGroup>
      <QtMoc>
        <InputChanged>$(input_changed)</InputChanged>
      </QtMoc>
    </ItemGroup>
  </Target>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  /// TARGET QtMocOverrideCpp
  /////////////////////////////////////////////////////////////////////////////////////////////////
  //
  // -->
  <Import Project="qtmoc_cl.targets"/>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  /// TARGET QtMoc
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Process each source file and produce the corresponding QtWork items
  // -->
  <PropertyGroup>
    <QtMocDependsOn>
      QtPrepare;
      QtMocPrepare;
      QtMocSetModified;
      QtMocOverrideCpp;
      $(QtMocDependsOn)
    </QtMocDependsOn>
  </PropertyGroup>
  <Target Name="QtMoc"
    DependsOnTargets="$(QtMocDependsOn)"
    BeforeTargets="$(QtMocBeforeTargets)" AfterTargets="$(QtMocAfterTargets)"
    Condition="'@(QtMoc)' != ''"
    Inputs="%(QtMoc.FullPath);%(QtMoc.AdditionalDependencies);$(MSBuildProjectFile)"
    Outputs="@(QtMoc->'%(OutputFile)')">
    <Message Importance="High" Condition="'$(QtDebug)' == 'true'" Text="## QtMoc @(QtMoc)" />
    <CreateProperty Value="true">
      <Output TaskParameter="ValueSetByTask" PropertyName="dependencies_changed" />
    </CreateProperty>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Convert string lists in source item properties to lists of items
    // -->
    <Flatten Items="@(QtMoc)"
      Metadata="InputFile;
                OutputFile;
                IncludePath;
                MacFramework;
                PreprocessOnly;
                Define;
                Undefine;
                Metadata;
                CompilerFlavor;
                NoInclude;
                PathPrefix;
                ForceInclude;
                PrependInclude;
                Include;
                NoNotesWarnings;
                NoNotes;
                NoWarnings;
                IgnoreConflicts;
                OptionsFile">
      <Output
        TaskParameter="Result" ItemName="LocalOptions" />
    </Flatten>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Translate local paths to build host paths
    // -->
    <HostTranslatePaths
      Items="@(LocalOptions)"
      Names="InputFile;
            OutputFile;
            IncludePath;
            MacFramework;
            PathPrefix;
            ForceInclude;
            PrependInclude;
            Include;
            OptionsFile">
      <Output
        TaskParameter="Result" ItemName="options" />
    </HostTranslatePaths>
    <ItemGroup>
      <!--
      /////////////////////////////////////////////////////////////////////////////////////////////
      // Escape double-quotes in macro definitions
      // -->
      <options>
        <Value Condition="('%(Name)' == 'Define' OR '%(Name)' == 'Undefine')
          AND ($([System.String]::Copy('%(Value)').Contains(' '))
            OR $([System.String]::Copy('%(Value)').Contains('&quot;')))"
          > &quot;$([System.String]::Copy('%(Value)').Replace('&quot;', '\&quot;'))&quot;</Value>
      </options>
      <!--
      /////////////////////////////////////////////////////////////////////////////////////////////
      // Remove quotes from all paths
      // Escape trailing back-slash in paths
      // Add quotes to paths containing spaces
      // -->
      <options>
        <Value Condition="'%(Name)' == 'InputFile' OR '%(Name)' == 'OutputFile'
          OR '%(Name)' == 'IncludePath' OR '%(Name)' == 'MacFramework' OR '%(Name)' == 'PathPrefix'
          OR '%(Name)' == 'ForceInclude' OR '%(Name)' == 'PrependInclude' OR '%(Name)' == 'Include'
          OR '%(Name)' == 'OptionsFile'"
          >$([System.String]::Copy('%(Value)').Replace('&quot;', ''))</Value>
      </options>
      <options>
        <Value Condition="('%(Name)' == 'InputFile' OR '%(Name)' == 'OutputFile'
          OR '%(Name)' == 'IncludePath' OR '%(Name)' == 'MacFramework' OR '%(Name)' == 'PathPrefix'
          OR '%(Name)' == 'ForceInclude' OR '%(Name)' == 'PrependInclude' OR '%(Name)' == 'Include'
          OR '%(Name)' == 'OptionsFile')
          AND $([System.String]::Copy('%(Value)').Contains(' '))
          AND $([System.String]::Copy('%(Value)').EndsWith('\'))"
          >%(Value)\</Value>
      </options>
      <options>
        <Value Condition="('%(Name)' == 'InputFile' OR '%(Name)' == 'OutputFile'
          OR '%(Name)' == 'IncludePath' OR '%(Name)' == 'MacFramework' OR '%(Name)' == 'PathPrefix'
          OR '%(Name)' == 'ForceInclude' OR '%(Name)' == 'PrependInclude' OR '%(Name)' == 'Include'
          OR '%(Name)' == 'OptionsFile')
          AND $([System.String]::Copy('%(Value)').Contains(' '))"
          >&quot;%(Value)&quot;</Value>
      </options>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Generate tool command line arguments
    // -->
      <!--//  [header-file]               Header file to read from -->
      <options>
        <Value Condition="'%(Name)' == 'InputFile'">%(Value)</Value>
      </options>
      <!--//  -o <file>                   Write output to file -->
      <options>
        <Value Condition="'%(Name)' == 'OutputFile'">-o %(Value)</Value>
      </options>
      <!--//  -I <dir>                    Add dir to the include path for header files -->
      <options>
        <Value Condition="'%(Name)' == 'IncludePath'">-I%(Value)</Value>
      </options>
      <!--//  -F <framework>              Add macOS framework to the include path for headers -->
      <options>
        <Value Condition="'%(Name)' == 'MacFramework'">-F %(Value)</Value>
      </options>
      <!--//  -E                          Preprocess only; do not generate meta object code -->
      <options>
        <Value Condition="'%(Name)' == 'PreprocessOnly' AND '%(Value)' != 'true'"></Value>
      </options>
      <options>
        <Value Condition="'%(Name)' == 'PreprocessOnly' AND '%(Value)' == 'true'">-E</Value>
      </options>
      <!--//  -D <macro[=def]>            Define macro, with optional definition -->
      <options>
        <Value Condition="'%(Name)' == 'Define'">-D%(Value)</Value>
      </options>
      <!--//  -U <macro>                  Undefine macro-->
      <options>
        <Value Condition="'%(Name)' == 'Undefine'">-U%(Value)</Value>
      </options>
      <!--//  -M <key=value>              Add key/value pair to plugin meta data -->
      <options>
        <Value Condition="'%(Name)' == 'Metadata'">-M%(Value)</Value>
      </options>
      <!--//   -compiler-flavor <flavor>  Set the compiler flavor: either "msvc" or "unix" -->
      <options>
        <Value Condition="'%(Name)' == 'CompilerFlavor'">--compiler-flavor %(Value)</Value>
      </options>
      <!--//  -i                          Do not generate an #include statement -->
      <options>
        <Value Condition="'%(Name)' == 'NoInclude' AND '%(Value)' != 'true'"></Value>
      </options>
      <options>
        <Value Condition="'%(Name)' == 'NoInclude' AND '%(Value)' == 'true'">-i</Value>
      </options>
      <!--//  -p <path>                   Path prefix for included file -->
      <options>
        <Value Condition="'%(Name)' == 'PathPrefix'">-p%(Value)</Value>
      </options>
      <!--//  -f <file>                   Force #include <file> (overwrite default) -->
      <options>
        <Value Condition="'%(Name)' == 'ForceInclude'">-f %(Value)</Value>
      </options>
      <!--//  -b <file>                   Prepend #include <file> (preserve default include) -->
      <options>
        <Value Condition="'%(Name)' == 'PrependInclude'">-b %(Value)</Value>
      </options>
      <!--//   -include <file>            Parse <file> as an #include before the main source(s) -->
      <options>
        <Value Condition="'%(Name)' == 'Include'">--include %(Value)</Value>
      </options>
      <!--//  -n <which>                  Do not display notes (-nn) or warnings (-nw) -->
      <options>
        <Value Condition="'%(Name)' == 'NoNotesWarnings'">-n%(Value)</Value>
      </options>
      <!--//   -no-notes                  Do not display notes -->
      <options>
        <Value Condition="'%(Name)' == 'NoNotes' AND '%(Value)' != 'true'"></Value>
      </options>
      <options>
        <Value Condition="'%(Name)' == 'NoNotes' AND '%(Value)' == 'true'">--no-notes</Value>
      </options>
      <!--//   -no-warnings               Do not display warnings (implies  -no-notes) -->
      <options>
        <Value Condition="'%(Name)' == 'NoWarnings' AND '%(Value)' != 'true'"></Value>
      </options>
      <options>
        <Value Condition="'%(Name)' == 'NoWarnings' AND '%(Value)' == 'true'">--no-warnings</Value>
      </options>
      <!--//   -ignore-option-clashes     Ignore all options that conflict with compilers -->
      <options>
        <Value Condition="'%(Name)' == 'IgnoreConflicts' AND '%(Value)' != 'true'"></Value>
      </options>
      <options>
        <Value Condition="'%(Name)' == 'IgnoreConflicts' AND '%(Value)' == 'true'"
          >--ignore-option-clashes</Value>
      </options>
      <!--//  [@option-file]              Read additional options from option-file-->
      <options>
        <Value Condition="'%(Name)' == 'OptionsFile'">@%(Value)</Value>
      </options>
    </ItemGroup>
    <PropertyGroup>
      <options>@(options->'%(Value)', ' ')</options>
    </PropertyGroup>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Aux properties
    // -->
    <PropertyGroup>
      <!--// Force modified flag if source was manually selected to build -->
      <input_changed Condition="'$(SelectedFiles)' != ''"
        >true</input_changed>
      <input_changed Condition="'$(SelectedFiles)' == ''"
        >%(QtMoc.InputChanged)</input_changed>
      <!--// Run work in parallel processes -->
      <run_parallel Condition="'@(QtMoc)' != ''
        AND '%(QtMoc.ParallelProcess)' == 'true'
        AND '$(SelectedFiles)' == ''"
        >true</run_parallel>
      <!--// Run work in single process -->
      <run_single Condition="'@(QtMoc)' != ''
        AND ('%(QtMoc.ParallelProcess)' != 'true'
         OR '$(SelectedFiles)' != '')"
        >true</run_single>
      <!--// Get relative path to output -->
      <output_relative
>$([MSBuild]::MakeRelative($(ProjectDir), %(QtMoc.OutputFile)).TrimStart('\'))</output_relative>
      <!--// Get relative path to input -->
      <input_relative
>$([MSBuild]::MakeRelative($(ProjectDir), %(QtMoc.InputFile)).TrimStart('\'))</input_relative>
    </PropertyGroup>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Create work item
    // -->
    <ItemGroup Condition="'$(run_parallel)' == 'true' OR '$(run_single)' == 'true'">
      <QtWork Include="@(QtMoc)">
        <WorkType>moc</WorkType>
        <ToolPath Condition="'$(QtVsProjectSettings)' == 'true'"
          >$(QtToolsPath)/moc</ToolPath>
        <ToolPath Condition="'$(QtVsProjectSettings)' != 'true'"
          >%(QtMoc.QTDIR)\bin\moc.exe</ToolPath>
        <Options>$(options)</Options>
        <Message>%(QtMoc.ExecutionDescription)</Message>
        <DependenciesChanged>$(dependencies_changed)</DependenciesChanged>
        <InputChanged>$(input_changed)</InputChanged>
        <ParallelBuild Condition="'$(run_parallel)' == 'true'">true</ParallelBuild>
        <ParallelBuild Condition="'$(run_single)'   == 'true'">false</ParallelBuild>
        <!--
        ///////////////////////////////////////////////////////////////////////////////////////////
        // C++ dynamic source -->
        <ClCompile Condition="'%(QtMoc.DynamicSource)' == 'output'">$(output_relative)</ClCompile>
        <ClCompile Condition="'%(QtMoc.DynamicSource)' ==  'input'">$(input_relative)</ClCompile>
      </QtWork>
    </ItemGroup>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Clean-up
    // -->
    <PropertyGroup>
      <options/>
      <dependencies_changed/>
      <input_changed/>
      <run_parallel/>
      <run_single/>
      <output_relative/>
      <input_relative/>
    </PropertyGroup>
    <ItemGroup>
      <LocalOptions Remove="@(LocalOptions)"/>
      <options Remove="@(options)"/>
      <selected_files Remove="@(selected_files)"/>
    </ItemGroup>
  </Target>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Import dependants
  // -->
  <Import
    Condition="'$(QtMsBuildTargets_AfterMoc)' != ''"
    Project="$(QtMsBuildTargets_AfterMoc)"/>
</Project>
QtMSBuild/QtMsBuild/moc/qtmoc.xml
New file
@@ -0,0 +1,316 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
-->
<!--
///////////////////////////////////////////////////////////////////////////////////////////////////
// Defines the fields included in the moc property page, as well as any
// other metadata associated to QtMoc items
// -->
<ProjectSchemaDefinitions
  xmlns="http://schemas.microsoft.com/build/2009/properties"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:sys="clr-namespace:System;assembly=mscorlib">
  <Rule
    Name="QtRule30_Moc"
    PageTemplate="tool"
    DisplayName="Qt Meta-Object Compiler"
    Order="9">
    <Rule.DataSource>
      <DataSource
        Persistence="ProjectFile"
        ItemType="QtMoc" />
    </Rule.DataSource>
    <Rule.Categories>
      <Category
        Name="General">
        <Category.DisplayName>
          <sys:String>moc.exe</sys:String>
        </Category.DisplayName>
      </Category>
    </Rule.Categories>
    <StringListProperty
      Name="Inputs"
      Category="General"
      IsRequired="true"
      Visible="False">
      <StringListProperty.DataSource>
        <DataSource
           Persistence="ProjectFile"
           ItemType="QtMoc"
           SourceType="Item" />
      </StringListProperty.DataSource>
    </StringListProperty>
    <StringProperty
      Name="ExecutionDescription"
      DisplayName="Execution Description"
      IncludeInCommandLine="False"/>
    <StringProperty
      Name="QTDIR"
      DisplayName="Qt Directory"
      Description="Path to installation of Qt."/>
    <StringProperty
      Name="InputFile"
      HelpUrl="http://doc.qt.io/qt-5/moc.html"
      DisplayName="Input File"
      Description="Specifies the full path of the input file. (&lt;file&gt;)"
      Switch="&quot;[value]&quot;" />
    <StringProperty
      Name="OutputFile"
      Category="General"
      HelpUrl="http://doc.qt.io/qt-5/moc.html"
      DisplayName="Output File"
      Description="Specifies the full path of the output file. (-o &lt;file&gt;)"
      Switch="-o &quot;[value]&quot;" />
    <StringListProperty
      Name="IncludePath"
      HelpUrl="http://doc.qt.io/qt-5/moc.html"
      DisplayName="Include Path"
      Description=
"Add &lt;dir&gt; to the include path for header files; separate with semicolons if more than one.
(-I&lt;dir&gt;)"
      Switch="&quot;-I[value]&quot;" />
    <StringProperty
      Name="MacFramework"
      HelpUrl="http://doc.qt.io/qt-5/moc.html"
      DisplayName="macOS Framework"
      Description=
"Add macOS &lt;framework&gt; to the include path for header files. (-F &lt;framework&gt;)"
      Switch="-F &quot;[value]&quot;"
      Visible="False"/>
    <BoolProperty
      Name="PreprocessOnly"
      HelpUrl="http://doc.qt.io/qt-5/moc.html"
      DisplayName="Preprocess Only"
      Description="Preprocess only; do not generate meta object code. (-E)"
      Switch="-E"
      Visible="False"/>
    <StringListProperty
      Name="Define"
      HelpUrl="http://doc.qt.io/qt-5/moc.html"
      DisplayName="Macro Definitions"
      Description=
"Define macro, with optional definition; separate with semicolons if more than one.
(-D&lt;macro&gt;[=&lt;def&gt;])"
      Switch="-D " />
    <StringListProperty
      Name="Undefine"
      HelpUrl="http://doc.qt.io/qt-5/moc.html"
      DisplayName="Undefine Macro Definitions"
      Description="Undefine macro; separate with semicolons if more than one. (-U&lt;macro&gt;)"
      Switch="-U[value]" />
    <StringListProperty
      Name="Metadata"
      HelpUrl="http://doc.qt.io/qt-5/moc.html"
      DisplayName="Plugin Meta Data"
      Description=
"Add key/value pair to plugin meta data; separate with semicolons if more than one.
(-M&lt;key=value&gt;)"
      Switch="-M[value]" />
    <StringProperty
      Name="CompilerFlavor"
      HelpUrl="http://doc.qt.io/qt-5/moc.html"
      DisplayName="Compiler Flavor"
      Description=
"Set the compiler &lt;flavor&gt;: either &quot;msvc&quot; or &quot;unix&quot;.
(--compiler-flavor &lt;flavor&gt;)"
      Switch="--compiler-flavor [value]"/>
    <BoolProperty
      Name="NoInclude"
      HelpUrl="http://doc.qt.io/qt-5/moc.html"
      DisplayName="No Include"
      Description="Do not generate an #include statement. (-i)"
      Switch="-i"/>
    <StringProperty
      Name="PathPrefix"
      HelpUrl="http://doc.qt.io/qt-5/moc.html"
      DisplayName="Path Prefix"
      Description="&lt;path&gt; prefix for included file. (-p &lt;path&gt;)"
      Switch="-p [value]"/>
    <StringListProperty
      Name="ForceInclude"
      HelpUrl="http://doc.qt.io/qt-5/moc.html"
      DisplayName="Force Include"
      Description=
"Force #include &lt;file&gt; (overwrite default); separate with semicolons if more than one.
(-f &lt;file&gt;)"
      Switch="-f &quot;[value]&quot;"/>
    <StringListProperty
      Name="PrependInclude"
      HelpUrl="http://doc.qt.io/qt-5/moc.html"
      DisplayName="Prepend Include"
      Description=
"Prepend #include &lt;file&gt; (preserve default); separate with semicolons if more than one.
(-b &lt;file&gt;)"
      Switch="-b &quot;[value]&quot;"/>
    <StringListProperty
      Name="Include"
      HelpUrl="http://doc.qt.io/qt-5/moc.html"
      DisplayName="Include"
      Description=
"Parse &lt;file&gt; as an #include before the main source(s); separate with semicolons if more
than one. (--include &lt;file&gt;)"
      Switch="--include &quot;[value]&quot;"/>
    <StringListProperty
      Name="NoNotesWarnings"
      HelpUrl="http://doc.qt.io/qt-5/moc.html"
      DisplayName="No Notes Or Warnings"
      Description=
"Do not display notes (-nn) or warnings (-nw); Compatibility option; separate with semicolons if
more than one. (-n&lt;n|w&gt;)"
      Switch="-n[value]"
      Visible="False"/>
    <BoolProperty
      Name="NoNotes"
      HelpUrl="http://doc.qt.io/qt-5/moc.html"
      DisplayName="No Notes"
      Description="Do not display notes. (--no-notes)"
      Switch="--no-notes"/>
    <BoolProperty
      Name="NoWarnings"
      HelpUrl="http://doc.qt.io/qt-5/moc.html"
      DisplayName="No Warnings"
      Description="Do not display warnings (implies --no-notes). (--no-warnings)"
      Switch="--no-warnings"/>
    <BoolProperty
      Name="IgnoreConflicts"
      HelpUrl="http://doc.qt.io/qt-5/moc.html"
      DisplayName="Ignore Conflicts"
      Description=
"Ignore all options that conflict with compilers, like -pthread conflicting with moc's -p option.
(--ignore-option-clashes)"
      Switch="--ignore-option-clashes"/>
    <StringProperty
      Name="OptionsFile"
      HelpUrl="http://doc.qt.io/qt-5/moc.html"
      DisplayName="Options File"
      Description="Read additional command-line options from &lt;file&gt;. (@&lt;file&gt;)"
      Switch="&quot;@[value]&quot;" />
    <StringProperty
      Name="CommandLineTemplate"
      DisplayName="Command Line"
      Visible="False"
      IncludeInCommandLine="False" />
    <DynamicEnumProperty
      Name="QtMocBeforeTargets"
      Category="General"
      EnumProvider="Targets"
      IncludeInCommandLine="False" Visible="False">
      <DynamicEnumProperty.DisplayName>
        <sys:String>Execute Before</sys:String>
      </DynamicEnumProperty.DisplayName>
      <DynamicEnumProperty.Description>
        <sys:String>Specifies the targets for the build customization to run before.</sys:String>
      </DynamicEnumProperty.Description>
      <DynamicEnumProperty.ProviderSettings>
        <NameValuePair
          Name="Exclude"
          Value="^QtMocBeforeTargets|^Compute" />
      </DynamicEnumProperty.ProviderSettings>
      <DynamicEnumProperty.DataSource>
        <DataSource
          Persistence="ProjectFile"
          ItemType=""
          HasConfigurationCondition="true" />
      </DynamicEnumProperty.DataSource>
    </DynamicEnumProperty>
    <DynamicEnumProperty
      Name="QtMocAfterTargets"
      Category="General"
      EnumProvider="Targets"
      IncludeInCommandLine="False" Visible="False">
      <DynamicEnumProperty.DisplayName>
        <sys:String>Execute After</sys:String>
      </DynamicEnumProperty.DisplayName>
      <DynamicEnumProperty.Description>
        <sys:String>Specifies the targets for the build customization to run after.</sys:String>
      </DynamicEnumProperty.Description>
      <DynamicEnumProperty.ProviderSettings>
        <NameValuePair
          Name="Exclude"
          Value="^QtMocAfterTargets|^Compute" />
      </DynamicEnumProperty.ProviderSettings>
      <DynamicEnumProperty.DataSource>
        <DataSource
          Persistence="ProjectFile"
          ItemType=""
          HasConfigurationCondition="true" />
      </DynamicEnumProperty.DataSource>
    </DynamicEnumProperty>
    <StringListProperty
      Name="Outputs"
      DisplayName="Outputs"
      IncludeInCommandLine="False"
      Visible="False" />
    <StringListProperty
      Name="AdditionalDependencies"
      DisplayName="Additional Dependencies"
      IncludeInCommandLine="False"/>
    <StringProperty
      Subtype="AdditionalOptions"
      Name="AdditionalOptions"
      Category="General">
      <StringProperty.DisplayName>
        <sys:String>Additional Options</sys:String>
      </StringProperty.DisplayName>
      <StringProperty.Description>
        <sys:String>Additional Options</sys:String>
      </StringProperty.Description>
    </StringProperty>
    <EnumProperty
      Name="DynamicSource"
      DisplayName="Dynamic C++ Source"
      Description="Add file to list of C++ sources during build.">
      <EnumValue
        Name="output"
        DisplayName="Output File"
        Description="Use output as dynamic C++ source."/>
      <EnumValue
        Name="input"
        DisplayName="Input File"
        Description="Use input as dynamic C++ source."/>
      <EnumValue
        Name="false"
        DisplayName="Disable"
        Description="Disable dynamic source."/>
    </EnumProperty>
    <BoolProperty
      Name="ParallelProcess"
      DisplayName="Parallel Process"
      Description="Run tool in parallel process."/>
  </Rule>
  <ItemType
    Name="QtMoc"
    DisplayName="Qt Meta-Object Compiler (moc)" />
  <ContentType
    Name="QtMoc"
    DisplayName="Qt Meta-Object Compiler (moc)"
    ItemType="QtMoc" />
</ProjectSchemaDefinitions>
QtMSBuild/QtMsBuild/moc/qtmoc_cl.targets_TT
New file
@@ -0,0 +1,157 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
    *****************************************************************************
    **
    ** Copyright (C) 2019 The Qt Company Ltd.
    ** Contact: https://www.qt.io/licensing/
    **
    ** This file is part of the Qt VS Tools.
    **
    ** $QT_BEGIN_LICENSE:GPL-EXCEPT$
    ** Commercial License Usage
    ** Licensees holding valid commercial Qt licenses may use this file in
    ** accordance with the commercial license agreement provided with the
    ** Software or, alternatively, in accordance with the terms contained in
    ** a written agreement between you and The Qt Company. For licensing terms
    ** and conditions see https://www.qt.io/terms-conditions. For further
    ** information use the contact form at https://www.qt.io/contact-us.
    **
    ** GNU General Public License Usage
    ** Alternatively, this file may be used under the terms of the GNU
    ** General Public License version 3 as published by the Free Software
    ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
    ** included in the packaging of this file. Please review the following
    ** information to ensure the GNU General Public License requirements will
    ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
    **
    ** $QT_END_LICENSE$
    **
    *****************************************************************************
<#@output extension="targets" #>
<#@include file="$(SolutionDir)\common.tt" #>
<#@assembly Name="System.Xml" #>
<#@assembly Name="System.Xml.Linq" #>
<#@import namespace="System.Collections.Generic" #>
<#@import namespace="System.Linq" #>
<#@import namespace="System.Text" #>
<#@import namespace="System.Xml" #>
<#@import namespace="System.Xml.Linq" #>
<#
          var pathRuleCl = Path.Combine(VC_TARGETS_PATH, "1033", "cl.xml");
          var xmlRule = XmlLoad(File.ReadAllText(pathRuleCl, Encoding.UTF8));
#>
    **          <#=WARNING_GENERATED_FILE#>
    *****************************************************************************
-->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Target Name="QtMocOverrideCpp" DependsOnTargets="QtMocPrepare;QtGetDefaultClCompile"
    Inputs="%(QtMoc.Identity)" Outputs="@(QtMoc->'####### Don't skip this target #######')">
    <Message Importance="High" Condition="'$(QtDebug)' == 'true'"
      Text="## QtMocOverrideCpp @(QtMoc)" />
    <PropertyGroup Condition="'$(QtVsProjectClProperties)' == 'true'">
      <override_cl_compile>%(QtMoc.OverrideClCompile)</override_cl_compile>
    </PropertyGroup>
    <ItemGroup Condition="'$(override_cl_compile)' == 'extend'">
      <QtMoc>
        <!-- BEGIN Generated Text <#=XML_COMMENT_END#>
<#=
XmlPrint(xmlRule.Elements()
    .Where(x => x.Name.ToString().Equals("StringListProperty"))
    .Where(x => (string)x.Attribute("Visible") != "false")
    .Where(x => (string)x.Attribute("Category") != "Command Line")
    .Where(x => !x.Descendants("DataSource").Any())
    .Select(x => new XElement((string)x.Attribute("Name"),
        string.Format(
            "@(ClCompile->WithMetadataValue('Identity','DefaultClCompile')->'%({0})');%(QtMoc.{0})",
            (string)x.Attribute("Name")))))
#>
        <#=XML_COMMENT_BEGIN#> END Generated Text -->
      <AdditionalCppOptions
        Condition="'%(QtMoc.AdditionalCppOptions)' != ''"
        >@(ClCompile->
          WithMetadataValue('Identity','DefaultClCompile')->
          '%(AdditionalOptions)') %(QtMoc.AdditionalCppOptions)</AdditionalCppOptions>
      <AdditionalCppOptions
        Condition="'%(QtMoc.AdditionalCppOptions)' == ''"
        >@(ClCompile->
          WithMetadataValue('Identity','DefaultClCompile')->
          '%(AdditionalOptions)')</AdditionalCppOptions>
      </QtMoc>
      <QtMoc>
        <IncludePath>%(QtMoc.AdditionalIncludeDirectories)</IncludePath>
        <Define>%(QtMoc.PreprocessorDefinitions)</Define>
        <Undefine>%(QtMoc.UndefinePreprocessorDefinitions)</Undefine>
      </QtMoc>
    </ItemGroup>
    <ItemGroup Condition="'$(override_cl_compile)' == 'replace'">
      <QtMoc>
        <IncludePath Condition="'%(QtMoc.AdditionalIncludeDirectories)' != ''"
          >%(QtMoc.AdditionalIncludeDirectories)</IncludePath>
        <IncludePath Condition="'%(QtMoc.AdditionalIncludeDirectories)' == ''"
          >@(ClCompile->
            WithMetadataValue('Identity', 'DefaultClCompile')->
            '%(AdditionalIncludeDirectories)')</IncludePath>
        <Define Condition="'%(QtMoc.PreprocessorDefinitions)' != ''"
          >%(QtMoc.PreprocessorDefinitions)</Define>
        <Define Condition="'%(QtMoc.PreprocessorDefinitions)' == ''"
          >@(ClCompile->
            WithMetadataValue('Identity','DefaultClCompile')->
            '%(PreprocessorDefinitions)')</Define>
        <Undefine Condition="'%(QtMoc.UndefinePreprocessorDefinitions)' == ''"
          >%(QtMoc.UndefinePreprocessorDefinitions)</Undefine>
        <Undefine Condition="'%(QtMoc.UndefinePreprocessorDefinitions)' != ''"
          >@(ClCompile->
            WithMetadataValue('Identity','DefaultClCompile')->
            '%(UndefinePreprocessorDefinitions)')</Undefine>
      </QtMoc>
    </ItemGroup>
    <ItemGroup Condition="'$(override_cl_compile)' == 'false'">
      <QtMoc>
        <!-- BEGIN Generated Text <#=XML_COMMENT_END#>
<#=
XmlPrint(xmlRule.Elements()
    .Where(x => x.Name.ToString().EndsWith("Property"))
    .Where(x => (string)x.Attribute("Visible") != "false")
    .Where(x => (string)x.Attribute("Category") != "Command Line")
    .Where(x => !x.Descendants("DataSource").Any())
    .Select(x => new XElement((string)x.Attribute("Name"),
        new XAttribute("Condition",
            string.Format("'%(QtMoc.{0})' != ''", (string)x.Attribute("Name"))),
        string.Format(
            "@(ClCompile->WithMetadataValue('Identity','DefaultClCompile')->'%({0})')",
            (string)x.Attribute("Name")))))
#>
        <#=XML_COMMENT_BEGIN#> END Generated Text -->
        <IncludePath
          >@(ClCompile->
            WithMetadataValue('Identity','DefaultClCompile')->
            '%(AdditionalIncludeDirectories)')</IncludePath>
        <Define
          >@(ClCompile->
            WithMetadataValue('Identity','DefaultClCompile')->
            '%(PreprocessorDefinitions)')</Define>
        <Undefine
          >@(ClCompile->
            WithMetadataValue('Identity','DefaultClCompile')->
            '%(UndefinePreprocessorDefinitions)')</Undefine>
        <AdditionalCppOptions
          >@(ClCompile->
            WithMetadataValue('Identity','DefaultClCompile')->
            '%(AdditionalOptions)')</AdditionalCppOptions>
      </QtMoc>
    </ItemGroup>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Clean-up
    // -->
    <PropertyGroup>
      <override_cl_compile/>
    </PropertyGroup>
  </Target>
</Project>
QtMSBuild/QtMsBuild/moc/qtmoc_v3.xml_TT
New file
@@ -0,0 +1,356 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
    *****************************************************************************
    **
    ** Copyright (C) 2019 The Qt Company Ltd.
    ** Contact: https://www.qt.io/licensing/
    **
    ** This file is part of the Qt VS Tools.
    **
    ** $QT_BEGIN_LICENSE:GPL-EXCEPT$
    ** Commercial License Usage
    ** Licensees holding valid commercial Qt licenses may use this file in
    ** accordance with the commercial license agreement provided with the
    ** Software or, alternatively, in accordance with the terms contained in
    ** a written agreement between you and The Qt Company. For licensing terms
    ** and conditions see https://www.qt.io/terms-conditions. For further
    ** information use the contact form at https://www.qt.io/contact-us.
    **
    ** GNU General Public License Usage
    ** Alternatively, this file may be used under the terms of the GNU
    ** General Public License version 3 as published by the Free Software
    ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
    ** included in the packaging of this file. Please review the following
    ** information to ensure the GNU General Public License requirements will
    ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
    **
    ** $QT_END_LICENSE$
    **
    *****************************************************************************
<#@output extension="xml" #>
<#@include file="$(SolutionDir)\common.tt" #>
<#@assembly Name="System.Xml" #>
<#@assembly Name="System.Xml.Linq" #>
<#@import namespace="System.Collections.Generic" #>
<#@import namespace="System.Linq" #>
<#@import namespace="System.Text" #>
<#@import namespace="System.Xml" #>
<#@import namespace="System.Xml.Linq" #>
<#
          var pathRuleCl = Path.Combine(VC_TARGETS_PATH, "1033", "cl.xml");
          var xmlRule = XmlLoad(File.ReadAllText(pathRuleCl, Encoding.UTF8));
          var categoryNames = xmlRule
              .Elements("Rule.Categories")
              .Elements("Category")
              .Where(x => x.Attribute("Subtype") == null)
              .ToDictionary(
                  x => (string)x.Attribute("Name"),
                  x => (string)x.Attribute("DisplayName"));
#>
    **          <#=WARNING_GENERATED_FILE#>
    *****************************************************************************
-->
<ProjectSchemaDefinitions
  xmlns="http://schemas.microsoft.com/build/2009/properties"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:sys="clr-namespace:System;assembly=mscorlib">
  <Rule
    Name="QtRule30_Moc"
    PageTemplate="tool"
    DisplayName="Qt Meta-Object Compiler"
    Order="9">
    <Rule.DataSource>
      <DataSource
        Persistence="ProjectFile"
        ItemType="QtMoc" />
    </Rule.DataSource>
    <Rule.Categories>
      <Category Name="General" DisplayName="moc"/>
      <Category Name="MocCpp" DisplayName="Override C/C++"/>
    </Rule.Categories>
    <StringListProperty
      Name="Inputs"
      Category="General"
      IsRequired="true"
      Visible="False">
      <StringListProperty.DataSource>
        <DataSource
           Persistence="ProjectFile"
           ItemType="QtMoc"
           SourceType="Item" />
      </StringListProperty.DataSource>
    </StringListProperty>
    <StringProperty
      Name="ExecutionDescription"
      DisplayName="Execution Description"
      IncludeInCommandLine="False"/>
    <StringProperty
      Name="QtMocDir"
      Category="General"
      DisplayName="Output Directory"
      Description="Specifies the path of the generated moc output directory."/>
    <StringProperty
      Name="QtMocFileName"
      Category="General"
      DisplayName="Output File Name"
      Description="Specifies the name of the generated moc output file."/>
    <StringProperty
      Name="QTDIR"
      DisplayName="Qt Directory"
      Visible="false"/>
    <StringProperty
      Name="InputFile"
      DisplayName="Input File"
      Visible="false"/>
    <StringProperty
      Name="OutputFile"
      DisplayName="Output File"
      Visible="false"/>
    <StringProperty
      Name="MacFramework"
      HelpUrl="http://doc.qt.io/qt-5/moc.html"
      DisplayName="macOS Framework"
      Description=
"Add macOS &lt;framework&gt; to the include path for header files. (-F &lt;framework&gt;)"
      Switch="-F &quot;[value]&quot;"
      Visible="False"/>
    <BoolProperty
      Name="PreprocessOnly"
      HelpUrl="http://doc.qt.io/qt-5/moc.html"
      DisplayName="Preprocess Only"
      Description="Preprocess only; do not generate meta object code. (-E)"
      Switch="-E"
      Visible="False"/>
    <StringListProperty
      Name="Metadata"
      HelpUrl="http://doc.qt.io/qt-5/moc.html"
      DisplayName="Plugin Meta Data"
      Description=
"Add key/value pair to plugin meta data; separate with semicolons if more than one.
(-M&lt;key=value&gt;)"
      Switch="-M[value]" />
    <StringProperty
      Name="CompilerFlavor"
      HelpUrl="http://doc.qt.io/qt-5/moc.html"
      DisplayName="Compiler Flavor"
      Description=
"Set the compiler &lt;flavor&gt;: either &quot;msvc&quot; or &quot;unix&quot;.
(--compiler-flavor &lt;flavor&gt;)"
      Switch="--compiler-flavor [value]"/>
    <BoolProperty
      Name="NoInclude"
      HelpUrl="http://doc.qt.io/qt-5/moc.html"
      DisplayName="No Include"
      Description="Do not generate an #include statement. (-i)"
      Switch="-i"/>
    <StringProperty
      Name="PathPrefix"
      HelpUrl="http://doc.qt.io/qt-5/moc.html"
      DisplayName="Path Prefix"
      Description="&lt;path&gt; prefix for included file. (-p &lt;path&gt;)"
      Switch="-p [value]"/>
    <StringListProperty
      Name="ForceInclude"
      HelpUrl="http://doc.qt.io/qt-5/moc.html"
      DisplayName="Force Include"
      Description=
"Force #include &lt;file&gt; (overwrite default); separate with semicolons if more than one.
(-f &lt;file&gt;)"
      Switch="-f &quot;[value]&quot;"/>
    <StringListProperty
      Name="PrependInclude"
      HelpUrl="http://doc.qt.io/qt-5/moc.html"
      DisplayName="Prepend Include"
      Description=
"Prepend #include &lt;file&gt; (preserve default); separate with semicolons if more than one.
(-b &lt;file&gt;)"
      Switch="-b &quot;[value]&quot;"/>
    <StringListProperty
      Name="Include"
      HelpUrl="http://doc.qt.io/qt-5/moc.html"
      DisplayName="Include"
      Description=
"Parse &lt;file&gt; as an #include before the main source(s); separate with semicolons if more
than one. (--include &lt;file&gt;)"
      Switch="--include &quot;[value]&quot;"/>
    <StringListProperty
      Name="NoNotesWarnings"
      HelpUrl="http://doc.qt.io/qt-5/moc.html"
      DisplayName="No Notes Or Warnings"
      Description=
"Do not display notes (-nn) or warnings (-nw); Compatibility option; separate with semicolons if
more than one. (-n&lt;n|w&gt;)"
      Switch="-n[value]"
      Visible="False"/>
    <BoolProperty
      Name="NoNotes"
      HelpUrl="http://doc.qt.io/qt-5/moc.html"
      DisplayName="No Notes"
      Description="Do not display notes. (--no-notes)"
      Switch="--no-notes"/>
    <BoolProperty
      Name="NoWarnings"
      HelpUrl="http://doc.qt.io/qt-5/moc.html"
      DisplayName="No Warnings"
      Description="Do not display warnings (implies --no-notes). (--no-warnings)"
      Switch="--no-warnings"/>
    <BoolProperty
      Name="IgnoreConflicts"
      HelpUrl="http://doc.qt.io/qt-5/moc.html"
      DisplayName="Ignore Conflicts"
      Description=
"Ignore all options that conflict with compilers, like -pthread conflicting with moc's -p option.
(--ignore-option-clashes)"
      Switch="--ignore-option-clashes"/>
    <StringProperty
      Name="OptionsFile"
      HelpUrl="http://doc.qt.io/qt-5/moc.html"
      DisplayName="Options File"
      Description="Read additional command-line options from &lt;file&gt;. (@&lt;file&gt;)"
      Switch="&quot;@[value]&quot;" />
    <StringProperty
      Name="CommandLineTemplate"
      DisplayName="Command Line"
      Visible="False"
      IncludeInCommandLine="False" />
    <DynamicEnumProperty
      Name="QtMocBeforeTargets"
      Category="General"
      EnumProvider="Targets"
      IncludeInCommandLine="False" Visible="False">
      <DynamicEnumProperty.DisplayName>
        <sys:String>Execute Before</sys:String>
      </DynamicEnumProperty.DisplayName>
      <DynamicEnumProperty.Description>
        <sys:String>Specifies the targets for the build customization to run before.</sys:String>
      </DynamicEnumProperty.Description>
      <DynamicEnumProperty.ProviderSettings>
        <NameValuePair
          Name="Exclude"
          Value="^QtMocBeforeTargets|^Compute" />
      </DynamicEnumProperty.ProviderSettings>
      <DynamicEnumProperty.DataSource>
        <DataSource
          Persistence="ProjectFile"
          ItemType=""
          HasConfigurationCondition="true" />
      </DynamicEnumProperty.DataSource>
    </DynamicEnumProperty>
    <DynamicEnumProperty
      Name="QtMocAfterTargets"
      Category="General"
      EnumProvider="Targets"
      IncludeInCommandLine="False" Visible="False">
      <DynamicEnumProperty.DisplayName>
        <sys:String>Execute After</sys:String>
      </DynamicEnumProperty.DisplayName>
      <DynamicEnumProperty.Description>
        <sys:String>Specifies the targets for the build customization to run after.</sys:String>
      </DynamicEnumProperty.Description>
      <DynamicEnumProperty.ProviderSettings>
        <NameValuePair
          Name="Exclude"
          Value="^QtMocAfterTargets|^Compute" />
      </DynamicEnumProperty.ProviderSettings>
      <DynamicEnumProperty.DataSource>
        <DataSource
          Persistence="ProjectFile"
          ItemType=""
          HasConfigurationCondition="true" />
      </DynamicEnumProperty.DataSource>
    </DynamicEnumProperty>
    <StringListProperty
      Name="Outputs"
      DisplayName="Outputs"
      IncludeInCommandLine="False"
      Visible="False" />
    <StringListProperty
      Name="AdditionalDependencies"
      DisplayName="Additional Dependencies"
      IncludeInCommandLine="False"/>
    <StringProperty
      Subtype="AdditionalOptions"
      Name="AdditionalOptions"
      Category="General">
      <StringProperty.DisplayName>
        <sys:String>Additional Options</sys:String>
      </StringProperty.DisplayName>
      <StringProperty.Description>
        <sys:String>Additional Options</sys:String>
      </StringProperty.Description>
    </StringProperty>
    <EnumProperty
      Name="DynamicSource"
      DisplayName="Dynamic C++ Source"
      Description="Add file to list of C++ sources during build.">
      <EnumValue
        Name="output"
        DisplayName="Output File"
        Description="Use output as dynamic C++ source."/>
      <EnumValue
        Name="input"
        DisplayName="Input File"
        Description="Use input as dynamic C++ source."/>
      <EnumValue
        Name="false"
        DisplayName="Disable"
        Description="Disable dynamic source."/>
    </EnumProperty>
    <BoolProperty
      Name="ParallelProcess"
      DisplayName="Parallel Process"
      Description="Run tool in parallel process."/>
    <StringListProperty Name="IncludePath" Visible="false"/>
    <StringListProperty Name="Define" Visible="false"/>
    <StringListProperty Name="Undefine" Visible="false"/>
    <EnumProperty
      Name="OverrideClCompile"
      Category="MocCpp"
      DisplayName="Override C/C++ Properties"
      Description="Define how C/C++ properties are redefined for moc">
      <EnumValue Name="extend" DisplayName=
"Extend (append override definitions to C/C++ list properties; replace other properties)"/>
      <EnumValue Name="replace" DisplayName=
"Replace (use override definitions instead of C/C++ properties)"/>
      <EnumValue Name="false" DisplayName=
"Disabled (use C/C++ properties; ignore override definitions)"/>
    </EnumProperty>
    <!-- BEGIN Generated Text <#=XML_COMMENT_END#>
<#=
XmlPrint(xmlRule.Elements()
    .Where(x => x.Name.ToString().EndsWith("Property"))
    .Where(x => (string)x.Attribute("Visible") != "false")
    .Where(x => (string)x.Attribute("Category") != "Command Line")
    .Where(x => !x.Descendants("DataSource").Any())
    .GroupBy(x => (string)x.Attribute("Category"))
    .SelectMany(y => y.Select(x =>
    {
        x = new XElement(x);
        x.SetAttributeValue("Category", "MocCpp");
        x.SetAttributeValue("Description", "(overrides C/C++ property) "
            + (string)x.Attribute("Description"));
        return x;
    })
    .Prepend(new XElement("StringProperty",
        new XAttribute("Name", "QtCppHeader_" + y.Key.Replace(' ', '_')),
        new XAttribute("Category", "MocCpp"),
        new XAttribute("ReadOnly", "true"),
        new XAttribute("DisplayName", string.Format("{0} {1} {2}",
            new string('#', 10), categoryNames[y.Key], new string('#', 30)))))))
#>
      <#=XML_COMMENT_BEGIN#> END Generated Text -->
    <StringProperty
      Name="AdditionalCppOptions"
      DisplayName="Additional Options"
      Description="Additional Options."
      Category="MocCpp"/>
  </Rule>
  <ItemType
    Name="QtMoc"
    DisplayName="Qt Meta-Object Compiler (moc)" />
  <ContentType
    Name="QtMoc"
    DisplayName="Qt Meta-Object Compiler (moc)"
    ItemType="QtMoc" />
</ProjectSchemaDefinitions>
QtMSBuild/QtMsBuild/qml/qt_import.props
New file
@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/****************************************************************************
**
** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
-->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Qt/MSBuild import
  // -->
  <PropertyGroup>
    <QtMsBuildProps_AfterRcc>
      $(QtMsBuildProps_AfterRcc);
      $(MSBuildThisFileDirectory)qtqml.props;
      $(MSBuildThisFileDirectory)qtqml_cache.props;
      $(MSBuildThisFileDirectory)qtqml_static.props
    </QtMsBuildProps_AfterRcc>
    <QtMsBuildTargets_AfterRcc>
      $(QtMsBuildTargets_AfterRcc);
      $(MSBuildThisFileDirectory)qtqml.targets;
      $(MSBuildThisFileDirectory)qtqml_cache.targets;
      $(MSBuildThisFileDirectory)qtqml_static.targets
    </QtMsBuildTargets_AfterRcc>
  </PropertyGroup>
</Project>
QtMSBuild/QtMsBuild/qml/qtqml.props
New file
@@ -0,0 +1,59 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
-->
<!--
///////////////////////////////////////////////////////////////////////////////////////////////////
// Qt/MSBuild QML property definitions
// -->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Import pre-requisites
  // -->
  <Import
    Condition="'$(QtMsBuildProps_BeforeQml)' != ''"
    Project="$(QtMsBuildProps_BeforeQml)"/>
  <!-- Default QML work dir = $(IntDir)\qml
         * can be overridden in property sheets -->
  <PropertyGroup>
    <QtQmlIntDir Condition="'$(QtQmlIntDir)' == ''"
      >$([System.IO.Path]::Combine('$(ProjectDir)', '$(IntDir)', 'qml'))</QtQmlIntDir>
  </PropertyGroup>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Import dependants
  // -->
  <Import
    Condition="'$(QtMsBuildProps_AfterQml)' != ''"
    Project="$(QtMsBuildProps_AfterQml)"/>
</Project>
QtMSBuild/QtMsBuild/qml/qtqml.targets
New file
@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
-->
<!--
///////////////////////////////////////////////////////////////////////////////////////////////////
// QML targets
// -->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Import pre-requisites
  // -->
  <Import
    Condition="'$(QtMsBuildTargets_BeforeQml)' != ''"
    Project="$(QtMsBuildTargets_BeforeQml)"/>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Qt/MSBuild global properties
  //  * add QtQml to the list of targets to run during build
  // -->
  <PropertyGroup>
    <QtBuildTargets>$(QtBuildTargets);QtQml</QtBuildTargets>
  </PropertyGroup>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // QML build entry point
  // -->
  <Target Name="QtQml" DependsOnTargets="QtQmlCreateItems">
  </Target>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Create QtQml items for project files with extension '.qml' or '.js'
  // -->
  <Target Name="QtQmlCreateItems">
    <ItemGroup>
      <QtQml Include="@(None)"
        Condition="'%(None.Extension)' == '.qml' OR '%(None.Extension)' == '.js'" />
    </ItemGroup>
  </Target>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Import dependants
  // -->
  <Import
    Condition="'$(QtMsBuildTargets_AfterQml)' != ''"
    Project="$(QtMsBuildTargets_AfterQml)"/>
</Project>
QtMSBuild/QtMsBuild/qml/qtqml_cache.props
New file
@@ -0,0 +1,84 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/****************************************************************************
**
** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
-->
<!--
///////////////////////////////////////////////////////////////////////////////////////////////////
// Qt/MSBuild QML property definitions
// -->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Import pre-requisites
  // -->
  <Import
    Condition="'$(QtMsBuildProps_BeforeQmlCache)' != ''"
    Project="$(QtMsBuildProps_BeforeQmlCache)"/>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // QtRcc item template, QML cache generation properties
  // -->
  <ItemDefinitionGroup>
    <QtRcc>
      <QmlCacheGenerate>false</QmlCacheGenerate>
      <!--
      // QML cache generation -->
      <QmlCacheGenMessage
        ><![CDATA[Qt Quick Compiler: compiling %<Identity> ahead of time]]></QmlCacheGenMessage>
      <QmlCacheOutputFile
        ><![CDATA[$(ProjectDir)GeneratedFiles\%<Filename>_%<Suffix>.cpp]]></QmlCacheOutputFile>
      <!--
      // QRC filtering -->
      <QmlCacheFilterMessage
        >Qt Quick Compiler: filtering %(Identity)</QmlCacheFilterMessage>
      <QmlCacheFilteredFile
        >$(ProjectDir)GeneratedFiles\%(Filename)_qmlcache.qrc</QmlCacheFilteredFile>
      <QmlCacheFilteredOutputFile
        >$(ProjectDir)GeneratedFiles\qrc_%(Filename)_qmlcache.cpp</QmlCacheFilteredOutputFile>
      <QmlCacheFilteredInitFuncName
        >%(Filename)_qmlcache</QmlCacheFilteredInitFuncName>
      <!--
      // QML cache loader generation -->
      <QmlCacheLoaderMessage
        >Qt Quick Compiler: generating cache loader</QmlCacheLoaderMessage>
      <QmlCacheLoaderFile
        >$(ProjectDir)GeneratedFiles\qmlcache_loader.cpp</QmlCacheLoaderFile>
    </QtRcc>
  </ItemDefinitionGroup>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Import dependants
  // -->
  <Import
    Condition="'$(QtMsBuildProps_AfterQmlCache)' != ''"
    Project="$(QtMsBuildProps_AfterQmlCache)"/>
</Project>
QtMSBuild/QtMsBuild/qml/qtqml_cache.targets
New file
@@ -0,0 +1,625 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
-->
<!--
///////////////////////////////////////////////////////////////////////////////////////////////////
// Targets required to build the QML cache (aka. qtquickcompiler)
// -->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Import pre-requisites
  // -->
  <Import
    Condition="'$(QtMsBuildTargets_BeforeQmlCache)' != ''"
    Project="$(QtMsBuildTargets_BeforeQmlCache)"/>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Qt/MSBuild global properties
  // -->
  <PropertyGroup>
    <QtBuildTargets>$(QtBuildTargets);QtQmlCache</QtBuildTargets>
    <QtRccDependsOn>$(QtRccDependsOn);QtQmlCache</QtRccDependsOn>
  </PropertyGroup>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // TARGET QtQmlCachePrepare
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Pre-process rcc source files marked for QML cache generation
  // -->
  <Target Name="QtQmlCachePrepare"
    DependsOnTargets="QtRccSetDependencies"
    BeforeTargets="QtRccPrepare" Condition="'@(QtRcc)' != ''"
    Inputs="%(QtRcc.Identity)" Outputs="@(QtRcc->'####### Don't skip this target #######')">
    <ItemGroup>
      <selected_files Include="$(SelectedFiles)"/>
    </ItemGroup>
    <Message Importance="High" Condition="'$(QtDebug)' == 'true'"
      Text="## QtQmlCachePrepare %(QtRcc.Identity)" />
    <!--// Remove sources excluded from build -->
    <ItemGroup>
      <QtRcc Remove="@(QtRcc)"
        Condition="'$(SelectedFiles)' == '' AND '%(QtRcc.ExcludedFromBuild)' == 'true'"/>
    </ItemGroup>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // $(is_selected) ::= file is selected to build
    // -->
    <PropertyGroup>
      <selected_files>[@(selected_files->'%(Identity)','][')]</selected_files>
      <file>[@(QtRcc->'%(Identity)')]</file>
      <output_file>@(QtRcc->'%(OutputFile)')</output_file>
      <is_selected
        Condition="'@(selected_files)' == '' OR $(selected_files.Contains('$(file)'))"
        >true</is_selected>
      <is_selected
        Condition="'@(selected_files)' != '' AND !$(selected_files.Contains('$(file)'))"
        >false</is_selected>
    </PropertyGroup>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Parse QRC file
    // @(res_file)    ::= names of resource files
    // @(res_qml_js)  ::= names of QML and JS resource files
    // @(res_other)   ::= names of other resource files
    // -->
    <ItemGroup>
      <res_file
        Condition="'@(QtRcc)' != '' AND '%(QtRcc.QmlCacheGenerate)' == 'true'"
        Include="%(QtRcc.ResourceFiles)"/>
    </ItemGroup>
    <ItemGroup Condition="'@(res_file)' != ''">
      <res_qml_js Include="%(res_file.Identity)"
        Condition="'%(res_file.Extension)' == '.qml' OR '%(res_file.Extension)' == '.js'"/>
      <res_other Include="%(res_file.Identity)"
        Condition="'%(res_file.Extension)' != '.qml' AND '%(res_file.Extension)' != '.js'"/>
    </ItemGroup>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Expand QML and JS build items
    // -->
    <ItemGroup Condition="'@(res_qml_js)' != ''">
      <template Include="template">
        <InputFile><![CDATA[%<FullPath>]]></InputFile>
        <OutputFile>@(QtRcc->'%(QmlCacheOutputFile)')</OutputFile>
        <Message>@(QtRcc->'%(QmlCacheGenMessage)')</Message>
        <Outputs>%(OutputFile)</Outputs>
        <ResourceFile>@(QtRcc->'%(FullPath)')</ResourceFile>
        <IsSelected>$(is_selected)</IsSelected>
        <AdditionalDependencies>@(QtRcc)</AdditionalDependencies>
      </template>
    </ItemGroup>
    <!--
    // @(QtQmlCacheItem) ::= QML and JS resource files to be cached -->
    <Expand Condition="'@(res_qml_js)' != ''"
      Items="@(res_qml_js)" BaseItem="@(QtRcc)" Template="@(template)">
      <Output TaskParameter="Result" ItemName="QtQmlCacheItem"/>
    </Expand>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Convert rcc sources to QML cache generation filter sources
    // -->
    <ItemGroup Condition="'@(QtQmlCacheItem)' != ''">
      <!--
      // @(QtRccFilter) ::= QRC files to be filtered -->
      <QtRccFilter Include="@(QtRcc)">
        <QtQmlCacheItems>@(QtQmlCacheItem)</QtQmlCacheItems>
        <OtherResources>@(res_other->'%(Identity)')</OtherResources>
        <InputChanged>false</InputChanged>
        <OutputFile>%(QtRcc.QmlCacheFilteredFile)</OutputFile>
        <Outputs>%(QtRcc.QmlCacheFilteredFile)</Outputs>
        <IsSelected>$(is_selected)</IsSelected>
      </QtRccFilter>
      <QtRcc Remove="@(QtRcc)"/>
    </ItemGroup>
    <!--
    // Delete output file to force build of source if it was manually selected to build
    //  (e.g. by the 'Compile' option in the context menu for the file) -->
    <Delete
      Condition="'$(SelectedFiles)' != '' AND '$(is_selected)' == 'true'"
      Files="%(QtRccFilter.OutputFile)"/>
    <Delete
      Condition="'$(SelectedFiles)' != '' AND '$(is_selected)' == 'true'"
      Files="%(QtQmlCacheItem.OutputFile)"/>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Clean-up
    // -->
    <PropertyGroup>
      <selected_files/>
      <file/>
      <output_file/>
      <is_selected/>
    </PropertyGroup>
    <ItemGroup>
      <res_file Remove="@(res_file)"/>
      <res_qml_js Remove="@(res_qml_js)"/>
      <res_other Remove="@(res_other)"/>
      <template Remove="@(res_other)"/>
    </ItemGroup>
  </Target>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // TARGET QtRccFilterSetModified
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Set InputModified flag for modified files (i.e. Inputs newer than Outputs)
  // -->
  <Target Name="QtRccFilterSetModified" DependsOnTargets="QtQmlCachePrepare"
    Inputs="%(QtRccFilter.FullPath);%(QtRccFilter.AdditionalDependencies)"
    Outputs="@(QtRccFilter->'%(OutputFile)')">
    <Message Importance="High" Condition="'$(QtDebug)' == 'true' AND '@(QtRccFilter)' != ''"
      Text="## QtRccFilterSetModified %(QtRccFilter.Identity) => %(QtRccFilter.OutputFile)"/>
    <PropertyGroup>
      <input_changed/>
    </PropertyGroup>
    <CreateProperty Condition="'@(QtRccFilter)' != ''" Value="true">
      <Output TaskParameter="ValueSetByTask" PropertyName="input_changed" />
    </CreateProperty>
    <ItemGroup>
      <QtRccFilter>
        <InputChanged>$(input_changed)</InputChanged>
        <IsSelected Condition="'$(input_changed)' == 'true'">true</IsSelected>
      </QtRccFilter>
    </ItemGroup>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Clean-up
    // -->
    <PropertyGroup>
      <input_changed/>
    </PropertyGroup>
  </Target>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // TARGET QtRccFilter
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Filter QRC file:
  //    - Filter QML and JS resources from QRC
  //    - If other resources are present, generate new QRC with filtered contents
  //    - Collect data to use in cache loader generation
  // -->
  <Target Name="QtRccFilter" DependsOnTargets="QtRccFilterSetModified"
    Inputs="%(QtRccFilter.FullPath);%(QtRccFilter.AdditionalDependencies);$(MSBuildProjectFile)"
    Outputs="@(QtRccFilter->'%(OutputFile)')">
    <Message Importance="High" Condition="'$(QtDebug)' == 'true'"
      Text="## QtRccFilter %(QtRccFilter.Identity) => @(QtRccFilter->'%(OutputFile)')" />
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Set DependenciesChanged flag for modified files or dependencies
    // -->
    <PropertyGroup>
      <dependencies_changed/>
    </PropertyGroup>
    <CreateProperty Value="true">
      <Output TaskParameter="ValueSetByTask" PropertyName="dependencies_changed" />
    </CreateProperty>
    <ItemGroup>
      <QtRccFilter>
        <DependenciesChanged>$(dependencies_changed)</DependenciesChanged>
      </QtRccFilter>
    </ItemGroup>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // @(input_file)    ::= QRC file to filter
    // @(filtered_file) ::= filtered QRC file
    // -->
    <ItemGroup>
      <input_file Include="%(QtRccFilter.InputFile)"
        Condition="'%(QtRccFilter.QtQmlCacheItems)' != '' AND '%(QtRccFilter.InputFile)' != ''"/>
      <filtered_file Include="%(QtRccFilter.QmlCacheFilteredFile)"
        Condition="'%(QtRccFilter.QmlCacheFilteredFile)' != ''"/>
    </ItemGroup>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Prepare qmlcachegen command for QRC filtering
    // -->
    <PropertyGroup>
      <!--
      // $(options) ::= qmlcachegen command line options -->
      <options Condition="'%(QtRccFilter.QtQmlCacheItems)' != '' AND '@(input_file)' != ''"
        >$(options) @(input_file->'--filter-resource-file &quot;%(Identity)&quot;')</options>
      <options Condition="'%(QtRccFilter.QtQmlCacheItems)' != '' AND '@(filtered_file)' != ''"
        >$(options) @(filtered_file->'-o &quot;%(Identity)&quot;')</options>
      <!--
      // $(full_path) ::= full path of filtered file -->
      <full_path Condition="'%(QtRccFilter.QtQmlCacheItems)' != ''"
>$([System.IO.Path]::Combine($(MSBuildProjectDirectory),%(QmlCacheFilteredFile)))</full_path>
      <!--
      // $(relative_path) ::= path of filtered file, relative to project directory -->
      <relative_path Condition="'%(QtRccFilter.QtQmlCacheItems)' != ''"
>$([MSBuild]::MakeRelative($(MSBuildProjectDirectory),$(full_path)).TrimStart('\'))</relative_path>
      <!--
      // $(run_parallel) ::= run qmlcachegen in a parallel process
      // $(run_single)   ::= run qmlcachegen in single process mode -->
      <run_parallel Condition="'@(QtRccFilter)' != ''
        AND '%(QtRccFilter.ParallelProcess)' == 'true' AND '$(SelectedFiles)' == ''"
      >true</run_parallel>
      <run_single Condition="'@(QtRccFilter)' != ''
        AND ('%(QtRccFilter.ParallelProcess)' != 'true' OR '$(SelectedFiles)' != '')"
      >true</run_single>
    </PropertyGroup>
    <ItemGroup Condition="'@(QtRccFilter)' != ''">
      <!--
      /////////////////////////////////////////////////////////////////////////////////////////////
      // Create work item for QRC filtering
      // -->
      <QtWork
        Include="@(QtRccFilter)"
        Condition="'%(QtRccFilter.QtQmlCacheItems)' != ''
          AND '%(QtRccFilter.OtherResources)' != ''
          AND '%(QtRccFilter.IsSelected)' == 'true'">
        <WorkType>qmlcachegen_filter</WorkType>
        <ToolPath Condition="'$(QtVsProjectSettings)' == 'true'"
          >$(QtToolsPath)\qmlcachegen.exe</ToolPath>
        <ToolPath Condition="'$(QtVsProjectSettings)' != 'true'"
          >%(QtRccFilter.QTDIR)\bin\qmlcachegen.exe</ToolPath>
        <Options>$(options)</Options>
        <OutputFile>$(full_path)</OutputFile>
        <Message>%(QtRccFilter.QmlCacheFilterMessage)</Message>
        <ParallelBuild Condition="'$(run_parallel)' == 'true'">true</ParallelBuild>
        <ParallelBuild Condition="'$(run_single)'   == 'true'">false</ParallelBuild>
      </QtWork>
      <!--
      /////////////////////////////////////////////////////////////////////////////////////////////
      // Create build item for generated QRC file
      // -->
      <QtRcc Condition="'%(QtRccFilter.QtQmlCacheItems)' != ''
          AND '%(QtRccFilter.OtherResources)' != ''"
        Include="@(QtRccFilter->'$(relative_path)')">
        <InputFile>@(QtRccFilter->'%(QmlCacheFilteredFile)')</InputFile>
        <OutputFile>@(QtRccFilter->'%(QmlCacheFilteredOutputFile)')</OutputFile>
        <InitFuncName>@(QtRccFilter->'%(QmlCacheFilteredInitFuncName)')</InitFuncName>
        <DependsOn>@(QtRccFilter)</DependsOn>
      </QtRcc>
    </ItemGroup>
    <!--
    /////////////////////////////////////////////////////////////////////////////////////////////
    // If sources were manually selected (e.g. by the 'Compile' option in the context menu for
    // project items), add generated QRC to the list of selected files
    // -->
    <PropertyGroup>
      <selected_rcc
        Condition="'$(SelectedFiles)' != ''
          AND '%(QtRccFilter.IsSelected)' == 'true'
          AND '%(QtRccFilter.QtQmlCacheItems)' != ''
          AND '%(QtRccFilter.OtherResources)' != ''"
        >$(relative_path)</selected_rcc>
    </PropertyGroup>
    <PropertyGroup Condition="'$(selected_rcc)' != ''">
      <SelectedFiles>$(SelectedFiles);$(selected_rcc)</SelectedFiles>
    </PropertyGroup>
    <ItemGroup Condition="'$(selected_rcc)' != ''">
      <selected_files Include="$(selected_rcc)"/>
      <SelectedFiles Include="$(selected_rcc)"/>
    </ItemGroup>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Update timestamp of generated QRC file to force rcc target to run
    // -->
    <MakeDir Directories="$([System.IO.Path]::GetDirectoryName(%(QtRccFilter.OutputFile)))"/>
    <Touch Condition="'%(QtRccFilter.InputChanged)' == 'true'"
      AlwaysCreate="true" Files="%(QtRccFilter.OutputFile)"/>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Create loader input item, used in cache loader generation
    // -->
    <ItemGroup Condition="'@(QtRccFilter)' != ''">
      <loader_input Include="@(QtRccFilter->'QtQmlCacheLoader')">
        <Inputs>%(QtRccFilter.Identity)</Inputs>
        <InputFile>%(QtRccFilter.InputFile)</InputFile>
        <Mapping Condition="'%(QtRccFilter.QtQmlCacheItems)' != '' AND '%(QtRccFilter.OtherResources)' != ''"
          >%(QtRccFilter.InputFile)=$(full_path)</Mapping>
      </loader_input>
    </ItemGroup>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Clean-up
    // -->
    <ItemGroup>
      <input_file Remove="@(input_file)"/>
      <filtered_file Remove="@(filtered_file)"/>
    </ItemGroup>
    <PropertyGroup>
      <dependencies_changed/>
      <options/>
      <full_path/>
      <relative_path/>
      <run_parallel/>
      <run_single/>
      <selected_rcc/>
    </PropertyGroup>
  </Target>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // TARGET QtQmlCacheLoader
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Generate QML cache loader
  // -->
  <Target Name="QtQmlCacheLoader" DependsOnTargets="QtRccFilter">
    <Message Importance="High" Condition="'$(QtDebug)' == 'true'"
      Text="## QtQmlCacheLoader @(QtQmlCacheLoader->'%(Inputs)')" />
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Get QML cache loader properties from project rcc property page
    // -->
    <ItemGroup>
      <QtRcc Include="qmlcachengen_loader"/>
      <loader Include="@(QtRcc)" Condition="'%(QtRcc.Identity)' == 'qmlcachengen_loader'"/>
    </ItemGroup>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Generate QML cache loader
    // -->
    <PropertyGroup>
      <!--
      // $(options) ::= qmlcachegen command line options -->
      <options Condition="'@(loader_input)' != ''"
        >$(options) @(loader_input->'--resource-file-mapping=&quot;%(Mapping)&quot;',' ')</options>
      <options Condition="'@(loader_input)' != ''"
        >$(options) @(loader_input->'&quot;%(InputFile)&quot;',' ')</options>
      <options Condition="'@(loader)' != ''"
        >$(options) @(loader->'-o &quot;%(QmlCacheLoaderFile)&quot;')</options>
      <!--
      // $(run_parallel) ::= run qmlcachegen in a parallel process
      // $(run_single)   ::= run qmlcachegen in single process mode -->
      <run_parallel Condition="'@(QtQmlCacheLoader)' != ''
        AND '%(loader.ParallelProcess)' == 'true' AND '$(SelectedFiles)' == ''">true</run_parallel>
      <run_single Condition="'@(QtQmlCacheLoader)' != ''
        AND ('%(loader.ParallelProcess)' != 'true' OR  '$(SelectedFiles)' != '')">true</run_single>
      <!--
      // $(dependencies_changed)  ::= source QRC files changed status
      // $(input_changed)         ::= source QRC files input changed status -->
      <dependencies_changed>@(loader_input->'%(DependenciesChanged)')</dependencies_changed>
      <input_changed>@(loader_input->'%(InputChanged)')</input_changed>
      <input_changed Condition="!Exists('@(loader->'%(QmlCacheLoaderFile)')')">true</input_changed>
      <is_selected>@(loader_input->'%(IsSelected)')</is_selected>
      <!--// Get relative path to output -->
      <cache_loader_path>@(loader->'%(QmlCacheLoaderFile)')</cache_loader_path>
      <output_relative
>$([MSBuild]::MakeRelative($(ProjectDir), $(cache_loader_path)).TrimStart('\'))</output_relative>
    </PropertyGroup>
    <ItemGroup>
      <!--
      //  Create work item to generate QML cache loader -->
      <QtWork
        Include="qmlcachengen_loader"
        Condition="'@(loader_input)' != ''
          AND $(is_selected.Contains('true'))">
        <WorkType>qmlcachengen_loader</WorkType>
        <ToolPath Condition="'$(QtVsProjectSettings)' == 'true'"
          >$(QtToolsPath)\qmlcachegen.exe</ToolPath>
        <ToolPath Condition="'$(QtVsProjectSettings)' != 'true'"
          >@(loader->'%(QTDIR)')\bin\qmlcachegen.exe</ToolPath>
        <Options>$(options)</Options>
        <OutputFile>@(loader->'%(QmlCacheLoaderFile)')</OutputFile>
        <Message>@(loader->'%(QmlCacheLoaderMessage)')</Message>
        <ParallelBuild Condition="'$(run_parallel)' == 'true'">true</ParallelBuild>
        <ParallelBuild Condition="'$(run_single)'   == 'true'">false</ParallelBuild>
        <DisableLog>true</DisableLog>
        <DependenciesChanged>$(dependencies_changed.Contains('true'))</DependenciesChanged>
        <InputChanged>$(input_changed.Contains('true'))</InputChanged>
        <ClCompile Condition="'%(loader.DynamicSource)' != 'false'">$(output_relative)</ClCompile>
        <DependsOn>@(loader_input->'%(Inputs)')</DependsOn>
      </QtWork>
    </ItemGroup>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Clean-up
    // -->
    <ItemGroup>
      <loader_mapping_option  Remove="@(mapping_option)"/>
      <loader_input_option    Remove="@(loader_input_option)"/>
      <loader                 Remove="@(loader)"/>
      <QtRcc                  Remove="qmlcachengen_loader"/>
    </ItemGroup>
    <PropertyGroup>
      <options/>
      <run_parallel/>
      <run_single/>
      <dependencies_changed/>
      <input_changed/>
      <cache_loader_path/>
      <output_relative/>
    </PropertyGroup>
  </Target>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  /// TARGET QtQmlSetModified
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Set InputModified flag for modified files (i.e. Inputs newer than Outputs)
  // -->
  <Target Name="QtQmlSetModified" DependsOnTargets="QtQmlCachePrepare"
    Inputs="%(QtQmlCacheItem.FullPath);%(QtQmlCacheItem.AdditionalDependencies)"
    Outputs="@(QtQmlCacheItem->'%(OutputFile)')">
    <Message Importance="High" Condition="'$(QtDebug)' == 'true'"
      Text="## QtQmlSetModified %(QtQmlCacheItem.Identity) => @(QtQmlCacheItem->'%(OutputFile)')"/>
    <PropertyGroup>
      <input_changed/>
    </PropertyGroup>
    <CreateProperty Value="true">
      <Output TaskParameter="ValueSetByTask" PropertyName="input_changed" />
    </CreateProperty>
    <ItemGroup>
      <QtQmlCacheItem>
        <InputChanged>$(input_changed)</InputChanged>
      </QtQmlCacheItem>
    </ItemGroup>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Clean-up
    // -->
    <PropertyGroup>
      <input_changed/>
    </PropertyGroup>
  </Target>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // TARGET QtQmlCacheItem
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // -->
  <Target Name="QtQmlCacheItem" DependsOnTargets="QtQmlSetModified"
    Inputs="%(QtQmlCacheItem.FullPath);%(QtQmlCacheItem.AdditionalDependencies);$(MSBuildProjectFile)"
    Outputs="@(QtQmlCacheItem->'%(OutputFile)')">
    <Message Importance="High" Condition="'$(QtDebug)' == 'true'"
      Text="## QtQmlCacheItem %(QtQmlCacheItem.Identity) => @(QtQmlCacheItem->'%(OutputFile)')" />
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Set DependenciesChanged flag for modified files or dependencies
    // -->
    <PropertyGroup>
      <dependencies_changed/>
    </PropertyGroup>
    <CreateProperty Value="true">
      <Output TaskParameter="ValueSetByTask" PropertyName="dependencies_changed" />
    </CreateProperty>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Generate QML cache
    // -->
    <PropertyGroup>
      <!--
      // $(options) ::= qmlcachegen command line options -->
      <options Condition="'@(QtQmlCacheItem)' != ''"
        >$(options) --resource=&quot;%(ResourceFile)&quot;</options>
      <options Condition="'@(QtQmlCacheItem)' != ''"
        >$(options) &quot;%(FullPath)&quot;</options>
      <options Condition="'@(QtQmlCacheItem)' != ''"
        >$(options) -o &quot;%(OutputFile)&quot;</options>
      <!--
      // $(run_parallel) ::= run qmlcachegen in a parallel process
      // $(run_single)   ::= run qmlcachegen in single process mode -->
      <run_parallel Condition="'@(QtQmlCacheItem)' != ''
        AND '%(QtQmlCacheItem.ParallelProcess)' == 'true' AND '$(SelectedFiles)' == ''"
      >true</run_parallel>
      <run_single Condition="'@(QtQmlCacheItem)' != ''
        AND ('%(QtQmlCacheItem.ParallelProcess)' != 'true' OR '$(SelectedFiles)' != '')"
      >true</run_single>
      <!--// Get relative path to output -->
      <output_relative
>$([MSBuild]::MakeRelative($(ProjectDir), %(QtQmlCacheItem.OutputFile)).TrimStart('\'))</output_relative>
    </PropertyGroup>
    <ItemGroup>
      <!--
      //  Create work item to generate QML cache -->
      <QtWork
        Include="@(QtQmlCacheItem)"
        Condition="'@(QtQmlCacheItem)' != ''
          AND '%(QtQmlCacheItem.IsSelected)' == 'true'">
        <WorkType>qmlcachegen</WorkType>
        <ToolPath Condition="'$(QtVsProjectSettings)' == 'true'"
          >$(QtToolsPath)\qmlcachegen.exe</ToolPath>
        <ToolPath Condition="'$(QtVsProjectSettings)' != 'true'"
          >%(QtQmlCacheItem.QTDIR)\bin\qmlcachegen.exe</ToolPath>
        <Options>$(options)</Options>
        <Message>%(QtQmlCacheItem.Message)</Message>
        <DependenciesChanged>$(dependencies_changed)</DependenciesChanged>
        <ParallelBuild Condition="'$(run_parallel)' == 'true'">true</ParallelBuild>
        <ParallelBuild Condition="'$(run_single)'   == 'true'">false</ParallelBuild>
        <ClCompile Condition="'%(QtQmlCacheItem.DynamicSource)' != 'false'">$(output_relative)</ClCompile>
      </QtWork>
    </ItemGroup>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Clean-up
    // -->
    <PropertyGroup>
      <dependencies_changed/>
      <options/>
      <run_parallel/>
      <run_single/>
      <output_relative/>
    </PropertyGroup>
    <ItemGroup>
      <selected_files Remove="@(selected_files)"/>
    </ItemGroup>
  </Target>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // TARGET QtQmlCache
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Root target of QML cache generation
  // -->
  <Target Name="QtQmlCache"
    DependsOnTargets="QtQmlCacheLoader;QtQmlCacheItem"
    BeforeTargets="QtRcc">
    <Message Importance="High" Condition="'$(QtDebug)' == 'true'" Text="## QtQmlCache" />
  </Target>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Import dependants
  // -->
  <Import
    Condition="'$(QtMsBuildTargets_AfterQmlCache)' != ''"
    Project="$(QtMsBuildTargets_AfterQmlCache)"/>
</Project>
QtMSBuild/QtMsBuild/qml/qtqml_static.props
New file
@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
-->
<!--
///////////////////////////////////////////////////////////////////////////////////////////////////
// Qt/MSBuild property definitions for QML static imports
// -->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Import pre-requisites
  // -->
  <Import
    Condition="'$(QtMsBuildProps_BeforeQmlStatic)' != ''"
    Project="$(QtMsBuildProps_BeforeQmlStatic)"/>
  <PropertyGroup>
    <QtQmlPluginImportCpp>$(QtQmlIntDir)\qml_plugin_import.cpp</QtQmlPluginImportCpp>
  </PropertyGroup>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Import dependants
  // -->
  <Import
    Condition="'$(QtMsBuildProps_AfterQmlStatic)' != ''"
    Project="$(QtMsBuildProps_AfterQmlStatic)"/>
</Project>
QtMSBuild/QtMsBuild/qml/qtqml_static.targets
New file
@@ -0,0 +1,342 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
-->
<!--
///////////////////////////////////////////////////////////////////////////////////////////////////
// Generate imports of QML static plugins
// -->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Import pre-requisites
  // -->
  <Import
    Condition="'$(QtMsBuildTargets_BeforeQmlStatic)' != ''"
    Project="$(QtMsBuildTargets_BeforeQmlStatic)"/>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Qt/MSBuild global properties
  //  * add QtQmlStatic to the list of targets to run during build
  //  * add QtQmlStaticLink to the list of targets to run when calculating linker input
  // -->
  <PropertyGroup>
    <QtBuildTargets>$(QtBuildTargets);QtQmlStatic</QtBuildTargets>
    <ComputeLinkInputsTargets>$(ComputeLinkInputsTargets);QtQmlStaticLink</ComputeLinkInputsTargets>
  </PropertyGroup>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  /// TARGET QtQmlStaticLink
  ///  => runs only once
  ///  => always runs if building against a static build of Qt
  ///  => targets that must run first: QtQmlStatic, ComputeCLGeneratedLinkInputs
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Add QML static plugin libs to Link input.
  // -->
  <Target
    Name="QtQmlStaticLink"
    Condition="'$(QtStaticPlugins)' == 'true' AND '@(QtQml)' != ''"
    DependsOnTargets="QtQmlStatic;ComputeCLGeneratedLinkInputs">
    <ItemGroup>
      <Link>
        <AdditionalDependencies Condition="'@(QtQmlImportLib)' != ''"
          >%(Link.AdditionalDependencies);@(QtQmlImportLib)</AdditionalDependencies>
      </Link>
    </ItemGroup>
  </Target>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  /// TARGET QtQmlStatic
  ///  => runs only once
  ///  => always runs if building against a static build of Qt
  ///  => targets that must run first: QtQmlImportsParseJson, QtQmlGetImportCpp
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Entry point for generating imports of QML static plugins.
  // -->
  <Target
    Name="QtQmlStatic"
    Condition="'$(QtStaticPlugins)' == 'true' AND '@(QtQml)' != ''"
    DependsOnTargets="QtQmlImportsParseJson;QtQmlGetImportCpp">
    <ItemGroup>
      <!-- for each required import, create a reference to the corresponding import lib -->
      <QtQmlImportLib
        Condition="'$(QtBuildConfig)' == 'debug'"
        Include="@(QtQmlImport->'%(Path)\%(Plugin)d.lib')"/>
      <QtQmlImportLib
        Condition="'$(QtBuildConfig)' != 'debug'"
        Include="@(QtQmlImport->'%(Path)\%(Plugin).lib')"/>
    </ItemGroup>
  </Target>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  /// TARGET QtQmlGetImportCpp
  ///  => runs only once
  ///  => skipped if generated C++ is up-to-date, relative to all JSON output files
  ///  => targets that must run first: QtQmlImportsParseJson
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Generate C++ source file with imports of QML static plugins.
  // -->
  <Target
    Name="QtQmlGetImportCpp"
    Condition="'$(QtStaticPlugins)' == 'true' AND '@(QtQml)' != ''"
    DependsOnTargets="QtQmlImportsParseJson"
    Inputs="@(QtQml->'%(ImportJson)')"
    Outputs="$(QtQmlPluginImportCpp)">
    <!-- file header -->
    <PropertyGroup>
      <QmlPluginImportCppHeader>
        <![CDATA[
// This file is autogenerated by Qt/MSBuild. It imports static plugin classes for
// static plugins used by QML imports.
#include <QtPlugin>]]>
      </QmlPluginImportCppHeader>
    </PropertyGroup>
    <!-- file contents: header + imports -->
    <ItemGroup>
      <QmlPluginImportCpp Include="$(QmlPluginImportCppHeader)" />
      <QmlPluginImportCpp Include="@(QtQmlImport->'Q_IMPORT_PLUGIN(%(ClassName))')" />
    </ItemGroup>
    <!-- write .cpp file -->
    <WriteLinesToFile
      File="$(QtQmlPluginImportCpp)"
      Lines="@(QmlPluginImportCpp)" />
    <!-- clean-up -->
    <PropertyGroup>
      <QmlPluginImportCppHeader/>
    </PropertyGroup>
    <ItemGroup>
      <QtQmlPluginImportCpp Remove="@(QtQmlPluginImportCpp)" />
    </ItemGroup>
  </Target>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  /// TARGET QtQmlImportsParseJson
  ///  => runs only once
  ///  => always runs if building agains a static build of Qt
  ///  => targets that must run first: QtQmlScanImports
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Parse JSON output of qmlimportscanner.
  //  * ATTN: "Naïve" parser: assumes JSON is formatted with each value in a single line
  // -->
  <Target
    Name="QtQmlImportsParseJson"
    Condition="'$(QtStaticPlugins)' == 'true' AND '@(QtQml)' != ''"
    DependsOnTargets="QtQmlScanImports">
    <!-- constants -->
    <PropertyGroup>
      <StrClassName>&quot;classname&quot;: </StrClassName>
      <StrPath>&quot;path&quot;: </StrPath>
      <StrPlugin>&quot;plugin&quot;: </StrPlugin>
    </PropertyGroup>
    <!-- load text of all JSON output files -->
    <ReadLinesFromFile File="%(QtQml.ImportJson)">
      <Output TaskParameter="Lines" ItemName="JsonText"/>
    </ReadLinesFromFile>
    <ItemGroup>
      <!-- list of all lines starting with '"classname": ' -->
      <JsonClassName
        Include="@(JsonText)"
        Condition="$([System.String]::Copy('%(JsonText.Identity)').StartsWith('$(StrClassName)'))" />
      <!-- extract value -->
      <JsonClassName>
        <ClassName>$([System.String]::Copy('%(JsonClassName.Identity)').Substring($(StrClassName.Length)).Trim(',').Trim('"'))</ClassName>
      </JsonClassName>
      <!-- list of all lines starting with '"path": ' -->
      <JsonPath
        Include="@(JsonText)"
        Condition="$([System.String]::Copy('%(JsonText.Identity)').StartsWith('$(StrPath)'))" />
      <!-- extract value -->
      <JsonPath>
        <Path>$([System.String]::Copy('%(JsonPath.Identity)').Substring($(StrPath.Length)).Trim(',').Trim('"'))</Path>
      </JsonPath>
      <!-- list of all lines starting with '"plugin": ' -->
      <JsonPlugin
        Include="@(JsonText)"
        Condition="$([System.String]::Copy('%(JsonText.Identity)').StartsWith('$(StrPlugin)'))" />
      <!-- extract value -->
      <JsonPlugin>
        <Plugin>$([System.String]::Copy('%(JsonPlugin.Identity)').Substring($(StrPlugin.Length)).Trim(',').Trim('"'))</Plugin>
      </JsonPlugin>
    </ItemGroup>
    <!-- join lists of extracted values into single list of imports -->
    <Join LeftItems="@(JsonClassName)" RightItems="@(JsonPath)" On="ROW_NUMBER">
      <Output TaskParameter="Result" ItemName="JsonAux"/>
    </Join>
    <Join LeftItems="@(JsonAux)" RightItems="@(JsonPlugin)" On="ROW_NUMBER">
      <Output TaskParameter="Result" ItemName="Json"/>
    </Join>
    <!-- remove duplicate import items -->
    <RemoveDuplicates Inputs="@(Json->'%(ClassName)')">
      <Output TaskParameter="Filtered" ItemName="QtQmlImport"/>
    </RemoveDuplicates>
    <!-- @(QtQmlImport) => list of required imports -->
    <!-- clean-up -->
    <PropertyGroup>
      <StrClassName/>
      <StrPath/>
      <StrPlugin/>
    </PropertyGroup>
    <ItemGroup>
      <JsonText Remove="@(JsonText)" />
      <JsonClassName Remove="@(JsonClassName)"/>
      <JsonPath Remove="@(JsonPath)"/>
      <JsonPlugin Remove="@(JsonPlugin)"/>
      <JsonAux Remove="@(JsonAux)" />
      <Json Remove="@(Json)" />
    </ItemGroup>
  </Target>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  /// TARGET QtQmlScanImports
  ///  => runs once for each QML file
  ///  => skipped if corresponding JSON output file is up-to-date
  ///  => targets that must run first: QtQmlStaticPrepare
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Run qmlimportscanner tool.
  // -->
  <Target
    Name="QtQmlScanImports"
    Condition="'$(QtStaticPlugins)' == 'true' AND '@(QtQml)' != ''"
    DependsOnTargets="QtQmlStaticPrepare"
    Inputs="%(QtQml.Identity)"
    Outputs="%(QtQml.ImportJson)">
    <!-- create QML work dir -->
    <MakeDir Directories="$(QtQmlIntDir)" />
    <!-- map local paths to build host paths -->
    <ItemGroup>
      <LocalPath Include="QtQmlFile">
        <Name>Path</Name>
        <Item>%(QtQml.Identity)</Item>
        <Value>%(QtQml.Identity)</Value>
      </LocalPath>
      <LocalPath Include="QtQmlImportJson">
        <Name>Path</Name>
        <Item>%(QtQml.ImportJson)</Item>
        <Value>%(QtQml.ImportJson)</Value>
      </LocalPath>
      <LocalPath Include="QtInstallQml">
        <Name>Path</Name>
        <Item>$(QMake_QT_INSTALL_QML_)</Item>
        <Value>$(QMake_QT_INSTALL_QML_)</Value>
      </LocalPath>
    </ItemGroup>
    <HostTranslatePaths Items="@(LocalPath)" Names="Path">
      <Output TaskParameter="Result" ItemName="HostPath"/>
    </HostTranslatePaths>
    <ItemGroup>
      <QtQmlFile Include="@(HostPath->WithMetadataValue('Identity', 'QtQmlFile'))">
        <LocalPath>%(Item)</LocalPath>
        <HostPath>%(Value)</HostPath>
      </QtQmlFile>
      <QtQmlImportJson Include="@(HostPath->WithMetadataValue('Identity', 'QtQmlImportJson'))">
        <LocalPath>%(Item)</LocalPath>
        <HostPath>%(Value)</HostPath>
      </QtQmlImportJson>
      <QtInstallQml Include="@(HostPath->WithMetadataValue('Identity', 'QtInstallQml'))">
        <LocalPath>%(Item)</LocalPath>
        <HostPath>%(Value)</HostPath>
      </QtInstallQml>
    </ItemGroup>
    <!-- qmlimportscanner command line -->
    <PropertyGroup>
      <Cmd><![CDATA["$(QtToolsPath)/qmlimportscanner.exe"]]></Cmd>
      <Cmd><![CDATA[$(Cmd) -qmlFiles @(QtQmlFile->'%(HostPath)')]]></Cmd>
      <Cmd><![CDATA[$(Cmd) -importPath @(QtInstallQml->'%(HostPath)')]]></Cmd>
    </PropertyGroup>
    <!-- run qmlimportscanner -->
    <HostExec
      Command="$(Cmd)" RedirectStdOut="@(QtQmlImportJson->'%(HostPath)')"
      Inputs="@(QtQmlFile->'%(HostPath)')"
      Outputs="@(QtQmlImportJson->'%(HostPath)')"
      RemoteTarget="$(ResolvedRemoteTarget)"
      RemoteProjectDir="$(_ResolvedRemoteProjectDir)" />
  </Target>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  /// TARGET QtQmlStaticPrepare
  ///  => runs once for each QML file
  ///  => skipped if $(QtStaticPlugins) is false
  ///  => skipped if there are no QML files in the project
  ///  => targets that must run first: QtQmlCreateItems
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Calculate path of .json file with the output of qmlimportscanner for each QML file.
  //  * Format: <QML work dir> '\' SHA1(<path to QML file>) '_' <QML file name> '.json'
  // -->
  <Target
    Name="QtQmlStaticPrepare"
    Condition="'$(QtStaticPlugins)' == 'true' AND '@(QtQml)' != ''"
    DependsOnTargets="QtQmlCreateItems"
    Inputs="%(QtQml.Identity)"
    Outputs="@(QtQml->'####### Do not skip this target #######')">
    <!-- calculate SHA1 of QML file path, relative to project dir -->
    <Hash ItemsToHash="@(QtQml)">
      <Output TaskParameter="HashResult" PropertyName="QtQmlIdentityHash"/>
    </Hash>
    <!-- set path to corresponding JSON file -->
    <ItemGroup>
      <QtQml>
        <ImportJson>$([MSBuild]::MakeRelative(
          '$(ProjectDir)','$(QtQmlIntDir)\$(QtQmlIdentityHash)_%(Filename).json'))</ImportJson>
      </QtQml>
    </ItemGroup>
  </Target>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Import dependants
  // -->
  <Import
    Condition="'$(QtMsBuildTargets_AfterQmlStatic)' != ''"
    Project="$(QtMsBuildTargets_AfterQmlStatic)"/>
</Project>
QtMSBuild/QtMsBuild/qt.targets
New file
@@ -0,0 +1,77 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
-->
<!--
///////////////////////////////////////////////////////////////////////////////////////////////////
// Qt/MSBuild
// -->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Fail-safe import of private definitions
  // -->
  <Import
    Condition="'$(QtPrivateLoaded)' != 'true'"
    Project="$(MSBuildThisFileDirectory)\qt_private.props"/>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Defaults for project version constants
  // -->
  <PropertyGroup>
    <QtVsProjectVersion
      Condition="'$(QtVsProjectVersion)' == ''"
      >0</QtVsProjectVersion>
    <QtVsProjectMinVersion_Settings
      Condition="'$(QtVsProjectMinVersion_Settings)' == ''"
      >0</QtVsProjectMinVersion_Settings>
    <QtVsProjectMinVersion_ClProperties
      Condition="'$(QtVsProjectMinVersion_ClProperties)' == ''"
      >0</QtVsProjectMinVersion_ClProperties>
  </PropertyGroup>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Qt Common Targets
  // -->
  <Import Project="qt_globals.targets"/>
  <Import Project="qt_settings.targets"/>
  <Import Project="qt_tasks.targets"/>
  <Import Project="qt_vars.targets"/>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Import subfolder targets
  // -->
  <Import
    Project="$(QtMsBuildTargets)"/>
</Project>
QtMSBuild/QtMsBuild/qt_defaults.props
New file
@@ -0,0 +1,127 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/****************************************************************************
**
** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
-->
<!--
///////////////////////////////////////////////////////////////////////////////////////////////////
// Default values of Qt settings
//
// Preceding evaluation chain:
//  * Project global properties, incl. $(Keyword), $(WindowsTargetPlatformVersion), $(QtMsBuild)
//  * Microsoft.Cpp.Default.props
//  * Configuration properties, incl. $(ConfigurationType), $(PlatformToolset)
//
// -->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <QtDefaultsLoaded>true</QtDefaultsLoaded>
  </PropertyGroup>
  <!-- // Qt VS Project Format Version -->
  <PropertyGroup>
    <QtVsProjectVersion>0</QtVsProjectVersion>
    <QtVsProjectMinVersion_Settings>300</QtVsProjectMinVersion_Settings>
    <QtVsProjectMinVersion_ClProperties>300</QtVsProjectMinVersion_ClProperties>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Keyword)' != ''">
    <QtVsProjectVersion Condition="'$(Keyword)' == 'Qt4VSv1.0'">200</QtVsProjectVersion>
    <QtVsProjectVersion Condition="$(Keyword.StartsWith('QtVS_v'))"
      >$([System.Convert]::ToInt32($(Keyword.Substring(6))))</QtVsProjectVersion>
    <QtVsProjectSettings Condition="$(QtVsProjectVersion) &gt;= $(QtVsProjectMinVersion_Settings)"
      >true</QtVsProjectSettings>
    <QtVsProjectSettings Condition="$(QtVsProjectVersion) &lt; $(QtVsProjectMinVersion_Settings)"
      >false</QtVsProjectSettings>
    <QtVsProjectClProperties
      Condition="$(QtVsProjectVersion) &gt;= $(QtVsProjectMinVersion_ClProperties)"
      >true</QtVsProjectClProperties>
    <QtVsProjectClProperties
      Condition="$(QtVsProjectVersion) &lt; $(QtVsProjectMinVersion_ClProperties)"
      >false</QtVsProjectClProperties>
  </PropertyGroup>
  <PropertyGroup>
    <!--// Path of Qt binary files -->
    <QtPathBinaries>bin</QtPathBinaries>
    <QtPathLibraryExecutables>bin</QtPathLibraryExecutables>
    <!--// qmake template -->
    <QtQMakeTemplate>vcapp</QtQMakeTemplate>
    <!--// Extract Qt variables from qmake-generated Makefile
        //     Syntax: < var_name > [ = [ makefile_name ] / < pattern > / < replace > / ] -->
    <QMake_Makefile>
      DEFINES=/-D([^\s=]+(=(\x22(\\\\|\\\x22|[^\x22])*\x22|\S+))?)/$1/;
      INCLUDEPATH=INCPATH/-(?:iquote|isystem|idirafter|I)\s*(\x22[^\x22]+\x22|[^\s]+)/$1/;
      LIBS=/(?:(?:\/LIBPATH:|-L)(?:\x22[^\x22]+\x22|[^\s]+))|(\x22[^\x22]+\x22|[^\s]+)/$1/;
      LIBPATH=LIBS/(?:\/LIBPATH:|-L)(\x22[^\x22]+\x22|[^\s]+)/$1/;
    </QMake_Makefile>
    <!--// Extract Qt variables from qmake-generated .vcxproj file
        //     Syntax: < var_name >  = < xpath_to_value > -->
    <QMake_MSBuild>
      DEFINES=/Project/ItemDefinitionGroup/ClCompile/PreprocessorDefinitions;
      INCLUDEPATH=/Project/ItemDefinitionGroup/ClCompile/AdditionalIncludeDirectories;
      STDCPP=/Project/ItemDefinitionGroup/ClCompile/LanguageStandard;
      CL_OPTIONS=/Project/ItemDefinitionGroup/ClCompile/AdditionalOptions;
      LIBS=/Project/ItemDefinitionGroup/Link/AdditionalDependencies;
      LINK_OPTIONS=/Project/ItemDefinitionGroup/Link/AdditionalOptions;
    </QMake_MSBuild>
    <!--// Default Qt version -->
    <QtVersionsRegKey Condition="'$(QtVersionsRegKey)' == ''"
      >HKEY_CURRENT_USER\Software\Digia\Versions</QtVersionsRegKey>
    <DefaultQtVersion Condition="'$(DefaultQtVersion)' == ''"
      >$([MSBuild]::GetRegistryValue('$(QtVersionsRegKey)','DefaultQtVersion'))</DefaultQtVersion>
    <!--// Qt build config -->
    <QtBuildConfig Condition="'$(Configuration)' == 'Debug'">debug</QtBuildConfig>
    <QtBuildConfig Condition="'$(Configuration)' != 'Debug'">release</QtBuildConfig>
  </PropertyGroup>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Read subfolder dependencies (qt_import.props)
  // -->
  <PropertyGroup>
    <SubFolder>$([System.IO.Directory]::GetDirectories('$(MSBuildThisFileDirectory)'))</SubFolder>
    <SubFolderImports Condition="'$(SubFolder)' != ''"
      >
      $([System.String]::Join(
      '\qt_import.props;',
      $(SubFolder.Split(';'))))\qt_import.props
    </SubFolderImports>
    <QtImports>$(SubFolderImports.Split(';'))</QtImports>
    <SubFolder/>
    <SubFolderImports/>
  </PropertyGroup>
  <Import
    Project="$(QtImports)"/>
</Project>
QtMSBuild/QtMsBuild/qt_globals.targets
New file
@@ -0,0 +1,636 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
-->
<!--
///////////////////////////////////////////////////////////////////////////////////////////////////
/// Qt/MSBuild global definitions
///////////////////////////////////////////////////////////////////////////////////////////////////
// -->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Build dependencies
  // -->
  <PropertyGroup>
    <BuildDependsOn>
      QtVersion;
      $(BuildDependsOn);
      Qt
    </BuildDependsOn>
    <CleanDependsOn>
      $(CleanDependsOn);
      QtClean
    </CleanDependsOn>
    <DesignTimeBuildInitTargets>
      $(DesignTimeBuildInitTargets);
      Qt
    </DesignTimeBuildInitTargets>
    <ComputeCompileInputsTargets>
      $(ComputeCompileInputsTargets);
      Qt
    </ComputeCompileInputsTargets>
    <BeforeClCompileTargets>
      $(BeforeClCompileTargets);
      Qt
    </BeforeClCompileTargets>
    <ComputeLinkInputsTargets>
      $(ComputeLinkInputsTargets);
      Qt
    </ComputeLinkInputsTargets>
  </PropertyGroup>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Qt/MSBuild global properties
  // -->
  <Import Project="..\version.targets" Condition="Exists('..\version.targets')"/>
  <PropertyGroup>
    <QtMsBuildVersion>$(QtVSToolsVersion)</QtMsBuildVersion>
    <QtDebug Condition="'$(QtDebug)' == ''">false</QtDebug>
    <QtLogFilePath Condition="'$(QtLogFilePath)' == ''"
      >$([System.IO.Path]::Combine($(ProjectDir),$(IntDir)qt_work.log))</QtLogFilePath>
    <QtMaxProcs Condition="'$(QtMaxProcs)' == ''"
      >$([System.Environment]::ProcessorCount)</QtMaxProcs>
  </PropertyGroup>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  /// TARGET QtGetDefaultClCompile
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Get default C++ properties
  // -->
  <Target Name="QtGetDefaultClCompile">
    <ItemGroup>
      <ClCompile Include="DefaultClCompile"/>
    </ItemGroup>
  </Target>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  /// TARGET QtClean
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Clean-up from previous build
  // -->
  <Target Name="QtClean">
    <Message Importance="High" Condition="'$(QtDebug)' == 'true'" Text="## Qt Clean"/>
    <Delete Files="$(QtLogFilePath)"/>
  </Target>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  /// TARGET QtVersion
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Print debug message with Qt/MSBuild version
  // -->
  <Target Name="QtVersion">
    <Message Importance="High" Condition="'$(QtDebug)' == 'true'"
      Text="Qt/MSBuild v$(QtMsBuildVersion) ($(MSBuildThisFileDirectory))"/>
  </Target>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  /// TARGET QtPrepare
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Prepare Qt build: read and parse work log file
  // -->
  <Target Name="QtPrepare"
    Condition="'$(QtSkipWork)' != 'true'"
    DependsOnTargets="$(QtDependsOn)"
    BeforeTargets="QtWorkPrepare">
    <Message Importance="High" Condition="'$(QtDebug)' == 'true'" Text="#### QtPrepare"/>
    <CriticalSection Lock="true" Name="$(ProjectGuid)" />
    <ReadLinesFromFile File="$(QtLogFilePath)">
      <Output TaskParameter="Lines" ItemName="QtLogData"/>
    </ReadLinesFromFile>
    <ItemGroup Condition="'@(QtLogData)' != ''">
      <QtWorkLog
        Include="@(QtLogData->'$([System.String]::Copy('%(QtLogData.Identity)').Split('|')[0])')">
        <Hash>$([System.String]::Copy('%(QtLogData.Identity)').Split('|')[1])</Hash>
      </QtWorkLog>
    </ItemGroup>
  </Target>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  /// TARGET QtWorkPrepare
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Analyze work request and decide if the Qt tool needs to be called or if the output from the
  // previous call is still valid.
  // -->
  <Target Name="QtWorkPrepare" DependsOnTargets="$(QtDependsOn);$(QtBuildTargets)"
    Condition="'$(QtSkipWork)' != 'true'"
    Inputs="%(QtWork.WorkType)(%(QtWork.Identity))"
    Outputs="@(QtWork->'####### Don't skip this target #######')">
    <Message Importance="High" Condition="'$(QtDebug)' == 'true' AND '@(QtWork)' != ''"
      Text="## QtWorkPrepare %(QtWork.Identity)" />
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Calculate hash for the requested work item, based on its associated tool and options
    // -->
    <GetItemHash Condition="'@(QtWork)' != ''"
      Item="@(QtWork)" Keys="Identity;WorkType;ToolPath;Options">
      <Output TaskParameter="Hash" PropertyName="work_hash" />
    </GetItemHash>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Try to find entry in Qt work log for the requested work item; get logged hash
    // -->
    <PropertyGroup Condition="'@(QtWork)' != ''">
      <work_key>@(QtWork->'%(WorkType)(%(Identity))')</work_key>
      <dependencies_changed>@(QtWork->'%(DependenciesChanged)')</dependencies_changed>
      <input_changed>@(QtWork->'%(InputChanged)')</input_changed>
      <project_changed
        Condition="'$(dependencies_changed)' == 'true' AND '$(input_changed)' != 'true'"
        >true</project_changed>
    </PropertyGroup>
    <FindInList Condition="'@(QtWork)' != '' AND '$(input_changed)' != 'true'"
      CaseSensitive="false" List="@(QtWorkLog)" ItemSpecToFind="$(work_key)">
      <Output TaskParameter="ItemFound" ItemName="log_entry"/>
    </FindInList>
    <PropertyGroup Condition="'@(QtWork)' != ''">
      <log_hash Condition="'@(log_entry)' != ''">@(log_entry->'%(Hash)')</log_hash>
    </PropertyGroup>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Skip work item if:
    //  * work is not needed:
    //      - input was not modified
    //      - AND project was not modified OR command line did not change (i.e. hashes are the same)
    //  * OR we're in a design-time build
    // -->
    <PropertyGroup>
      <do_work
        Condition="'$(input_changed)' == 'true'
               OR ('$(project_changed)' == 'true' AND '$(log_hash)' != '$(work_hash)')"
        >true</do_work>
      <skip_work
        Condition="'$(do_work)' != 'true' OR '$(DesignTimeBuild)' == 'true'"
        >true</skip_work>
    </PropertyGroup>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Skip work item
    // -->
    <ItemGroup Condition="'@(QtWork)' != '' AND '$(skip_work)' == 'true'">
      <QtWorkResult Include="@(QtWork)">
        <ExitCode>0</ExitCode>
        <Skipped>true</Skipped>
      </QtWorkResult>
      <QtWork Remove="@(QtWork)" />
    </ItemGroup>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Generate new work log entry and ensure path to output exists
    // -->
    <ItemGroup Condition="'@(QtWork)' != '' AND '$(skip_work)' != 'true'">
      <QtWorkLog Remove="$(work_key)"/>
      <QtWorkLog Include="$(work_key)">
        <Hash>$(work_hash)</Hash>
      </QtWorkLog>
    </ItemGroup>
    <MakeDir Condition="'@(QtWork)' != '' AND '$(skip_work)' != 'true'"
      Directories="$([System.IO.Path]::GetDirectoryName(%(QtWork.OutputFile)))"/>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Clean-up
    // -->
    <PropertyGroup>
      <work_key/>
      <log_hash/>
      <dependencies_changed/>
      <input_changed/>
      <project_changed/>
      <do_work/>
      <skip_work/>
    </PropertyGroup>
    <ItemGroup>
      <log_entry Remove="@(log_entry)"/>
    </ItemGroup>
  </Target>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  /// TARGET QtWork
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Run Qt tools and add dynamic C++ sources to build
  // -->
  <Target Name="QtWork"
    Condition="'$(QtSkipWork)' != 'true'"
    DependsOnTargets="QtWorkPrepare;QtGetDefaultClCompile">
    <Message Importance="High" Condition="'$(QtDebug)' == 'true'"
      Text="## Qt Build $(QtBuildTargets.Replace(';',' ').Trim())" />
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Run work locally in parallel processes
    // -->
    <QtRunWork
      Condition="'$(ApplicationType)' != 'Linux' AND '@(QtWork)' != ''
        AND '%(QtWork.ParallelBuild)' == 'true'
        AND '$(DesignTimeBuild)' != 'true'"
      QtWork="@(QtWork)" QtMaxProcs="$(QtMaxProcs)" QtDebug="$(QtDebug)">
      <Output TaskParameter="Result" ItemName="QtWorkResult" />
    </QtRunWork>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Run work locally in a single process
    // -->
    <QtRunWork
      Condition="'$(ApplicationType)' != 'Linux' AND '@(QtWork)' != ''
        AND '%(QtWork.ParallelBuild)' != 'true'
        AND '$(DesignTimeBuild)' != 'true'"
      QtWork="@(QtWork)" QtMaxProcs="1" QtDebug="$(QtDebug)">
      <Output TaskParameter="Result" ItemName="QtWorkResult" />
    </QtRunWork>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Run work in build host
    // -->
    <!-- // Translate local paths to host paths -->
    <Flatten
      Condition="'$(ApplicationType)' == 'Linux'
        AND '@(QtWork)' != '' AND '$(DesignTimeBuild)' != 'true'"
      Items="@(QtWork)" Metadata="ResourceFiles">
      <Output TaskParameter="Result" ItemName="ResourceFiles"/>
    </Flatten>
    <ItemGroup
      Condition="'$(ApplicationType)' == 'Linux'
        AND '@(QtWork)' != '' AND '$(DesignTimeBuild)' != 'true'">
      <LocalPath Include="%(QtWork.Identity)">
        <Name>InputPath</Name>
        <Item>%(QtWork.Identity)</Item>
        <Value>%(QtWork.Identity)</Value>
      </LocalPath>
      <LocalPath
        Condition="'%(ResourceFiles.Identity)' != ''"
        Include="@(ResourceFiles->'%(Item)')">
        <Name>InputPath</Name>
        <Item>@(ResourceFiles->'%(Value)')</Item>
        <Value>@(ResourceFiles->'%(Value)')</Value>
      </LocalPath>
      <LocalPath Include="%(QtWork.Identity)">
        <Name>OutputPath</Name>
        <Item>%(QtWork.OutputFile)</Item>
        <Value>%(QtWork.OutputFile)</Value>
      </LocalPath>
    </ItemGroup>
    <HostTranslatePaths
      Condition="'$(ApplicationType)' == 'Linux'
        AND '@(QtWork)' != '' AND '$(DesignTimeBuild)' != 'true'"
      Items="@(LocalPath)" Names="InputPath;OutputPath">
      <Output TaskParameter="Result" ItemName="HostPath"/>
    </HostTranslatePaths>
    <ItemGroup>
      <InputPath Include="@(HostPath->WithMetadataValue('Name', 'InputPath'))" />
      <OutputPath Include="@(HostPath->WithMetadataValue('Name', 'OutputPath'))" />
    </ItemGroup>
    <!-- // Run command -->
    <HostExec
      Condition="'$(ApplicationType)' == 'Linux'
        AND '%(Identity)' != '' AND '$(DesignTimeBuild)' != 'true'"
      Message="@(QtWork->'%(WorkType) %(Identity)')"
      Command="@(QtWork->'%(ToolPath) %(Options)')"
      Inputs="@(InputPath)"
      Outputs="@(OutputPath)"
      RemoteTarget="$(ResolvedRemoteTarget)"
      RemoteProjectDir="$(_ResolvedRemoteProjectDir)">
    </HostExec>
    <!-- // Generate result item -->
    <ItemGroup
      Condition="'$(ApplicationType)' == 'Linux'
        AND '@(QtWork)' != '' AND '$(DesignTimeBuild)' != 'true'">
      <QtWorkResult Include="@(QtWork)">
        <ExitCode>0</ExitCode>
      </QtWorkResult>
    </ItemGroup>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Save tracking log of files read during build; used by VS to check the up-to-date status
    // -->
    <ItemGroup Condition="'$(DesignTimeBuild)' != 'true' AND '$(QtVSToolsBuild)' != 'true'">
      <read_log Include="^%(QtWorkResult.FullPath);%(QtWorkResult.AdditionalDependencies)"
        Condition="'%(QtWorkResult.ExitCode)' == '0' AND '%(QtWorkResult.DisableLog)' != 'true'">
        <WorkType>%(QtWorkResult.WorkType)</WorkType>
      </read_log>
      <read_log>
        <Path Condition="$([System.String]::Copy('%(Identity)').StartsWith('^'))">%(Identity)</Path>
        <Path Condition="!$([System.String]::Copy('%(Identity)').StartsWith('^'))"
          >$([System.IO.Path]::Combine('$(MSBuildProjectDirectory)','%(Identity)'))</Path>
      </read_log>
    </ItemGroup>
    <WriteLinesToFile
      Condition="'@(read_log)' != ''"
      File="$(TLogLocation)%(read_log.WorkType).read.1u.tlog"
      Lines="@(read_log->MetaData('Path')->ToUpperInvariant());"
      Overwrite="true"
      Encoding="Unicode"/>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Save tracking log of files written during build; used by VS to check the up-to-date status
    // -->
    <ItemGroup Condition="'$(DesignTimeBuild)' != 'true' AND '$(QtVSToolsBuild)' != 'true'">
      <write_log Include="^%(QtWorkResult.FullPath);%(QtWorkResult.OutputFile)"
        Condition="'%(QtWorkResult.ExitCode)' == '0' AND '%(QtWorkResult.DisableLog)' != 'true'">
        <WorkType>%(QtWorkResult.WorkType)</WorkType>
      </write_log>
      <write_log>
        <Path Condition="$([System.String]::Copy('%(Identity)').StartsWith('^'))">%(Identity)</Path>
        <Path Condition="!$([System.String]::Copy('%(Identity)').StartsWith('^'))"
          >$([System.IO.Path]::Combine('$(MSBuildProjectDirectory)','%(Identity)'))</Path>
      </write_log>
    </ItemGroup>
    <WriteLinesToFile Condition="'@(write_log)' != ''"
     File="$(TLogLocation)%(write_log.WorkType).write.1u.tlog"
     Lines="@(write_log->MetaData('Path')->ToUpperInvariant());"
     Overwrite="true" Encoding="Unicode"/>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Log output files; this is used by VS to determine what files to delete on "Clean"
    // -->
    <ItemGroup Condition="'$(DesignTimeBuild)' != 'true' AND '$(QtVSToolsBuild)' != 'true'">
      <clean_log Include="%(QtWorkResult.OutputFile)"
        Condition="'%(QtWorkResult.ExitCode)' == '0'">
        <Source>@(QtWorkResult, '|')</Source>
      </clean_log>
    </ItemGroup>
    <WriteLinesToFile Condition="'@(clean_log)' != ''"
      File="$(TLogLocation)$(ProjectName).write.1u.tlog"
      Lines="^%(clean_log.Source);@(clean_log->'%(Fullpath)')"
      Encoding="Unicode"/>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Log calls to Qt tools; used in QtWorkPrepare to detect changes to the options of Qt tools
    // -->
    <WriteLinesToFile Condition="'@(QtWorkLog)' != '' AND '$(DesignTimeBuild)' != 'true'"
      File="$(QtLogFilePath)"
      Lines="@(QtWorkLog->'%(Identity)|%(Hash)')"
      Overwrite="true" Encoding="Unicode"/>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Generate build error if a Qt tool did not terminate correctly
    // -->
    <Error
      Condition="'%(QtWorkResult.ExitCode)' != ''
        AND '%(QtWorkResult.ExitCode)' != '0'
        AND '$(DesignTimeBuild)' != 'true'"
      File="%(QtWorkResult.Identity)" Code="%(QtWorkResult.ExitCode)"
      Text="%(QtWorkResult.WorkType) (%(QtWorkResult.ToolPath))"/>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Add dynamic C++ sources to build
    // -->
    <ItemGroup>
      <QtWork_ClCompile
        Condition="'%(QtWorkResult.ExitCode)' == '0' AND '%(QtWorkResult.ClCompile)' != ''"
        Include="@(QtWorkResult->'%(ClCompile)')"/>
      <QtWork_ClCompile
        Condition="Exists('$(QtVarsOutputDir)\qtvars_plugin_import.cpp')"
        Include="$(QtVarsOutputDir)\qtvars_plugin_import.cpp"/>
      <!-- Add QML static plugins -->
      <QtWork_ClCompile
        Condition="Exists('$(QtQmlPluginImportCpp)')"
        Include="$(QtQmlPluginImportCpp)"/>
    </ItemGroup>
    <ItemGroup Condition="'$(ApplicationType)' == 'Linux'">
      <QtWork_ClCompile Condition="'%(QtWork_ClCompile.ObjectFileName)' == ''">
        <ObjectFileName>$(IntDir)%(Filename).o</ObjectFileName>
      </QtWork_ClCompile>
    </ItemGroup>
    <!-- // Copy default C++ compiler properties -->
    <Expand Condition="'@(QtWork_ClCompile)' != ''"
      Items="@(QtWork_ClCompile)"
      BaseItem="@(ClCompile->WithMetadataValue('Identity', 'DefaultClCompile'))">
      <Output TaskParameter="Result" ItemName="QtWork_ClCompile_Expanded"/>
    </Expand>
    <!-- // Force pre-compiled header include -->
    <ItemGroup Condition="'$(ApplicationType)' != 'Linux'">
      <QtWork_ClCompile_Expanded>
        <AdditionalIncludeDirectories
          >$(ProjectDir);%(QtWork_ClCompile_Expanded.AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
        <ForcedIncludeFiles Condition="'%(PrecompiledHeader)' == 'Use'"
          >%(PrecompiledHeaderFile)</ForcedIncludeFiles>
        <AdditionalOptions>$([System.String]::Copy(
'%(QtWork_ClCompile_Expanded.AdditionalOptions) %(QtWork_ClCompile_Expanded.AdditionalCppOptions)')
          .Trim())</AdditionalOptions>
      </QtWork_ClCompile_Expanded>
    </ItemGroup>
    <!-- // Add C++ source items and clean-up temp items -->
    <ItemGroup>
      <ClCompile Include="@(QtWork_ClCompile_Expanded)"/>
      <QtWork_ClCompile_Expanded Remove="@(QtWork_ClCompile_Expanded)"/>
      <QtWork_ClCompile Remove="@(QtWork_ClCompile)"/>
    </ItemGroup>
    <!--// If sources were manually selected (e.g. by the 'Compile' option in the context menu for
        // project items), add generated C++ sources to the list of selected files -->
    <PropertyGroup Condition="'$(SelectedFiles)' != ''">
      <SelectedClCompile>@(QtWorkResult->'%(ClCompile)')</SelectedClCompile>
    </PropertyGroup>
    <PropertyGroup Condition="'$(SelectedClCompile)' != ''">
      <SelectedFiles>$(SelectedFiles);$(SelectedClCompile)</SelectedFiles>
    </PropertyGroup>
    <ItemGroup Condition="'$(SelectedClCompile)' != ''">
      <SelectedFiles Include="$(SelectedClCompile)"/>
    </ItemGroup>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Update C++ sources with generated information
    // -->
    <PropertyGroup>
      <QtIncludePath>@(QtIncludePath->Distinct())</QtIncludePath>
    </PropertyGroup>
    <ItemGroup>
      <ClCompile_Updated Include="@(ClCompile)">
        <AdditionalIncludeDirectories
>$(QtIncludePath);%(ClCompile.AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
      </ClCompile_Updated>
      <ClCompile Remove="@(ClCompile)"/>
      <ClCompile Include="@(ClCompile_Updated)"/>
      <ClCompile_Updated Remove="@(ClCompile_Updated)"/>
    </ItemGroup>
    <!--
    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Clean-up
    // -->
    <ItemGroup>
      <QtWork       Remove="@(QtWork)"/>
      <QtWorkResult Remove="@(QtWorkResult)"/>
      <QtWorkLog    Remove="@(QtWorkLog)"/>
      <read_log     Remove="@(read_log)"/>
      <write_log    Remove="@(write_log)"/>
      <clean_log    Remove="@(clean_log)"/>
    </ItemGroup>
  </Target>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  /// TARGET Qt
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Root Qt target
  // -->
  <Target Name="Qt" DependsOnTargets="QtPrepare;QtWork" BeforeTargets="FixupCLCompileOptions">
    <ItemGroup>
      <ClCompile Remove="DefaultClCompile" />
    </ItemGroup>
    <CriticalSection Lock="false" Name="$(ProjectGuid)" />
    <OnError ExecuteTargets="QtLeaveCriticalSection_OnError"/>
  </Target>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  /// TARGET QtOuterBuild
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Run targets in $(QtOuterBuildDependsOn) and then recursively invoke build
  // -->
  <Target Name="QtOuterBuild" DependsOnTargets="$(QtOuterBuildDependsOn)">
    <!--// Invoke inner build: recursive build in second MSBuild instance -->
    <MSBuild
      Projects="$(MSBuildProjectFullPath)"
      Targets="Build"
      Properties="QtInnerBuild=$(MSBuildProjectFullPath);RandomFileName=$(RandomFileName);BuildProjectReferences=false">
    </MSBuild>
    <OnError ExecuteTargets="QtLeaveCriticalSection_OnError"/>
  </Target>
  <PropertyGroup
    Condition="'$(QtInnerBuild)' == '' AND '$(DesignTimeBuild)' != 'true'">
    <!--// Outer build: invoke inner build -->
    <BuildDependsOn>
      $(QtOuterBuildPrepare);
      QtOuterBuild;
      $(QtOuterBuildFinalize)
    </BuildDependsOn>
    <QtInnerBuild>$(MSBuildProjectFullPath)</QtInnerBuild>
    <RandomFileName>$([System.IO.Path]::GetRandomFileName())</RandomFileName>
  </PropertyGroup>
  <PropertyGroup
    Condition="'$(QtInnerBuild)' != '$(MSBuildProjectFullPath)' AND '$(DesignTimeBuild)' != 'true'">
    <!--// Dependent project inner build: skip build -->
    <BuildDependsOn>$(QtOuterBuildPrepare);$(QtOuterBuildFinalize)</BuildDependsOn>
  </PropertyGroup>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  /// TARGET QtEnterCriticalSection_... / QtLeaveCriticalSection_InitializeBuildStatus
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Synchronize calls to InitializeBuildStatus
  // -->
  <Target Name="QtEnterCriticalSection_InitializeBuildStatus" BeforeTargets="InitializeBuildStatus">
    <CriticalSection Lock="true" Name="$(ProjectGuid)" />
  </Target>
  <Target Name="QtLeaveCriticalSection_InitializeBuildStatus" AfterTargets="InitializeBuildStatus">
    <CriticalSection Lock="false" Name="$(ProjectGuid)" />
  </Target>
  <PropertyGroup>
    <!--// Schedule critical section enter/leave targets around InitializeBuildStatus -->
    <QtSync_InitializeBuildStatus>
      QtEnterCriticalSection_InitializeBuildStatus;
      InitializeBuildStatus;
      QtLeaveCriticalSection_InitializeBuildStatus
    </QtSync_InitializeBuildStatus>
    <!--// Replace 'InitializeBuildStatus' with '$(QtSync_InitializeBuildStatus)' -->
    <BuildDependsOn>
      $([MSBuild]::Unescape(
        $([System.Text.RegularExpressions.Regex]::Replace(' $(BuildDependsOn) ',
          '(?&lt;!\w)InitializeBuildStatus(?!\w)', $(QtSync_InitializeBuildStatus)))))
    </BuildDependsOn>
  </PropertyGroup>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  /// TARGET QtEnterCriticalSection_... / QtLeaveCriticalSection_FinalizeBuildStatus
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Synchronize calls to FinalizeBuildStatus
  // -->
  <Target Name="QtEnterCriticalSection_FinalizeBuildStatus" BeforeTargets="FinalizeBuildStatus">
    <CriticalSection Lock="true" Name="$(ProjectGuid)" />
  </Target>
  <Target Name="QtLeaveCriticalSection_FinalizeBuildStatus" AfterTargets="FinalizeBuildStatus">
    <CriticalSection Lock="false" Name="$(ProjectGuid)" />
  </Target>
  <PropertyGroup>
    <!--// Schedule critical section enter/leave targets around FinalizeBuildStatus -->
    <QtSync_FinalizeBuildStatus>
      QtEnterCriticalSection_FinalizeBuildStatus;
      FinalizeBuildStatus;
      QtLeaveCriticalSection_FinalizeBuildStatus
    </QtSync_FinalizeBuildStatus>
    <!--// Replace 'FinalizeBuildStatus' with '$(QtSync_FinalizeBuildStatus)' -->
    <BuildDependsOn>
      $([MSBuild]::Unescape(
        $([System.Text.RegularExpressions.Regex]::Replace(' $(BuildDependsOn) ',
          '(?&lt;!\w)FinalizeBuildStatus(?!\w)', $(QtSync_FinalizeBuildStatus)))))
    </BuildDependsOn>
  </PropertyGroup>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  /// TARGET QtLeaveCriticalSection_OnError
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Fail-safe release of critical section lock, to be used in OnError tasks
  // -->
  <Target Name="QtLeaveCriticalSection_OnError">
    <CriticalSection Lock="false" Name="$(ProjectGuid)" />
  </Target>
</Project>
QtMSBuild/QtMsBuild/qt_private.props
New file
@@ -0,0 +1,233 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
-->
<!--
///////////////////////////////////////////////////////////////////////////////////////////////////
// Evaluation of Qt properties
//
// Preceding evaluation chain:
//  * Project global properties, incl. $(Keyword), $(WindowsTargetPlatformVersion), $(QtMsBuild)
//  * Microsoft.Cpp.Default.props
//  * Configuration properties, incl. $(ConfigurationType), $(PlatformToolset)
//  * qt_defaults.props
//  * Qt build settings, incl. $(QtInstall), $(QtModules)
//  * Property sheets preceding Qt.props
//
// -->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <QtPrivateLoaded>true</QtPrivateLoaded>
  </PropertyGroup>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Fail-safe import of default values
  // -->
  <Import
    Condition="'$(QtDefaultsLoaded)' != 'true'"
    Project="$(MSBuildThisFileDirectory)\qt_defaults.props"/>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Setup Qt installation path
  // -->
  <PropertyGroup Condition="'$(QtVsProjectSettings)' == 'true'">
    <QtInstallDir Condition="Exists('$(QtInstall)')">$(QtInstall)</QtInstallDir>
    <QtInstallRegKey Condition="'$(QtInstall)' != ''"
      >$(QtVersionsRegKey)\$(QtInstall)</QtInstallRegKey>
    <QtInstallRegDir Condition="'$(QtInstallDir)' == '' AND '$(QtInstallRegKey)' != ''"
      >$([MSBuild]::GetRegistryValue('$(QtInstallRegKey)','InstallDir'))</QtInstallRegDir>
    <QtInstallDir
      Condition="'$(ApplicationType)' != 'Linux' AND '$(QtInstallDir)' == ''
      AND Exists('$(QtInstallRegDir)')"
      >$(QtInstallRegDir)</QtInstallDir>
    <QtInstallDir
      Condition="'$(ApplicationType)' == 'Linux' AND '$(QtInstallDir)' == ''
      AND ( $(QtInstallRegDir.StartsWith('SSH:')) OR $(QtInstallRegDir.StartsWith('WSL:')) )"
      >$(QtInstallRegDir.Split(':')[1])</QtInstallDir>
    <QtInstallDir
      Condition="'$(ApplicationType)' == 'Linux' AND '$(QtInstallDir)' == ''"
      >$(QtInstall)</QtInstallDir>
  </PropertyGroup>
  <PropertyGroup Condition="'$(QtInstallDir)' != ''">
    <QtToolsPath Condition="'$(QtToolsPath)' == ''"
      >$([System.IO.Path]::Combine('$(QtInstallDir)','$(QtPathBinaries)').Replace('\', '/'))</QtToolsPath>
    <QtDllPath Condition="'$(QtDllPath)' == ''"
      >$([System.IO.Path]::Combine('$(QtInstallDir)','$(QtPathLibraryExecutables)').Replace('\', '/'))</QtDllPath>
    <QTDIR>$(QtInstallDir)</QTDIR>
  </PropertyGroup>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Qt Variables Expansion
  // -->
  <PropertyGroup Condition="'$(QtVsProjectSettings)' == 'true'">
    <!--// Path to Qt variables property file -->
    <QtVarsOutputDir Condition="'$(QtVarsOutputDir)' == ''"
      >$([System.IO.Path]::Combine('$(ProjectDir)', '$(IntDir)', 'qmake'))</QtVarsOutputDir>
    <QtVarsFileName Condition="'$(QtVarsFileName)' == ''"
      >qtvars_$(Platform.Replace(' ','_'))_$(Configuration.Replace(' ','_')).props</QtVarsFileName>
    <QtVarsFilePath Condition="'$(QtVarsFilePath)' == ''"
      >$(QtVarsOutputDir)\$(QtVarsFileName)</QtVarsFilePath>
    <!--// Path to temp work folder -->
    <QtVarsWorkDirName
      >temp</QtVarsWorkDirName>
    <QtVarsWorkDir
      >$([System.IO.Path]::Combine('$(QtVarsOutputDir)','$(QtVarsWorkDirName)'))</QtVarsWorkDir>
    <QtVarsWorkPath
      >$(QtVarsWorkDir)\$(QtVarsFileName)</QtVarsWorkPath>
    <QtVarsIndexPathDesignTime
      >$(QtVarsWorkDir)\$(ProjectGuid.Replace('{','').Replace('}','')).$(ProjectName).designtime.idx</QtVarsIndexPathDesignTime>
    <QtVarsDesignTime Condition="Exists('$(QtVarsIndexPathDesignTime)')"
      >$([System.String]::Copy($([System.IO.File]::ReadAllText('$(QtVarsIndexPathDesignTime)'))).Replace('&#xD;&#xA;',''))</QtVarsDesignTime>
  </PropertyGroup>
  <!--// Import Qt variables (full build) -->
  <Import
    Condition="'$(DesignTimeBuild)' != 'true' AND Exists('$(QtVarsFilePath)')"
    Project="$(QtVarsFilePath)"/>
  <!--// Import Qt variables (design-time build) -->
  <Import
    Condition="'$(DesignTimeBuild)' == 'true' AND Exists('$(QtVarsDesignTime)')"
    Project="$(QtVarsDesignTime)"/>
  <!--// Import Qt variables (fall-back) -->
  <Import
    Condition=
"'$(DesignTimeBuild)' == 'true' AND !Exists('$(QtVarsDesignTime)') AND Exists('$(QtVarsFilePath)')"
    Project="$(QtVarsFilePath)"/>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Add Qt DLL path to debugger definitions
  // -->
  <PropertyGroup>
    <LocalDebuggerEnvironment  Condition="'$(QtDllPath)' != ''"
      >PATH=%PATH%;$(QtDllPath)&#xD;&#xA;$(LocalDebuggerEnvironment)
    </LocalDebuggerEnvironment>
  </PropertyGroup>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // QML debugging
  // -->
  <PropertyGroup>
    <QmlDebug Condition="'$(QtQMLDebugEnable)' == 'true'"
      >-qmljsdebugger=file:$(ProjectGuid),block</QmlDebug>
    <LocalDebuggerCommandArguments
      >$(QmlDebug)</LocalDebuggerCommandArguments>
  </PropertyGroup>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Outer build
  // -->
  <PropertyGroup>
    <QtOuterBuildPrepare Condition="'$(QtOuterBuildPrepare)' == ''"
      >ResolveReferences;PrepareForBuild;InitializeBuildStatus</QtOuterBuildPrepare>
    <QtOuterBuildFinalize Condition="'$(QtOuterBuildFinalize)' == ''"
      >FinalizeBuildStatus</QtOuterBuildFinalize>
  </PropertyGroup>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Extract Qt build settings from qmake-generated project files
  // -->
  <PropertyGroup>
    <QtVars
      Condition="'$(QtQMakeTemplate)' == 'app'"
      >$(QMake_Makefile)</QtVars>
    <QtVars
      Condition="'$(QtQMakeTemplate)' == 'vcapp'"
      >$(QMake_MSBuild);</QtVars>
  </PropertyGroup>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Default item metadata
  // -->
  <ItemDefinitionGroup>
    <!--// C++ -->
    <ClCompile>
      <PreprocessorDefinitions Condition="'$(Qt_DEFINES_)' != ''"
        >$(Qt_DEFINES_);%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <PreprocessorDefinitions Condition="'$(QtQMLDebugEnable)' == 'true'"
        >QT_QML_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <AdditionalIncludeDirectories Condition="'$(Qt_INCLUDEPATH_)' != ''"
        >$(Qt_INCLUDEPATH_);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
      <LanguageStandard Condition="'$(Qt_STDCPP_)' != ''"
        >$(Qt_STDCPP_)</LanguageStandard>
      <AdditionalOptions Condition="'$(Qt_CL_OPTIONS_)' != ''"
        >$(Qt_CL_OPTIONS_) %(AdditionalOptions)</AdditionalOptions>
    </ClCompile>
    <!--// Linker (.obj files) -->
    <Link>
      <AdditionalDependencies Condition="'$(Qt_LIBS_)' != ''"
        >$(Qt_LIBS_);%(AdditionalDependencies)</AdditionalDependencies>
      <AdditionalLibraryDirectories Condition="'$(Qt_LIBPATH_)' != ''"
        >$(Qt_LIBPATH_);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
      <SharedLibrarySearchPath Condition="'$(Qt_LIBPATH_)' != ''"
        >$(Qt_LIBPATH_);%(SharedLibrarySearchPath)</SharedLibrarySearchPath>
      <AdditionalOptions Condition="'$(Qt_LINK_OPTIONS_)' != ''"
        >$(Qt_LINK_OPTIONS_) %(AdditionalOptions)</AdditionalOptions>
    </Link>
  </ItemDefinitionGroup>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Check static plugin import:
  //  * If qmake generated a platform plugin import, assume QML plugins are also required.
  // -->
  <PropertyGroup Condition="Exists('$(QtVarsWorkDir)\qtvars_plugin_import.cpp')">
    <QtStaticPlugins>true</QtStaticPlugins>
  </PropertyGroup>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Exclude Qt headers from code analysis
  // -->
  <PropertyGroup>
    <CAExcludePath>$(CAExcludePath);$(Qt_INCLUDEPATH_)</CAExcludePath>
  </PropertyGroup>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Evaluate subfolder properties
  // -->
  <Import
    Project="$(QtMsBuildProps)"/>
</Project>
QtMSBuild/QtMsBuild/qt_settings.targets
New file
@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/****************************************************************************
**
** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
-->
<!--
///////////////////////////////////////////////////////////////////////////////////////////////////
// Add property page for Qt settings
// -->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup Condition="'$(QtVsProjectSettings)' == 'true'">
    <PropertyPageSchema
      Include="$(MSBuildThisFileDirectory)qt_settings.xml">
      <Context>Project;PropertySheet</Context>
    </PropertyPageSchema>
  </ItemGroup>
</Project>
QtMSBuild/QtMsBuild/qt_settings.xml
New file
@@ -0,0 +1,148 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/****************************************************************************
**
** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
-->
<Rule
    Name="QtRule10_Settings"
    DisplayName="Qt Project Settings"
    PageTemplate="generic"
    Description="Qt Project Settings"
    Order="8"
    xmlns="http://schemas.microsoft.com/build/2009/properties">
  <Rule.DataSource>
    <DataSource Persistence="ProjectFile" Label="QtSettings" HasConfigurationCondition="true"/>
  </Rule.DataSource>
  <Rule.Categories>
    <Category Name="QtSettings_01_General" DisplayName="General"/>
    <Category Name="QtSettings_02_Paths" DisplayName="Paths"/>
    <Category Name="QtSettings_03_QMake" DisplayName="qmake"/>
    <Category Name="QtSettings_04_QML" DisplayName="QML"/>
  </Rule.Categories>
  <EnumProperty
    Name="Keyword"
    DisplayName="Qt VS Project Format Version"
    Category="QtSettings_01_General"
    ReadOnly="true"
    Description="Version of the format of this Qt Visual Studio project.">
    <EnumProperty.DataSource>
      <DataSource Persistence="ProjectFile" Label="Globals" />
    </EnumProperty.DataSource>
    <EnumValue Name="Qt4VSv1.0" DisplayName="Version 2.0"/>
    <EnumValue Name="QtVS_v300" DisplayName="Version 3.0"/>
    <EnumValue Name="QtVS_v301" DisplayName="Version 3.1"/>
    <EnumValue Name="QtVS_v302" DisplayName="Version 3.2"/>
    <EnumValue Name="QtVS_v303" DisplayName="Version 3.3"/>
    <EnumValue Name="QtVS_v304" DisplayName="Version 3.4"/>
  </EnumProperty>
  <StringProperty
    Name="QtLastBackgroundBuild"
    DisplayName="Last Background Build"
    Category="QtSettings_01_General"
    Visible="False">
    <StringProperty.DataSource>
      <DataSource Persistence="UserFile" Label="QtSettings" HasConfigurationCondition="true"/>
    </StringProperty.DataSource>
  </StringProperty>
  <DynamicEnumProperty
    Name="QtInstall"
    DisplayName="Qt Installation"
    Category="QtSettings_01_General"
    EnumProvider="QtVersionProvider"
    Description=
"Select Qt installation; can be either a path to an installation directory or a version name registered through the Qt Visual Studio Tools (v2.4 or above).">
  </DynamicEnumProperty>
  <StringListProperty
    Name="QtModules"
    Category="QtSettings_01_General"
    DisplayName="Qt Modules">
    <StringListProperty.ValueEditors>
      <ValueEditor EditorType="QtModulesEditor" DisplayName="&lt;Select Modules...&gt;" />
    </StringListProperty.ValueEditors>
  </StringListProperty>
  <EnumProperty
    Name="QtBuildConfig"
    Category="QtSettings_01_General"
    DisplayName="Build Config"
    Description="Select whether to use debug or release.">
    <EnumValue Name="debug" DisplayName="Debug"/>
    <EnumValue Name="release" DisplayName="Release"/>
  </EnumProperty>
  <BoolProperty
    Name="QtDeploy"
    Category="QtSettings_01_General"
    DisplayName="Run Deployment Tool"
    Description="Select whether Qt for Windows Deployment Tool (windeployqt) should be called after build."/>
  <StringProperty
    Name="QtPathBinaries"
    Category="QtSettings_02_Paths"
    DisplayName="Qt Binaries"
    Description=
"Path to folder containing executables of Qt tools (qmake, moc, etc.) When a non-rooted path is specified, it will be considered relative to the Qt installation directory."/>
  <StringProperty
    Name="QtPathLibraryExecutables"
    Category="QtSettings_02_Paths"
    DisplayName="Qt Library Executables"
    Description=
"Path to folder containing executable files of Qt modules. When a non-rooted path is specified, it will be considered relative to the Qt installation directory."/>
  <StringListProperty
    Name="QtHeaderSearchPath"
    Category="QtSettings_02_Paths"
    DisplayName="Additional Qt header search paths" />
  <StringListProperty
    Name="QtLibrarySearchPath"
    Category="QtSettings_02_Paths"
    DisplayName="Additional Qt library search paths" />
  <EnumProperty
    Name="QtQMakeTemplate"
    Category="QtSettings_03_QMake"
    DisplayName="Template"
    Description="Template of generated project files for extraction of Qt build settings.">
    <EnumValue Name="vcapp" DisplayName="MSBuild" />
    <EnumValue Name="app" DisplayName="Makefile" />
  </EnumProperty>
  <StringListProperty
    Name="QtVars"
    Category="QtSettings_03_QMake"
    DisplayName="Extract Variables"
    Visible="False" />
  <StringListProperty
    Name="QMakeExtraArgs"
    Category="QtSettings_03_QMake"
    DisplayName="Additional Command Arguments" />
  <StringListProperty
    Name="QMakeCodeLines"
    Category="QtSettings_03_QMake"
    DisplayName="Additional Project Settings" />
  <BoolProperty
    Name="QtQMLDebugEnable"
    Category="QtSettings_04_QML"
    DisplayName="Enable QML Debugging"
    Description="Select whether to launch a QML session when debugging.">
  </BoolProperty>
</Rule>
QtMSBuild/QtMsBuild/qt_tasks.targets_TT
New file
@@ -0,0 +1,212 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
*****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
*****************************************************************************
<#@output extension="targets" #>
<#@include file="$(SolutionDir)\common.tt" #>
**          <#=WARNING_GENERATED_FILE#>
*****************************************************************************
-->
<!--
///////////////////////////////////////////////////////////////////////////////////////////////////
// Helper inline tasks used by the Qt/MSBuild targets
// -->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <!-- BEGIN Generated code <#=XML_COMMENT_END#><#
    // Parse .cs files and generate inline MSBuild tasks using C# code
    //
    var files = Directory.GetFiles(Path.Combine(SolutionDir, "QtMsBuild", "Tasks"), "*.cs");
    foreach(var file in files) {
        var text = File.ReadAllText(file);
        var result = TaskParser.Parse(text);
        var commentLines = (result.GetValues<string>("COMMENT")
            .FirstOrDefault() ?? "")
            .TrimEnd('\r', '\n').Split(new[] {"\r\n"}, StringSplitOptions.None);
        var taskAttribs = result.GetValues<string>("ATTRIBS")
            .FirstOrDefault() ?? "";
        var namespaces = result.GetValues<List<string>>("USING")
            .FirstOrDefault() ?? new List<string>();
        var parameters = (result.GetValues<List<ParamDecl>>("PARAMS")
            .FirstOrDefault() ?? new List<ParamDecl>())
            .Where((ParamDecl p) => !string.IsNullOrEmpty(p.name))
            .OrderBy((ParamDecl p) => p.isOut)
            .ThenBy((ParamDecl p) => p.isOptional);
        var taskCode = result.GetValues<string>("CODE")
            .FirstOrDefault()?.TrimEnd('\r', '\n') ?? "";
        var assemblyRefs = (result.GetValues<List<string>>("REFERENCE")
            .FirstOrDefault() ?? new List<string>())
            .Select(assemblyRef => assemblyRef.Trim());
        WriteLine(string.Format(
////////////////////////////////////////////////////////////////////////////////////////////////////
@"
  {0}
  {1}
  {2}
  <UsingTask {3}
    TaskFactory=""CodeTaskFactory""
    AssemblyFile=""$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll"">
    <ParameterGroup>{4}
    </ParameterGroup>
    <Task>{5}{6}
      <Code Type=""Fragment"" Language=""cs"">
        <![CDATA[
{7}
        ]]>
      </Code>
    </Task>
  </UsingTask>",
////////////////////////////////////////////////////////////////////////////////////////////////////
        /*{0}*/ XML_COMMENT_BEGIN,
        /*{1}*/ string.Join("\r\n  ", commentLines),
        /*{2}*/ XML_COMMENT_END,
        /*{3}*/ taskAttribs,
        /*{4}*/ string.Join("", parameters.Select(param => string.Format(
@"
      <{0} ParameterType=""{1}""{2}{3}/>",
            /*{0}*/ param.name,
            /*{1}*/ param.type,
            /*{2}*/ param.isOut ? @" Output=""true""" : "",
            /*{3}*/ !param.isOut && !param.isOptional ? @" Required=""true""" : ""))),
        /*{5}*/ string.Join("", assemblyRefs.Select(assemblyRef => string.Format(
@"
      <Reference Include=""{0}""/>",
            /*{0}*/ assemblyRef))),
        /*{6}*/ string.Join("", namespaces.Select(nameSpc => string.Format(
@"
      <Using Namespace=""{0}""/>",
            /*{0}*/ nameSpc))),
        /*{7}*/ taskCode));
    }
  #>
  <#=XML_COMMENT_BEGIN#> END Generated code -->
</Project>
<!--<#=XML_COMMENT_END#>
<#@assembly Name="$(SolutionDir)\QtVsTools.RegExpr\bin\$(Configuration)\QtVsTools.RegExpr.dll" #>
<#@import namespace="static QtVsTools.SyntaxAnalysis.RegExpr" #>
<#+
    class ParamDecl {
        public string name;
        public string type;
        public bool isOptional;
        public bool isOut;
    }
    Parser InitTaskParser()
    {
        var name
            = CharSet[CharWord + Chars['.']].Repeat();
        var assemblyRef
            = StartOfLine & HorizSpace & "//" & new Token("REF", HorizSpace, Line) & LineBreak;
        var usingStmt
            = new Token("using")
            & new Token("NAMESPACE", new Token("static").Optional() & name)
            & new Token(";");
        var paramDecl = new Token("PARAM",
            new Token("PARAM_OUT", "out").Optional()
            & new Token("PARAM_TYPE", name & new Token("[]").Optional())
            & new Token("PARAM_NAME", Word)
            & new Token("PARAM_OPTIONAL", "="
                & (new Token("null") | new Token("0") | new Token("false"))).Optional()
            & new Token(CharSet[',', ')']))
            {
                new Rule<ParamDecl>
                {
                    Update("PARAM_NAME", (ParamDecl p, string value) => p.name = value),
                    Update("PARAM_TYPE", (ParamDecl p, string value) => p.type = value),
                    Update("PARAM_OUT", (ParamDecl p, string value) => p.isOut = true),
                    Update("PARAM_OPTIONAL", (ParamDecl p, string value) => p.isOptional = true),
                }
            };
        var regionReference
            = StartOfLine & HorizSpace & "#region Reference" & Line & LineBreak
            & new Token("REFERENCE", SkipWs_Disable, assemblyRef.Repeat())
            {
                new Rule<List<string>>
                {
                    Update("REF", (List<string> list, string refName) => list.Add(refName))
                }
            };
        var regionUsing
            = StartOfLine & HorizSpace & "#region Using" & Line & LineBreak
            & new Token("USING", usingStmt.Repeat())
            {
                new Rule<List<string>>
                {
                    Update("NAMESPACE", (List<string> list, string nameSpc) => list.Add(nameSpc))
                }
            };
        var regionComment
            = StartOfLine & HorizSpace & "#region Comment" & Line & LineBreak
            & new Token("COMMENT", SkipWs_Disable,
                (!LookAhead[StartOfLine & HorizSpace & "#endregion"]
                & StartOfLine & HorizSpace & Line & LineBreak).Repeat());
        var regionParameters
            = StartOfLine & HorizSpace & "#region Parameters" & Line & LineBreak
            & new Token("PARAMS", paramDecl.Repeat())
            {
                new Rule<List<ParamDecl>>
                {
                    Update("PARAM", (List<ParamDecl> list, ParamDecl param) => list.Add(param))
                }
            };
        var regionCode
            = StartOfLine & HorizSpace & "#region Code" & Line & LineBreak
            & new Token("CODE", SkipWs_Disable,
                (!LookAhead[StartOfLine & HorizSpace & "#endregion"]
                & StartOfLine & HorizSpace & Line & LineBreak).Repeat());
        var task
            = StartOfLine & HorizSpace & "#region Task" & new Token("ATTRIBS", Line) & LineBreak
            & ( regionReference
                | regionUsing
                | regionComment
                | regionParameters
                | regionCode
                | (Line & LineBreak)
            ).Repeat();
        return task.Render(Space);
    }
    Parser _TaskParser;
    Parser TaskParser => _TaskParser ?? (
        _TaskParser = InitTaskParser());
//-->#>
QtMSBuild/QtMsBuild/qt_vars.targets
New file
@@ -0,0 +1,594 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/****************************************************************************
**
** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
-->
<!--
///////////////////////////////////////////////////////////////////////////////////////////////////
// Read Qt Build Variables
// -->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup Condition="'$(QtVsProjectSettings)' == 'true'">
    <QtOuterBuildDependsOn>QtVarsPrepare;QtVars;$(QtDependsOn)</QtOuterBuildDependsOn>
    <CleanDependsOn>$(CleanDependsOn);QtVarsClean</CleanDependsOn>
  </PropertyGroup>
  <Target Name="ResolveHost" DependsOnTargets="ResolveRemoteDir"
    Condition="'$(ApplicationType)' == 'Linux' AND '$(PlatformToolset)' != 'WSL_1_0'">
    <ResolveRemoteDir
      Condition="'$(_ResolvedRemoteProjectDir)' == ''"
      RemoteProjectDir="$(RemoteProjectDir)"
      RemoteTarget="$(ResolvedRemoteTarget)"
      ProjectDir="$(ProjectDir)"
      IntermediateDir="$(IntDir)"
      RemoteProjectDirFile="$(RemoteProjectDirFile)">
      <Output TaskParameter="ResolvedRemoteProjectDir" PropertyName="_ResolvedRemoteProjectDir"/>
    </ResolveRemoteDir>
  </Target>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  /// TARGET QtVars
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Call qmake with generated .pro file to export Qt variables into MSBuild .props file
  // -->
  <Target
    Name="QtVars"
    Condition="'$(QtVsProjectSettings)' == 'true'"
    DependsOnTargets="QtMocInit;QtUicInit;ResolveHost"
    Inputs="$(MSBuildProjectFile)" Outputs="$(QtVarsFilePath)">
    <!--// Check if qmake is in the tools path -->
    <Error Condition="'$(QtToolsPath)' == ''" Text="There's no Qt version assigned to project $(MSBuildProjectFile) for configuration $(Configuration)/$(Platform).&#xA;Please set a Qt installation in 'Project|Properties|Configuration Properties|Qt Project Settings|Qt Installation'."/>
    <Error
      Condition="'$(ApplicationType)' != 'Linux' AND !Exists('$(QtToolsPath)\qmake.exe')"
      Text="qmake not found in $(QtToolsPath) when building project $(MSBuildProjectFile)"/>
    <!--// Ensure C++ compiler in PATH -->
    <Exec
      Condition="'$(ApplicationType)' != 'Linux'"
      Command="WHERE /Q cl.exe" IgnoreExitCode="true">
      <Output TaskParameter="ExitCode" PropertyName="ErrorLevel"/>
    </Exec>
    <SetEnv
      Condition="'$(ApplicationType)' != 'Linux' AND '$(ErrorLevel)' != '0'"
      Name="PATH" Prefix="true" Value="$(ExecutablePath)"/>
    <!--// Set-up temp directory -->
    <RemoveDir
      Directories="$(QtVarsWorkDir)"/>
    <MakeDir
      Directories="$(QtVarsWorkDir)"/>
    <!--// Translate local paths to build host paths -->
    <ItemGroup>
      <LocalPath Include="WorkDir">
        <Name>Path</Name>
        <Item>$(QtVarsWorkDir)</Item>
        <Value>$(QtVarsWorkDir)</Value>
      </LocalPath>
      <LocalPath Include="QMakeProps">
        <Name>Path</Name>
        <Item>$(QtVarsWorkDir)\props.txt</Item>
        <Value>$(QtVarsWorkDir)\props.txt</Value>
      </LocalPath>
      <LocalPath Include="QMakeLog">
        <Name>Path</Name>
        <Item>$(QtVarsWorkDir)\qtvars.log</Item>
        <Value>$(QtVarsWorkDir)\qtvars.log</Value>
      </LocalPath>
      <LocalPath Include="QMakeProj">
        <Name>Path</Name>
        <Item>$(QtVarsWorkDir)\qtvars.pro</Item>
        <Value>$(QtVarsWorkDir)\qtvars.pro</Value>
      </LocalPath>
      <LocalPath Include="QtMakefile">
        <Name>Path</Name>
        <Item>$(QtVarsWorkDir)\Makefile</Item>
        <Value>$(QtVarsWorkDir)\Makefile</Value>
      </LocalPath>
    </ItemGroup>
    <HostTranslatePaths Items="@(LocalPath)" Names="Path">
      <Output TaskParameter="Result" ItemName="HostPath"/>
    </HostTranslatePaths>
    <ItemGroup>
      <WorkDir Include="@(HostPath->WithMetadataValue('Identity', 'WorkDir'))">
        <LocalPath>%(Item)</LocalPath>
        <HostPath>%(Value)</HostPath>
      </WorkDir>
      <QMakeProps Include="@(HostPath->WithMetadataValue('Identity', 'QMakeProps'))">
        <LocalPath>%(Item)</LocalPath>
        <HostPath>%(Value)</HostPath>
      </QMakeProps>
      <QMakeLog Include="@(HostPath->WithMetadataValue('Identity', 'QMakeLog'))">
        <LocalPath>%(Item)</LocalPath>
        <HostPath>%(Value)</HostPath>
      </QMakeLog>
      <QMakeProj Include="@(HostPath->WithMetadataValue('Identity', 'QMakeProj'))">
        <LocalPath>%(Item)</LocalPath>
        <HostPath>%(Value)</HostPath>
      </QMakeProj>
      <QtMakefile Include="@(HostPath->WithMetadataValue('Identity', 'QtMakefile'))">
        <LocalPath>%(Item)</LocalPath>
        <HostPath>%(Value)</HostPath>
      </QtMakefile>
    </ItemGroup>
    <!--// Run qmake: query properties -->
    <PropertyGroup>
      <Cmd><![CDATA["$(QtToolsPath)/qmake" -query]]></Cmd>
    </PropertyGroup>
    <HostExec
      Command="$(Cmd)" RedirectStdOut="props.txt"
      WorkingDirectory="@(WorkDir->'%(HostPath)')"
      Outputs="@(QMakeProps)"
      RemoteTarget="$(ResolvedRemoteTarget)"
      RemoteProjectDir="$(_ResolvedRemoteProjectDir)" />
    <ReadLinesFromFile
        File="@(QMakeProps->'%(LocalPath)')">
      <Output TaskParameter="Lines" ItemName="QMakeQueryResult"/>
    </ReadLinesFromFile>
    <!--// Parse qmake query result -->
    <ItemGroup>
      <QMakeQueryResult>
        <SepIdx>$([System.String]::Copy('%(Identity)').IndexOf(':'))</SepIdx>
      </QMakeQueryResult>
      <QMakeQueryResult>
        <ValueIdx>$([MSBuild]::Add(%(SepIdx), 1))</ValueIdx>
      </QMakeQueryResult>
      <QMakeQueryResult>
        <Name>$([System.String]::Copy('%(Identity)').Substring(0, %(SepIdx)).Replace('/', "SLASH"))</Name>
        <Value>$([System.String]::Copy('%(Identity)').Substring(%(ValueIdx)))</Value>
      </QMakeQueryResult>
      <QMakeProperty
        Include="@(QMakeQueryResult->'%(Name)')"
        RemoveMetadata="Name;SepIdx;ValueIdx"/>
    </ItemGroup>
    <!--// Parse Qt version -->
    <PropertyGroup Condition="'@(QMakeProperty)' != ''">
      <QtVersionMajor>0</QtVersionMajor>
      <QtVersionMinor>0</QtVersionMinor>
      <QtVersionPatch>0</QtVersionPatch>
      <QtVersionParts>0</QtVersionParts>
      <QtVersion
        >@(QMakeProperty->WithMetadataValue('Identity', 'QT_VERSION')->'%(Value)')</QtVersion>
      <QtVersionParts
        Condition="'$(QtVersion)' != ''">$(QtVersion.Split('.').Length)</QtVersionParts>
      <QtVersionMajor Condition="$(QtVersionParts) >= 1">$(QtVersion.Split('.')[0])</QtVersionMajor>
      <QtVersionMinor Condition="$(QtVersionParts) >= 2">$(QtVersion.Split('.')[1])</QtVersionMinor>
      <QtVersionPatch Condition="$(QtVersionParts) >= 3">$(QtVersion.Split('.')[2])</QtVersionPatch>
    </PropertyGroup>
    <!--// Workaround for 5.13.2 NDEBUG obsession -->
    <PropertyGroup
      Condition="$(QtVersionMajor) > 5
                  OR ($(QtVersionMajor) == 5 AND ($(QtVersionMinor) > 13
                    OR ($(QtVersionMinor) == 13 AND ($(QtVersionPatch) >= 2))))">
      <QMakeOptionEarly>true</QMakeOptionEarly>
    </PropertyGroup>
    <!--// qmake command line arguments -->
    <ItemGroup>
      <QMakeArgsList Condition="'$(QMakeOptionEarly)' == 'true'" Include="-early"/>
      <QMakeArgsList Include="CONFIG -= debug release debug_and_release"/>
      <QMakeArgsList Include="CONFIG += $(QtBuildConfig)"/>
      <QMakeArgsList Include="$(QMakeExtraArgs)"/>
    </ItemGroup>
    <ItemGroup>
      <QMakeArgsList>
        <Escaped>%(Identity)</Escaped>
        <Escaped Condition="$([System.String]::Copy('%(Identity)').Contains(' '))
            OR $([System.String]::Copy('%(Identity)').Contains('&quot;'))"
        >&quot;$([System.String]::Copy('%(Identity)').Replace('&quot;','\&quot;'))&quot;</Escaped>
      </QMakeArgsList>
    </ItemGroup>
    <PropertyGroup>
      <QMakeArgs>@(QMakeArgsList->'%(Escaped)', ' ')</QMakeArgs>
      <QMakeArgs Condition="'$(QtQMakeTemplate)' == 'vcapp'"> -tp vc $(QMakeArgs)</QMakeArgs>
    </PropertyGroup>
    <!--// Modules and additional .pro file lines -->
    <ItemGroup>
      <QtModuleList Include="$(QtModules)"/>
      <QMakeCodeLine Include="$(QMakeCodeLines)"/>
    </ItemGroup>
    <!--// Generate INCLUDEPATH value -->
    <ItemGroup>
      <QtIncludesList Include="$(QtHeaderSearchPath)"/>
      <QtIncludes Include=
"$([System.IO.Path]::Combine($(QtInstallDir),$([System.String]::Copy('%(QtIncludesList.Identity)'))))"/>
      <QtIncludesList Remove="@(QtIncludesList)"/>
    </ItemGroup>
    <PropertyGroup>
      <QtIncludes>@(QtIncludes->'&quot;%(Identity)&quot;', ' ')</QtIncludes>
    </PropertyGroup>
    <!--// Generate LIBS value -->
    <ItemGroup>
      <QtLibsList Include="$(QtLibrarySearchPath)"/>
      <QtLibs Include=
"$([System.IO.Path]::Combine($(QtInstallDir),$([System.String]::Copy('%(QtLibsList.Identity)'))))"/>
      <QtLibsList Include="@(QtLibsList)"/>
    </ItemGroup>
    <PropertyGroup>
      <QtLibs>@(QtLibs->'&quot;-L%(Identity)&quot;', ' ')</QtLibs>
    </PropertyGroup>
    <Message
      Importance="high"
      Text="Reading Qt configuration ($(QtToolsPath)/qmake)"/>
    <PropertyGroup>
      <!--// .pro file configuration -->
      <QtVarsProFileConfig>
        CONFIG += no_fixpath
      </QtVarsProFileConfig>
      <!--// .pro file input parameters -->
      <QtVarsProFileInput>
        <!--
# Selected Qt modules -->
        QT += @(QtModuleList->'%(Identity)', ' ')
        <!--
# Custom additional .pro file code (from property page) -->
        @(QMakeCodeLine->'%(Identity)','%0D%0A')
      </QtVarsProFileInput>
      <!--
# Custom additional header search paths (from property page) -->
      <QtVarsProFileInput Condition="'$(QtHeaderSearchPath)' != ''">
        $(QtVarsProFileInput)
        INCLUDEPATH += $(QtIncludes)
      </QtVarsProFileInput>
      <!--
# Custom additional library search paths (from property page) -->
      <QtVarsProFileInput Condition="'$(QtLibrarySearchPath)' != ''">
        $(QtVarsProFileInput)
        LIBS += $(QtLibs)
      </QtVarsProFileInput>
      <!--
# Undef UNICODE macro if project is configured with multi-byte char set -->
      <QtVarsProFileInput Condition="'$(CharacterSet)' == 'MultiByte'">
        $(QtVarsProFileInput)
        DEFINES -= UNICODE _UNICODE
      </QtVarsProFileInput>
    </PropertyGroup>
    <!--// Write .pro file to temp path -->
    <WriteLinesToFile
      File="$(QtVarsWorkDir)\qtvars.pro"
      Lines="$(QtVarsProFileConfig)
            ;$(QtVarsProFileInput)"/>
    <!--// Write start of Qt vars data file:
        //  * Open property group tag -->
    <PropertyGroup>
      <!--
######## BEGIN generated XML (.props) ##############################################################
##    -->
      <QtVarsDataFileText>
        <![CDATA[
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
        ]]>
      </QtVarsDataFileText>
      <!--
##
######## END generated XML (.props) ################################################################
      -->
    </PropertyGroup>
    <WriteLinesToFile File="$(QtVarsWorkPath)" Lines="$(QtVarsDataFileText)" Overwrite="true"/>
    <!--// Run qmake: convert Makefile vars to .props (XML) file -->
    <PropertyGroup>
      <Cmd><![CDATA["$(QtToolsPath)/qmake" $(QMakeArgs) qtvars.pro]]></Cmd>
    </PropertyGroup>
    <HostExec
      Command="$(Cmd)" RedirectStdOut="qtvars.log" RedirectStdErr="STDOUT"
      WorkingDirectory="@(WorkDir->'%(HostPath)')"
      Inputs="@(QMakeProj)"
      Outputs="@(QtMakefile);@(QMakeLog)"
      RemoteTarget="$(ResolvedRemoteTarget)"
      RemoteProjectDir="$(_ResolvedRemoteProjectDir)"
      IgnoreExitCode="true">
      <Output TaskParameter="ExitCode" PropertyName="ErrorLevel"/>
    </HostExec>
    <!--// Check qmake result -->
    <PropertyGroup
      Condition="'$(ErrorLevel)' != '0'
        OR ( '$(QtQMakeTemplate)' == 'app' AND !Exists('$(QtVarsWorkDir)\Makefile') )
        OR ( '$(QtQMakeTemplate)' == 'vcapp' AND !Exists('$(QtVarsWorkDir)\qtvars.vcxproj') )">
      <QMakeError>true</QMakeError>
    </PropertyGroup>
    <!--// Get qmake console output -->
    <ItemGroup>
      <QMakeError Include="($(QtToolsPath)/qmake)"/>
      <QMakeError Include="%24PWD=$(QtVarsWorkDir)"/>
    </ItemGroup>
    <ReadLinesFromFile
        File="$(QtVarsWorkDir)\qtvars.log">
      <Output TaskParameter="Lines" ItemName="QMakeError"/>
    </ReadLinesFromFile>
    <ItemGroup>
      <QMakeError
        Condition="$([System.String]::Copy('%(Identity)').StartsWith('Info: creating stash file'))"
        Remove="@(QMakeError)"/>
      <QMakeError
        Condition="'$(QtQMakeTemplate)' == 'app' AND !Exists('$(QtVarsWorkDir)\Makefile')"
        Include="Error creating Makefile"/>
      <QMakeError
        Condition="'$(QtQMakeTemplate)' == 'vcapp' AND !Exists('$(QtVarsWorkDir)\qtvars.vcxproj')"
        Include="Error creating .vcxproj file"/>
    </ItemGroup>
    <!--// If error, show qmake console output and stop build -->
    <Error
      Condition="'$(QMakeError)' == 'true'"
      File="$(MSBuildProjectFile)"
      Text="ERROR running qmake%0D%0Aqmake: @(QMakeError->'%(Identity)','%0D%0Aqmake: ')%0D%0A"/>
    <Message
      Importance="high"
      Condition="'$(QMakeError)' != 'true' AND '$(QtVarsDebug)' == 'true'"
      Text="qmake: @(QMakeError->'%(Identity)','%0D%0Aqmake: ')"/>
    <!--//// Extract Qt vars from Makefile
        // -->
    <!--// Parse variable definition expressions for Makefile -->
    <ParseVarDefs
      Condition="'$(QtQMakeTemplate)' == 'app' AND '$(QtVars)' != ''"
      QtVars="$(QtVars)">
      <Output TaskParameter="OutVarDefs" ItemName="QMake_Makefile_VarDef"/>
    </ParseVarDefs>
    <!--// Read variables from Makefile -->
    <GetVarsFromMakefile
      Condition="'$(QtQMakeTemplate)' == 'app'"
      Makefile="$(QtVarsWorkDir)\Makefile" VarDefs="@(QMake_Makefile_VarDef)"
      ExcludeValues="$(QtVarsWorkDir)">
      <Output TaskParameter="OutVars" ItemName="QtVar"/>
    </GetVarsFromMakefile>
    <!--//// Extract Qt vars from .vcxproj file
        // -->
    <!--// Parse variable definition expressions for .vcxproj file -->
    <ItemGroup Condition="'$(QtQMakeTemplate)' == 'vcapp'">
      <QMake_MSBuild_VarDef Include="$(QMake_MSBuild)"/>
      <QMake_MSBuild_VarDef>
        <Name>$([System.String]::Copy('%(Identity)').Split('=')[0].Trim())</Name>
        <XPath>$([System.String]::Copy('%(Identity)').Split('=')[1].Trim())</XPath>
      </QMake_MSBuild_VarDef>
    </ItemGroup>
    <!--// Read variables from .vcxproj file -->
    <GetVarsFromMSBuild
      Condition="'$(QtQMakeTemplate)' == 'vcapp'"
      Project="$(QtVarsWorkDir)\qtvars.vcxproj"
      VarDefs="@(QMake_MSBuild_VarDef)"
      ExcludeValues="$(QtVarsWorkDir)">
      <Output TaskParameter="OutVars" ItemName="QtVar"/>
    </GetVarsFromMSBuild>
    <!--// Write variables as MSBuild properties to .props file -->
    <PropertyGroup>
      <QtMakefileVars Condition="'@(QtVar)' != ''">
        <![CDATA[@(QtVar->'<Qt_%(Identity)_>%(Value)</Qt_%(Identity)_>','%0D%0A')]]>
      </QtMakefileVars>
    </PropertyGroup>
    <WriteLinesToFile Condition="'$(QtMakefileVars)' != ''"
      File="$(QtVarsWorkPath)" Lines="$([System.String]::Copy($(QtMakefileVars)))"/>
    <!--// Write qmake properties as MSBuild properties to .props file -->
    <PropertyGroup>
      <QMakeProps Condition="'@(QtVar)' != ''">
        <![CDATA[@(QMakeProperty->'<QMake_%(Identity)_>%(Value)</QMake_%(Identity)_>','%0D%0A')]]>
      </QMakeProps>
    </PropertyGroup>
    <WriteLinesToFile Condition="'$(QMakeProps)' != ''"
      File="$(QtVarsWorkPath)" Lines="$([System.String]::Copy($(QMakeProps)))"/>
    <!--// Qt settings list for backup -->
    <ItemGroup>
      <QtInstall Include="$(QtInstall)"/>
      <QtModules Include="$(QtModules)"/>
      <QtPathBinaries Include="$(QtPathBinaries)"/>
      <QtPathLibraryExecutables Include="$(QtPathLibraryExecutables)"/>
      <QtHeaderSearchPath Include="$(QtHeaderSearchPath)"/>
      <QtLibrarySearchPath Include="$(QtLibrarySearchPath)"/>
      <QtVariables Include="$(QtVars)"/>
      <QMakeCodeLines Include="$(QMakeCodeLines)"/>
      <QtBuildConfig Include="$(QtBuildConfig)"/>
    </ItemGroup>
    <!--// Write end of .props (XML) file
        //  * Add Qt tools output directories to include path
        //  * Save settings backup
        //  * Close property group tag
        //  * Create QtVar items to export Qt variables to the calling instance of MSBuild
        //  * Close project tag -->
    <PropertyGroup>
      <!--
######## BEGIN generated XML (.props) ##############################################################
##    -->
      <QtVarsDataFileText>
        <![CDATA[
    <Qt_INCLUDEPATH_
      >%24(Qt_INCLUDEPATH_)%3B@(QtIncludePath->Distinct(),'%3B')</Qt_INCLUDEPATH_>
    <QtBkup_QtInstall
      >@(QtInstall,'%3B')</QtBkup_QtInstall>
    <QtBkup_QtModules
      >@(QtModules,'%3B')</QtBkup_QtModules>
    <QtBkup_QtPathBinaries
      >@(QtPathBinaries,'%3B')</QtBkup_QtPathBinaries>
    <QtBkup_QtPathLibraryExecutables
      >@(QtPathLibraryExecutables,'%3B')</QtBkup_QtPathLibraryExecutables>
    <QtBkup_QtHeaderSearchPath
      >@(QtHeaderSearchPath,'%3B')</QtBkup_QtHeaderSearchPath>
    <QtBkup_QtLibrarySearchPath
      >@(QtLibrarySearchPath,'%3B')</QtBkup_QtLibrarySearchPath>
    <QtBkup_QtVars
      >@(QtVariables,'%3B')</QtBkup_QtVars>
    <QtBkup_QMakeCodeLines
      >@(QMakeCodeLines,'%3B')</QtBkup_QMakeCodeLines>
    <QtBkup_QtBuildConfig
      >@(QtBuildConfig,'%3B')</QtBkup_QtBuildConfig>
    <QtVersion>$(QtVersion)</QtVersion>
    <QtVersionMajor>$(QtVersionMajor)</QtVersionMajor>
    <QtVersionMinor>$(QtVersionMinor)</QtVersionMinor>
    <QtVersionPatch>$(QtVersionPatch)</QtVersionPatch>
  </PropertyGroup>
</Project>
        ]]>
      </QtVarsDataFileText>
      <!--
##
######## END generated XML (.props) ################################################################
      -->
    </PropertyGroup>
    <WriteLinesToFile File="$(QtVarsWorkPath)" Lines="$(QtVarsDataFileText)"/>
    <!--// Create $(QtVarsOutputDir) -->
    <MakeDir Directories="$(QtVarsOutputDir)"/>
    <!--// Copy generated .props to $(QtVarsOutputDir) -->
    <Delete
      Condition="'$(ErrorLevel)' == '0'"
      Files="$(QtVarsFilePath)"/>
    <Copy
      Condition="'$(ErrorLevel)' == '0'"
      SourceFiles="$(QtVarsWorkPath)" DestinationFiles="$(QtVarsFilePath)"/>
    <!--// Copy generated qtvars_plugin_import.cpp to $(QtVarsOutputDir) -->
    <Delete
      Condition="'$(ErrorLevel)' == '0'"
      Files="$(QtVarsOutputDir)\qtvars_plugin_import.cpp"/>
    <Copy
      Condition="'$(ErrorLevel)' == '0' AND Exists('$(QtVarsWorkDir)\qtvars_plugin_import.cpp')"
      SourceFiles="$(QtVarsWorkDir)\qtvars_plugin_import.cpp"
      DestinationFiles="$(QtVarsOutputDir)\qtvars_plugin_import.cpp"/>
    <!--// In design-time, copy generated .props to randomly named file -->
    <PropertyGroup>
      <QtVarsDesignTimeNew
        Condition="'$(ErrorLevel)' == '0' AND '$(QtVSToolsBuild)' == 'true'"
        >$([System.IO.Path]::Combine('$(TEMP)','$([System.IO.Path]::GetRandomFileName()).designtime.props'))
      </QtVarsDesignTimeNew>
    </PropertyGroup>
    <Copy
      Condition="'$(ErrorLevel)' == '0' AND '$(QtVSToolsBuild)' == 'true'"
      SourceFiles="$(QtVarsFilePath)" DestinationFiles="$(QtVarsDesignTimeNew)"/>
    <WriteLinesToFile
      Condition="'$(ErrorLevel)' == '0' AND '$(QtVSToolsBuild)' == 'true'"
      File="$(QtVarsIndexPathDesignTime)" Overwrite="true" Lines="$(QtVarsDesignTimeNew)"/>
    <!--// Clean-up -->
    <ItemGroup>
      <QtModuleList Remove="@(QtModuleList)"/>
      <QMakeCodeLine Remove="@(QMakeCodeLine)"/>
      <QtIncludes Remove="@(QtIncludes)"/>
      <QtLibs Remove="@(QtLibs)"/>
      <QMakeError Remove="@(QMakeError)"/>
      <QtInstall Remove="@(QtInstall)"/>
      <QtModules Remove="@(QtModules)"/>
      <QtPathBinaries Remove="@(QtPathBinaries)"/>
      <QtPathLibraryExecutables Remove="@(QtPathLibraryExecutables)"/>
      <QtHeaderSearchPath Remove="@(QtHeaderSearchPath)"/>
      <QtLibrarySearchPath Remove="@(QtLibrarySearchPath)"/>
      <QtVariables Remove="@(QtVariables)"/>
      <QMakeCodeLines Remove="@(QMakeCodeLines)"/>
      <QtBuildConfig Remove="@(QtBuildConfig)"/>
      <QMake_Makefile_VarDef Remove="@(QMake_Makefile_VarDef)"/>
      <QMake_MSBuild_VarDef Remove="@(QMake_MSBuild_VarDef)"/>
      <QtVar Remove="@(QtVar)"/>
    </ItemGroup>
    <PropertyGroup>
      <QtIncludes/>
      <QtLibs/>
      <QtVarsProFileConfig/>
      <QtVarsProFileInput/>
      <QtVarsDataFileText/>
      <Cmd/>
      <QtMakefileVars/>
    </PropertyGroup>
  </Target>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  /// TARGET QtVarsPrepare
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Force QtVars target to run when Qt settings have changed
  // -->
  <Target Name="QtVarsPrepare" BeforeTargets="QtVars" Condition="Exists('$(QtVarsFilePath)')">
    <Delete Files="$(QtVarsFilePath)" Condition="Exists('$(QtVarsFilePath)')
        AND '$(QtBkup_QtInstall)' != '$(QtInstall)'" />
    <Delete Files="$(QtVarsFilePath)" Condition="Exists('$(QtVarsFilePath)')
        AND '$(QtBkup_QtModules)' != '$(QtModules)'" />
    <Delete Files="$(QtVarsFilePath)" Condition="Exists('$(QtVarsFilePath)')
        AND '$(QtBkup_QtPathBinaries)' != '$(QtPathBinaries)'" />
    <Delete Files="$(QtVarsFilePath)" Condition="Exists('$(QtVarsFilePath)')
        AND '$(QtBkup_QtPathLibraryExecutables)' != '$(QtPathLibraryExecutables)'" />
    <Delete Files="$(QtVarsFilePath)" Condition="Exists('$(QtVarsFilePath)')
        AND '$(QtBkup_QtHeaderSearchPath)' != '$(QtHeaderSearchPath)'" />
    <Delete Files="$(QtVarsFilePath)" Condition="Exists('$(QtVarsFilePath)')
        AND '$(QtBkup_QtLibrarySearchPath)' != '$(QtLibrarySearchPath)'" />
    <Delete Files="$(QtVarsFilePath)" Condition="Exists('$(QtVarsFilePath)')
        AND '$(QtBkup_QtVars)' != '$(QtVars)'" />
    <Delete Files="$(QtVarsFilePath)" Condition="Exists('$(QtVarsFilePath)')
        AND '$(QtBkup_QMakeCodeLines)' != '$(QMakeCodeLines)'" />
    <Delete Files="$(QtVarsFilePath)" Condition="Exists('$(QtVarsFilePath)')
        AND '$(QtBkup_QtBuildConfig)' != '$(QtBuildConfig)'" />
  </Target>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  /// TARGET QtVarsClean
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Delete all files generated by the QtVars target
  // -->
  <Target Name="QtVarsClean">
    <RemoveDir Directories="$(QtVarsOutputDir)"/>
  </Target>
  <!--
  /////////////////////////////////////////////////////////////////////////////////////////////////
  /// TARGET QtVarsDesignTime
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // Force QtVars target to run (called when project properties change)
  // -->
  <Target Name="QtVarsDesignTime">
    <CallTarget Targets="QtVarsClean"/>
    <CallTarget Targets="QtVars"/>
  </Target>
</Project>
Diff truncated after the above file
QtMSBuild/QtMsBuild/rcc/qt_import.props QtMSBuild/QtMsBuild/rcc/qtrcc.props QtMSBuild/QtMsBuild/rcc/qtrcc.targets QtMSBuild/QtMsBuild/rcc/qtrcc.xml QtMSBuild/QtMsBuild/rcc/qtrcc_cl.targets_TT QtMSBuild/QtMsBuild/rcc/qtrcc_v3.xml_TT QtMSBuild/QtMsBuild/repc/qt_import.props QtMSBuild/QtMsBuild/repc/qtrepc.props QtMSBuild/QtMsBuild/repc/qtrepc.targets QtMSBuild/QtMsBuild/repc/qtrepc.xml QtMSBuild/QtMsBuild/repc/qtrepc_cl.targets_TT QtMSBuild/QtMsBuild/repc/qtrepc_v3.xml_TT QtMSBuild/QtMsBuild/translation/qt_import.props QtMSBuild/QtMsBuild/translation/qttranslation.props QtMSBuild/QtMsBuild/translation/qttranslation.targets QtMSBuild/QtMsBuild/translation/qttranslation.xml QtMSBuild/QtMsBuild/uic/qt_import.props QtMSBuild/QtMsBuild/uic/qtuic.props QtMSBuild/QtMsBuild/uic/qtuic.targets QtMSBuild/QtMsBuild/uic/qtuic.xml QtMSBuild/QtMsBuild/uic/qtuic_v3.xml QtMSBuild/Tasks/CriticalSection.cs QtMSBuild/Tasks/DumpItems.cs QtMSBuild/Tasks/Expand.cs QtMSBuild/Tasks/Flatten.cs QtMSBuild/Tasks/GetItemHash.cs QtMSBuild/Tasks/GetVarsFromMSBuild.cs QtMSBuild/Tasks/GetVarsFromMakefile.cs QtMSBuild/Tasks/HostExec_LinuxSSL.cs QtMSBuild/Tasks/HostExec_LinuxWSL.cs QtMSBuild/Tasks/HostExec_LinuxWSL_Error.cs QtMSBuild/Tasks/HostExec_Windows.cs QtMSBuild/Tasks/HostTranslatePaths_LinuxSSL.cs QtMSBuild/Tasks/HostTranslatePaths_LinuxWSL.cs QtMSBuild/Tasks/HostTranslatePaths_LinuxWSL_Error.cs QtMSBuild/Tasks/HostTranslatePaths_Windows.cs QtMSBuild/Tasks/Join.cs QtMSBuild/Tasks/ListQrc.cs QtMSBuild/Tasks/ParseVarDefs.cs QtMSBuild/Tasks/QtRunWork.cs QtTmLanguage/qt/LICENSE QtTmLanguage/qt/pri.pro.tmLanguage QtVsTest/Macro.cs QtVsTest/MacroClient.h QtVsTest/MacroParser.cs QtVsTest/MacroServer.cs QtVsTest/Properties/AssemblyInfo.cs QtVsTest/QtVsTest.cs QtVsTest/QtVsTest.csproj QtVsTest/Resources/QtVsTest.ico QtVsTest/csmacro.tmLanguage_TT QtVsTest/csmacro.tmTheme_TT QtVsTest/source.extension.vsixmanifest_TT QtVsTools.Core/BuildConfig.cs QtVsTools.Core/CommandLineParser.cs QtVsTools.Core/Common/EnumExt.cs QtVsTools.Core/CompilerToolWrapper.cs QtVsTools.Core/CxxStreamReader.cs QtVsTools.Core/ExportProjectDialog.cs QtVsTools.Core/ExportProjectDialog.resx QtVsTools.Core/Extensions.cs QtVsTools.Core/FakeFilter.cs QtVsTools.Core/FilesToList.cs QtVsTools.Core/Filters.cs QtVsTools.Core/HelperFunctions.cs QtVsTools.Core/ImageButton.cs QtVsTools.Core/LinkerToolWrapper.cs QtVsTools.Core/MainWinWrapper.cs QtVsTools.Core/Messages.cs QtVsTools.Core/MocCmdChecker.cs QtVsTools.Core/MsBuildProject.cs QtVsTools.Core/Observable.cs QtVsTools.Core/ProFileContent.cs QtVsTools.Core/ProFileOption.cs QtVsTools.Core/ProSolution.cs QtVsTools.Core/ProjectExporter.cs QtVsTools.Core/ProjectImporter.cs QtVsTools.Core/ProjectMacros.cs QtVsTools.Core/Properties/AssemblyInfo.cs QtVsTools.Core/QMake.cs QtVsTools.Core/QMakeConf.cs QtVsTools.Core/QMakeQuery.cs QtVsTools.Core/QrcItem.cs QtVsTools.Core/QrcParser.cs QtVsTools.Core/QrcPrefix.cs QtVsTools.Core/QtConfig.cs QtVsTools.Core/QtModule.cs QtVsTools.Core/QtModules.cs QtVsTools.Core/QtMsBuild.cs QtVsTools.Core/QtProject.cs QtVsTools.Core/QtVSException.cs QtVsTools.Core/QtVSIPSettings.cs QtVsTools.Core/QtVersionManager.cs QtVsTools.Core/QtVsTools.Core.csproj QtVsTools.Core/QtVsTools.Core.ico QtVsTools.Core/RccOptions.cs QtVsTools.Core/Resources.cs QtVsTools.Core/Resources.resx QtVsTools.Core/Resources/delete.png QtVsTools.Core/Resources/delete_d.png QtVsTools.Core/Resources/newitem.png QtVsTools.Core/Resources/newitem_d.png QtVsTools.Core/SR.cs QtVsTools.Core/TemplateType.cs QtVsTools.Core/VersionInformation.cs QtVsTools.Core/VisualStudio/IProjectTracker.cs QtVsTools.Core/VisualStudio/VsServiceProvider.cs QtVsTools.Core/WaitDialog.cs QtVsTools.Package/Common/Concurrent.cs QtVsTools.Package/Common/ConcurrentStopwatch.cs QtVsTools.Package/Common/Disposable.cs QtVsTools.Package/Common/Json/DeferredObject.cs QtVsTools.Package/Common/Json/Serializable.cs QtVsTools.Package/Common/Json/SerializableEnum.cs QtVsTools.Package/Common/Json/Serializer.cs QtVsTools.Package/Common/NativeAPI.cs QtVsTools.Package/Common/PriorityQueue.cs QtVsTools.Package/Common/Prototyped.cs QtVsTools.Package/Common/PunisherQueue.cs QtVsTools.Package/Common/Timestamp.cs QtVsTools.Package/Common/VsToolsDialogWindow.cs QtVsTools.Package/Editors/Editor.QtDesigner.cs QtVsTools.Package/Editors/Editor.QtLinguist.cs QtVsTools.Package/Editors/Editor.QtResourceEditor.cs QtVsTools.Package/Editors/Editor.cs QtVsTools.Package/Language/LICENSE.APACHE QtVsTools.Package/Language/qml.qmlproject.tmLanguage QtVsTools.Package/Marketplace/Overview.html_TT QtVsTools.Package/Options/QtLegacyOptionsPage.cs QtVsTools.Package/Options/QtOptionsPage.cs QtVsTools.Package/Options/QtVersionsPage.cs QtVsTools.Package/Options/QtVersionsTable.cs QtVsTools.Package/Options/QtVersionsTable.xaml QtVsTools.Package/Package/AddTranslationDialog.cs QtVsTools.Package/Package/AddTranslationDialog.resx QtVsTools.Package/Package/ChangeFor.cs QtVsTools.Package/Package/DteEventsHandler.cs QtVsTools.Package/Package/ExtLoader.cs QtVsTools.Package/Package/FormChangeQtVersion.Designer.cs QtVsTools.Package/Package/FormChangeQtVersion.cs QtVsTools.Package/Package/FormChangeQtVersion.resx QtVsTools.Package/Package/FormProjectQtSettings.Designer.cs QtVsTools.Package/Package/FormProjectQtSettings.cs QtVsTools.Package/Package/FormProjectQtSettings.resx QtVsTools.Package/Package/ProjectQtSettings.cs QtVsTools.Package/Package/QMakeWrapper.cs QtVsTools.Package/Package/QtHelp.cs QtVsTools.Package/Package/QtHelpLinkChooser.xaml QtVsTools.Package/Package/QtHelpLinkChooser.xaml.cs QtVsTools.Package/Package/QtItemContextMenu.cs QtVsTools.Package/Package/QtMainMenu.cs QtVsTools.Package/Package/QtMsBuildConverter.cs QtVsTools.Package/Package/QtProjectContextMenu.cs QtVsTools.Package/Package/QtSolutionContextMenu.cs QtVsTools.Package/Package/SR.cs QtVsTools.Package/Package/Translation.cs QtVsTools.Package/Package/TranslationItem.cs QtVsTools.Package/Package/Version.cs QtVsTools.Package/Properties/AssemblyInfo.cs QtVsTools.Package/QML/Classification/QmlAsyncClassifier.cs QtVsTools.Package/QML/Classification/QmlClassificationFormat.cs QtVsTools.Package/QML/Classification/QmlErrorClassifier.cs QtVsTools.Package/QML/Classification/QmlExpressionEvalClassifier.cs QtVsTools.Package/QML/Classification/QmlSyntaxClassifier.cs QtVsTools.Package/QML/Classification/QmlTag.cs QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7BoilerPlate.cs QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7Breakpoint.cs QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7CodeContext.cs QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7Engine.cs QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7Enums.cs QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7Events.cs QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7Expression.cs QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7InfoHelpers.cs QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7Program.cs QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7Property.cs QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7StackFrame.cs QtVsTools.Package/QML/Debugging/QmlDebugLauncher.cs QtVsTools.Package/QML/Debugging/QmlDebugger.cs QtVsTools.Package/QML/Debugging/QmlFileSystem.cs QtVsTools.Package/QML/Debugging/V4/Messages/QmlDebugV4Backtrace.cs QtVsTools.Package/QML/Debugging/V4/Messages/QmlDebugV4Break.cs QtVsTools.Package/QML/Debugging/V4/Messages/QmlDebugV4ClearBreakpoint.cs QtVsTools.Package/QML/Debugging/V4/Messages/QmlDebugV4Connect.cs QtVsTools.Package/QML/Debugging/V4/Messages/QmlDebugV4Continue.cs QtVsTools.Package/QML/Debugging/V4/Messages/QmlDebugV4Disconnect.cs QtVsTools.Package/QML/Debugging/V4/Messages/QmlDebugV4Evaluate.cs QtVsTools.Package/QML/Debugging/V4/Messages/QmlDebugV4Exception.cs QtVsTools.Package/QML/Debugging/V4/Messages/QmlDebugV4Frame.cs QtVsTools.Package/QML/Debugging/V4/Messages/QmlDebugV4JsObject.cs QtVsTools.Package/QML/Debugging/V4/Messages/QmlDebugV4JsValue.cs QtVsTools.Package/QML/Debugging/V4/Messages/QmlDebugV4Lookup.cs QtVsTools.Package/QML/Debugging/V4/Messages/QmlDebugV4Message.cs QtVsTools.Package/QML/Debugging/V4/Messages/QmlDebugV4Scope.cs QtVsTools.Package/QML/Debugging/V4/Messages/QmlDebugV4SetBreakpoint.cs QtVsTools.Package/QML/Debugging/V4/Messages/QmlDebugV4SetExceptionBreak.cs QtVsTools.Package/QML/Debugging/V4/Messages/QmlDebugV4Version.cs QtVsTools.Package/QML/Debugging/V4/QmlDebugV4Client.cs QtVsTools.Package/QML/Debugging/V4/QmlDebugV4Protocol.cs QtVsTools.Package/QML/Parser/QmlParserDiagnostics.cs QtVsTools.Package/QML/Parser/QmlParserInterop.cs QtVsTools.Package/QML/Syntax/QmlAst.cs QtVsTools.Package/QML/Syntax/QmlSyntax.cs QtVsTools.Package/QtMenus.vsct_TT QtVsTools.Package/QtMsBuild/QtModulesEditor.cs QtVsTools.Package/QtMsBuild/QtModulesPopup.xaml QtVsTools.Package/QtMsBuild/QtModulesPopup.xaml.cs QtVsTools.Package/QtMsBuild/QtProjectBuild.cs QtVsTools.Package/QtMsBuild/QtProjectIntelliSense.cs QtVsTools.Package/QtMsBuild/QtProjectLogger.cs QtVsTools.Package/QtMsBuild/QtProjectTracker.cs QtVsTools.Package/QtMsBuild/QtVersionProvider.cs QtVsTools.Package/QtVsTools.Package.csproj QtVsTools.Package/QtVsTools.Qml.Debug.pkgdef QtVsTools.Package/QtVsTools.ico QtVsTools.Package/QtVsToolsPackage.cs QtVsTools.Package/Resources.resx QtVsTools.Package/Resources/menuimages.png QtVsTools.Package/Resources/qt.ico QtVsTools.Package/VSPackage.resx QtVsTools.Package/VisualStudio/VsShell.cs QtVsTools.Package/preview.png QtVsTools.Package/qt.ico QtVsTools.Package/qt5.natvis.xml QtVsTools.Package/qt6.natvis.xml QtVsTools.Package/qtmodules.xml QtVsTools.Package/source.extension.vsixmanifest_TT QtVsTools.RegExpr/Properties/AssemblyInfo.cs QtVsTools.RegExpr/QtVsTools.RegExpr.csproj QtVsTools.RegExpr/README QtVsTools.RegExpr/expression/CharClassLiteral.cs QtVsTools.RegExpr/expression/CharClassRange.cs QtVsTools.RegExpr/expression/CharClassSet.cs QtVsTools.RegExpr/expression/RegExpr.cs QtVsTools.RegExpr/expression/RegExprAssert.cs QtVsTools.RegExpr/expression/RegExprChoice.cs QtVsTools.RegExpr/expression/RegExprLiteral.cs QtVsTools.RegExpr/expression/RegExprRepeat.cs QtVsTools.RegExpr/expression/RegExprSequence.cs QtVsTools.RegExpr/expression/RegExprToken.cs QtVsTools.RegExpr/expression/Renderer.cs QtVsTools.RegExpr/parser/ParseTree.cs QtVsTools.RegExpr/parser/Parser.cs QtVsTools.RegExpr/production/Production.cs QtVsTools.RegExpr/production/ProductionRule.cs QtVsTools.RegExpr/production/ProductionRuleAction.cs QtVsTools.RegExpr/utils/Consts.cs QtVsTools.RegExpr/utils/Utils.cs QtVsTools.Wizards/Properties/AssemblyInfo.cs QtVsTools.Wizards/QtVsTools.Wizards.csproj QtVsTools.Wizards/Resources/ExpanderStyle.xaml QtVsTools.Wizards/Resources/Qt-logo-small.png QtVsTools.Wizards/Resources/QtProjectWizard.ico QtVsTools.Wizards/Resources/medium.png QtVsTools.Wizards/Resources/small.png QtVsTools.Wizards/Wizards/ClassWizard/AddClassPage.xaml QtVsTools.Wizards/Wizards/ClassWizard/AddClassPage.xaml.cs QtVsTools.Wizards/Wizards/ClassWizard/AddClassWizard.cs QtVsTools.Wizards/Wizards/ClassWizard/Class.cs QtVsTools.Wizards/Wizards/ClassWizard/ClassKind.cs QtVsTools.Wizards/Wizards/ClassWizard/Core/CoreClassPage.xaml QtVsTools.Wizards/Wizards/ClassWizard/Core/CoreClassPage.xaml.cs QtVsTools.Wizards/Wizards/ClassWizard/Core/CoreClassWizard.cs QtVsTools.Wizards/Wizards/ClassWizard/Gui/GuiClassPage.xaml QtVsTools.Wizards/Wizards/ClassWizard/Gui/GuiClassPage.xaml.cs QtVsTools.Wizards/Wizards/ClassWizard/Gui/GuiClassWizard.cs QtVsTools.Wizards/Wizards/ClassWizard/IClassWizard.cs QtVsTools.Wizards/Wizards/ClassWizard/UiClassInclusion.cs QtVsTools.Wizards/Wizards/ProjectWizard/ConfigPage.xaml QtVsTools.Wizards/Wizards/ProjectWizard/ConfigPage.xaml.cs QtVsTools.Wizards/Wizards/ProjectWizard/Console/ConsoleWizard.cs QtVsTools.Wizards/Wizards/ProjectWizard/Designer/DesignerPage.xaml QtVsTools.Wizards/Wizards/ProjectWizard/Designer/DesignerPage.xaml.cs QtVsTools.Wizards/Wizards/ProjectWizard/Designer/DesignerWizard.cs QtVsTools.Wizards/Wizards/ProjectWizard/Empty/EmptyWizard.cs QtVsTools.Wizards/Wizards/ProjectWizard/Gui/GuiPage.xaml QtVsTools.Wizards/Wizards/ProjectWizard/Gui/GuiPage.xaml.cs QtVsTools.Wizards/Wizards/ProjectWizard/Gui/GuiWizard.cs QtVsTools.Wizards/Wizards/ProjectWizard/Library/LibraryClassPage.xaml QtVsTools.Wizards/Wizards/ProjectWizard/Library/LibraryClassPage.xaml.cs QtVsTools.Wizards/Wizards/ProjectWizard/Library/LibraryWizard.cs QtVsTools.Wizards/Wizards/ProjectWizard/ProjectTemplateWizard.cs QtVsTools.Wizards/Wizards/ProjectWizard/Quick/QuickWizard.cs QtVsTools.Wizards/Wizards/ProjectWizard/Server/ServerPage.xaml QtVsTools.Wizards/Wizards/ProjectWizard/Server/ServerPage.xaml.cs QtVsTools.Wizards/Wizards/ProjectWizard/Server/ServerWizard.cs QtVsTools.Wizards/Wizards/Util/ClassNameValidationRule.cs QtVsTools.Wizards/Wizards/Util/FileExistsInFilterValidationRule.cs QtVsTools.Wizards/Wizards/Util/FileNameValidationRule.cs QtVsTools.Wizards/Wizards/Util/NativeMethods.cs QtVsTools.Wizards/Wizards/Util/SortComboBoxItem.cs QtVsTools.Wizards/Wizards/Util/UnsafeNativeMethods.cs QtVsTools.Wizards/Wizards/Util/VCLanguageManagerValidationRule.cs QtVsTools.Wizards/Wizards/WizardData.cs QtVsTools.Wizards/Wizards/WizardIntroPage.xaml QtVsTools.Wizards/Wizards/WizardIntroPage.xaml.cs QtVsTools.Wizards/Wizards/WizardPage.cs QtVsTools.Wizards/Wizards/WizardResult.cs QtVsTools.Wizards/Wizards/WizardWindow.xaml QtVsTools.Wizards/Wizards/WizardWindow.xaml.cs README.md Templates/console/Properties/AssemblyInfo.cs Templates/console/QtTemplate.Project.Console.csproj Templates/console/console.ico Templates/console/console.vcxproj Templates/console/console.vcxproj.filters Templates/console/console.vstemplate_TT Templates/console/main.cpp Templates/designer/Properties/AssemblyInfo.cs Templates/designer/QtTemplate.Project.Designer.csproj Templates/designer/designer.ico Templates/designer/designer.vcxproj Templates/designer/designer.vcxproj.filters Templates/designer/designer.vstemplate_TT Templates/designer/plugin.cpp Templates/designer/plugin.h Templates/designer/plugin.json Templates/designer/stdafx.cpp Templates/designer/stdafx.h Templates/designer/widget.cpp Templates/designer/widget.h Templates/dialogbuttonbottom/Properties/AssemblyInfo.cs Templates/dialogbuttonbottom/QtTemplate.Item.DialogButtonBottom.csproj Templates/dialogbuttonbottom/dialogbuttonbottom.ico Templates/dialogbuttonbottom/dialogbuttonbottom.ui Templates/dialogbuttonbottom/dialogbuttonbottom.vstemplate Templates/dialogbuttonright/Properties/AssemblyInfo.cs Templates/dialogbuttonright/QtTemplate.Item.DialogButtonRight.csproj Templates/dialogbuttonright/dialogbuttonright.ico Templates/dialogbuttonright/dialogbuttonright.ui Templates/dialogbuttonright/dialogbuttonright.vstemplate Templates/empty/Properties/AssemblyInfo.cs Templates/empty/QtTemplate.Project.Empty.csproj Templates/empty/empty.ico Templates/empty/empty.vcxproj Templates/empty/empty.vcxproj.filters Templates/empty/empty.vstemplate_TT Templates/gui/Properties/AssemblyInfo.cs Templates/gui/QtTemplate.Project.Gui.csproj Templates/gui/gui.ico Templates/gui/gui.vcxproj Templates/gui/gui.vcxproj.filters Templates/gui/gui.vstemplate_TT Templates/gui/main.cpp Templates/gui/stdafx.cpp Templates/gui/stdafx.h Templates/gui/widget.cpp Templates/gui/widget.h Templates/gui/widget.ui Templates/lib/Properties/AssemblyInfo.cs Templates/lib/QtTemplate.Project.Lib.csproj Templates/lib/global.h Templates/lib/header.h Templates/lib/lib.ico Templates/lib/lib.vcxproj Templates/lib/lib.vcxproj.filters Templates/lib/lib.vstemplate_TT Templates/lib/source.cpp Templates/lib/stdafx.cpp Templates/lib/stdafx.h Templates/mainwindow/Properties/AssemblyInfo.cs Templates/mainwindow/QtTemplate.Item.MainWindow.csproj Templates/mainwindow/mainwindow.ico Templates/mainwindow/mainwindow.ui Templates/mainwindow/mainwindow.vstemplate Templates/qml/NewFile.qml Templates/qml/Properties/AssemblyInfo.cs Templates/qml/QtTemplate.Item.QMLFile.csproj Templates/qml/qml.ico Templates/qml/qml.vstemplate Templates/qmldir/Properties/AssemblyInfo.cs Templates/qmldir/QtTemplate.Item.QMLDir.csproj Templates/qmldir/qml.ico Templates/qmldir/qmldir Templates/qmldir/qmldir.vstemplate Templates/quick/Properties/AssemblyInfo.cs Templates/quick/QtTemplate.Project.Quick.csproj Templates/quick/main.cpp Templates/quick/main.qml Templates/quick/qml.qrc Templates/quick/quick.ico Templates/quick/quick.vcxproj Templates/quick/quick.vcxproj.filters Templates/quick/quick.vstemplate_TT Templates/resource/Properties/AssemblyInfo.cs Templates/resource/QtTemplate.Item.Resource.csproj Templates/resource/resource.ico Templates/resource/resource.qrc Templates/resource/resource.vstemplate Templates/server/Properties/AssemblyInfo.cs Templates/server/QtTemplate.Project.Server.csproj Templates/server/header.h Templates/server/server.def Templates/server/server.ico Templates/server/server.rc Templates/server/server.vcxproj Templates/server/server.vcxproj.filters Templates/server/server.vstemplate_TT Templates/server/source.cpp Templates/server/stdafx.cpp Templates/server/stdafx.h Templates/server/widget.ui Templates/widget/Properties/AssemblyInfo.cs Templates/widget/QtTemplate.Item.Widget.csproj Templates/widget/widget.ico Templates/widget/widget.ui Templates/widget/widget.vstemplate Tests/BigSolution/generator/App.config Tests/BigSolution/generator/Program.cs Tests/BigSolution/generator/Properties/AssemblyInfo.cs Tests/BigSolution/generator/generator.csproj Tests/BigSolution/generator/generator.sln Tests/BigSolution/template/BigProjectNNN/BigClassNNN.cpp Tests/BigSolution/template/BigProjectNNN/BigClassNNN.h Tests/BigSolution/template/BigProjectNNN/BigProjectNNN.qrc Tests/BigSolution/template/BigProjectNNN/BigProjectNNN.ui Tests/BigSolution/template/BigProjectNNN/BigProjectNNN.vcxproj Tests/BigSolution/template/BigProjectNNN/BigProjectNNN.vcxproj.filters Tests/BigSolution/template/BigProjectNNN/BigProjectQtClassNNN.cpp Tests/BigSolution/template/BigProjectNNN/BigProjectQtClassNNN.h Tests/BigSolution/template/BigProjectNNN/bigprojectnnn_global.h Tests/BigSolution/template/BigSolution.sln Tests/SampleTest/Macros.qrc Tests/SampleTest/SampleTest.pro Tests/SampleTest/SampleTest.sln Tests/SampleTest/SampleTest.vcxproj Tests/SampleTest/SampleTest.vcxproj.filters Tests/SampleTest/Test_CreateGuiApp.csmacro Tests/SampleTest/Test_DebugGuiApp.csmacro Tests/SampleTest/Test_ImportProFile.csmacro Tests/SampleTest/Test_QtVsToolsLoaded.csmacro Tests/SampleTest/Test_RebuildSolution.csmacro Tests/SampleTest/main.cpp Tests/Test_QtMsBuild.Tasks/Properties/AssemblyInfo.cs Tests/Test_QtMsBuild.Tasks/TestTaskLoggingHelper.cs Tests/Test_QtMsBuild.Tasks/Test_Join.cs Tests/Test_QtMsBuild.Tasks/Test_QtMsBuild.Tasks.csproj Tests/Test_QtVsTools.PriorityQueue/Properties/AssemblyInfo.cs Tests/Test_QtVsTools.PriorityQueue/Test_PriorityQueue.cs Tests/Test_QtVsTools.PriorityQueue/Test_QtVsTools.PriorityQueue.csproj Tests/Test_QtVsTools.RegExpr/Properties/AssemblyInfo.cs Tests/Test_QtVsTools.RegExpr/Test_MacroParser.cs Tests/Test_QtVsTools.RegExpr/Test_QtVsTools.RegExpr.csproj Tests/Test_QtVsTools.RegExpr/Test_SubTokens.cs Tests/Test_QtVsTools.RegExpr/Test_XmlIntParser.cs Tests/concurrency/Solution1/MyPropertySheet.props Tests/concurrency/Solution1/QtClassLibrary1/QtClass.cpp Tests/concurrency/Solution1/QtClassLibrary1/QtClass.h Tests/concurrency/Solution1/QtClassLibrary1/QtClassLibrary1.cpp Tests/concurrency/Solution1/QtClassLibrary1/QtClassLibrary1.h Tests/concurrency/Solution1/QtClassLibrary1/QtClassLibrary1.vcxproj Tests/concurrency/Solution1/QtClassLibrary1/QtClassLibrary1.vcxproj.filters Tests/concurrency/Solution1/QtClassLibrary1/qtclasslibrary1_global.h Tests/concurrency/Solution1/QtWidgetsApplication1/QtWidgetsApplication1.cpp Tests/concurrency/Solution1/QtWidgetsApplication1/QtWidgetsApplication1.h Tests/concurrency/Solution1/QtWidgetsApplication1/QtWidgetsApplication1.qrc Tests/concurrency/Solution1/QtWidgetsApplication1/QtWidgetsApplication1.ui Tests/concurrency/Solution1/QtWidgetsApplication1/QtWidgetsApplication1.vcxproj Tests/concurrency/Solution1/QtWidgetsApplication1/QtWidgetsApplication1.vcxproj.filters Tests/concurrency/Solution1/QtWidgetsApplication1/main.cpp Tests/concurrency/Solution1/QtWidgetsApplication2/QtWidgetsApplication2.cpp Tests/concurrency/Solution1/QtWidgetsApplication2/QtWidgetsApplication2.h Tests/concurrency/Solution1/QtWidgetsApplication2/QtWidgetsApplication2.qrc Tests/concurrency/Solution1/QtWidgetsApplication2/QtWidgetsApplication2.ui Tests/concurrency/Solution1/QtWidgetsApplication2/QtWidgetsApplication2.vcxproj Tests/concurrency/Solution1/QtWidgetsApplication2/QtWidgetsApplication2.vcxproj.filters Tests/concurrency/Solution1/QtWidgetsApplication2/main.cpp Tests/concurrency/Solution1/Solution1.sln Tests/concurrency/Solution1/StaticLib1/Header.h Tests/concurrency/Solution1/StaticLib1/StaticLib1.cpp Tests/concurrency/Solution1/StaticLib1/StaticLib1.vcxproj Tests/concurrency/Solution1/StaticLib1/StaticLib1.vcxproj.filters Tests/concurrency/loop_msbuild.bat VsQml/README VsQml/astvisitor.cpp VsQml/astvisitor.h VsQml/vsqml.cpp VsQml/vsqml.h VsQml/vsqml.vcxproj VsQml/vsqml.vcxproj.filters VsQml/vsqml_global.h VsQml/vsqmldebugclient.cpp VsQml/vsqmldebugclient.h common.tt doc/config/macros.qdocconf doc/config/qtvstools-project.qdocconf doc/config/style/qt5-sidebar.html doc/doc.pri doc/images/qtvstools-addressbook-adddialog.png doc/images/qtvstools-addressbook-mainwindow.png doc/images/qtvstools-export-project.png doc/images/qtvstools-minus.png doc/images/qtvstools-plus.png doc/images/qtvstools-qrc-editor.png doc/images/qtvstools-qt-project-settings.png doc/images/qtvstools-qt-versions.png doc/images/qtvstools-qt-widget-class-wizard.png doc/images/qtvstools-widgets-app-class.png doc/images/qtvstools-widgets-app-modules.png doc/qtvstools-online.qdocconf doc/qtvstools.qdocconf doc/src/externallinks.qdoc doc/src/qtvstools.qdoc doc/tutorial/AddressBook/AddressBook.ico doc/tutorial/AddressBook/AddressBook.pro doc/tutorial/AddressBook/AddressBook.rc doc/tutorial/AddressBook/adddialog.cpp doc/tutorial/AddressBook/adddialog.h doc/tutorial/AddressBook/adddialog.ui doc/tutorial/AddressBook/addressbook.cpp doc/tutorial/AddressBook/addressbook.h doc/tutorial/AddressBook/addressbook.ui doc/tutorial/AddressBook/main.cpp references.props transform.targets version.targets version.tt vstools.bat vstools.pri_TT vstools.pro vstools.sln