Merge remote-tracking branch 'origin/11.0' into qds/dev

Conflicts: src/plugins/qmldesigner/designercore/metainfo/metainfo.cpp
  src/plugins/qmlprojectmanager/cmakegen/generatecmakelists.cpp
  tests/auto/qml/qmlprojectmanager/fileformat/fileformat.qbs
  tests/auto/qml/qmlprojectmanager/fileformat/tst_fileformat.cpp

Change-Id: I257f1908917bcc58805619b53b6866f2f73ca544
This commit is contained in:
Tim Jenssen
2023-06-02 21:23:26 +02:00
2486 changed files with 100472 additions and 44365 deletions

View File

@@ -1,10 +1,9 @@
add_subdirectory(3rdparty)
add_subdirectory(buildoutputparser)
option(BUILD_CPLUSPLUS_TOOLS "Build CPlusPlus tools" OFF)
function(add_qtc_cpp_tool name)
add_qtc_executable(${name}
SKIP_INSTALL
DEFINES
PATH_PREPROCESSOR_CONFIG=\"${CMAKE_CURRENT_SOURCE_DIR}/cplusplus-shared/pp-configuration.inc\"
${ARGN}
@@ -17,12 +16,10 @@ function(add_qtc_cpp_tool name)
)
endfunction()
if (BUILD_CPLUSPLUS_TOOLS)
add_qtc_cpp_tool(cplusplus-ast2png "")
add_qtc_cpp_tool(cplusplus-frontend "")
add_qtc_cpp_tool(cplusplus-mkvisitor PATH_AST_H=\"${CMAKE_CURRENT_SOURCE_DIR}/../libs/3rdparty/cplusplus/AST.h\")
add_qtc_cpp_tool(cplusplus-update-frontend PATH_CPP_FRONTEND=\"${CMAKE_CURRENT_SOURCE_DIR}/../libs/3rdparty/cplusplus\" PATH_DUMPERS_FILE=\"${CMAKE_CURRENT_SOURCE_DIR}/cplusplus-ast2png/dumpers.inc\")
endif()
add_qtc_cpp_tool(cplusplus-ast2png "")
add_qtc_cpp_tool(cplusplus-frontend "")
add_qtc_cpp_tool(cplusplus-mkvisitor PATH_AST_H=\"${CMAKE_CURRENT_SOURCE_DIR}/../libs/3rdparty/cplusplus/AST.h\")
add_qtc_cpp_tool(cplusplus-update-frontend PATH_CPP_FRONTEND=\"${CMAKE_CURRENT_SOURCE_DIR}/../libs/3rdparty/cplusplus\" PATH_DUMPERS_FILE=\"${CMAKE_CURRENT_SOURCE_DIR}/cplusplus-ast2png/dumpers.inc\")
if (APPLE)
add_subdirectory(disclaim)
@@ -46,3 +43,5 @@ add_subdirectory(wininterrupt) ## windows only
if (EXISTS ${CMAKE_CURRENT_LIST_DIR}/perfparser/CMakeLists.txt)
add_subdirectory(perfparser)
endif()
add_subdirectory(process_stub)

View File

@@ -1,6 +1,7 @@
import qbs 1.0
QtcTool {
install: false
Depends { name: "Qt"; submodules: ["core", "widgets"]; }
Depends { name: "CPlusPlus" }
Depends { name: "Utils" }

View File

@@ -3,7 +3,6 @@ import qbs.Environment
Project {
name: "CPlusPlus Tools"
condition: Environment.getEnv("BUILD_CPLUSPLUS_TOOLS")
references: [
"3rdparty/cplusplus-keywordgen/cplusplus-keywordgen.qbs",
"cplusplus-ast2png/cplusplus-ast2png.qbs",

View File

@@ -1,15 +0,0 @@
This directory needs to contain the files
icon_128x128.png
icon_128x128@2x.png
icon_16x16.png
icon_16x16@2x.png
icon_256x256.png
icon_256x256@2x.png
icon_32x32.png
icon_32x32@2x.png
icon_512x512.png
icon_512x512@2x.png
On OSX, they are obtainable by executing the following command:
iconutil -c iconset /System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/GenericDocumentIcon.icns

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 79 KiB

View File

@@ -1,879 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="2104"
height="4713"
id="svg3397"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="documenttypeicons.svg"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90">
<defs
id="defs3399">
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath6024">
<rect
style="fill:none;stroke:none"
id="rect6026"
width="87"
height="100"
x="225"
y="-5429" />
</clipPath>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="16"
inkscape:cx="27.375271"
inkscape:cy="533.28239"
inkscape:document-units="px"
inkscape:current-layer="layer3"
showgrid="true"
inkscape:window-width="2880"
inkscape:window-height="1503"
inkscape:window-x="-13"
inkscape:window-y="527"
inkscape:window-maximized="1"
inkscape:snap-grids="true"
showguides="true"
inkscape:guide-bbox="true"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0">
<inkscape:grid
type="xygrid"
id="grid3405"
empspacing="1"
visible="true"
enabled="true"
snapvisiblegridlinesonly="false"
dotted="true"
originx="-16"
originy="-7436" />
<inkscape:grid
type="xygrid"
id="grid3407"
empspacing="1"
visible="true"
enabled="true"
snapvisiblegridlinesonly="false"
spacingx="4px"
spacingy="4px"
originx="-16"
originy="-7436" />
<sodipodi:guide
position="266,-6734"
orientation="0,1"
id="guide4571" />
<sodipodi:guide
position="1,-7431"
orientation="0,1"
id="guide4573" />
</sodipodi:namedview>
<metadata
id="metadata3402">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="qt-logos"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-16,11096.638)" />
<g
inkscape:groupmode="layer"
id="layer3"
inkscape:label="qt-appicons"
transform="translate(-16,11069)">
<g
id="uifile_icon_16x16"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90"
transform="translate(0,-1036)">
<image
sodipodi:absref="C:\Users\aportale\dev\qtcreator-super\qtcreator\src\tools\icons\GenericDocumentIcon.iconset\icon_16x16.png"
xlink:href="GenericDocumentIcon.iconset\icon_16x16.png"
y="-5336"
x="16"
id="image3192"
height="16"
width="16" />
<rect
y="-5325"
x="27.62998"
height="2.9999692"
width="2.3699887"
id="rect4308-8"
style="fill:#cd9aa3;fill-opacity:1;stroke:none" />
<path
id="path4291-2"
d="m 19,-5324 -1,0.5082 1,0.4918 z"
style="fill:#47484a;fill-opacity:1;stroke:none"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccc" />
<g
id="tinyqt"
transform="translate(-50,-5859)">
<path
sodipodi:nodetypes="ccccccccc"
inkscape:connector-curvature="0"
id="path5089"
d="m 78,532.5 -1.5,1.5 -6.5,0 0,-4.5 1.5,-1.5 3.484375,-0.004 0,0.99807 3,0.002 z"
style="opacity:1;fill:#41cd52;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<g
id="g4959"
style="stroke:#ffffff;stroke-width:0.89999998;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
transform="translate(-2,-2)">
<path
sodipodi:nodetypes="zzzzz"
inkscape:connector-curvature="0"
id="path4945"
d="m 74.5,531.5 c 1,0 1,0.28518 1,1.5 0,1.21481 0,1.5 -1,1.5 -1,0 -1,-0.30273 -1,-1.5 0,-1.19726 0,-1.5 1,-1.5 z"
style="opacity:1;fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.89999998;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path4953"
d="m 75.309359,534.5 1.198874,1.38951"
style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.89999998;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
sodipodi:nodetypes="ccc"
inkscape:connector-curvature="0"
id="path4955"
d="m 77.484375,530.9963 0,2.89815 c 0.0017,0.96521 0.846972,0.77673 1.515655,0.60555"
style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.89999998;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path4957"
d="m 76.5,532.5 2.5,0"
style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.89999998;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
</g>
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="path4286-4"
d="m 21,-5325 -2,1 0,1 2,1 z"
style="fill:#e1cab0;fill-opacity:1;stroke:none" />
<rect
y="-5325.0005"
x="21"
height="1.999"
width="6"
id="rect4296-5"
style="fill:#f7ec07;fill-opacity:1;stroke:none" />
<rect
style="fill:#f7aa03;fill-opacity:1;stroke:none"
id="rect4298-5"
width="6"
height="1.9999794"
x="21"
y="-5324" />
<rect
style="fill:#fbcb00;fill-opacity:1;stroke:none"
id="rect4300-1"
width="6"
height="0.99998969"
x="21"
y="-5324" />
<rect
style="fill:#e4e6e7;fill-opacity:1;stroke:none"
id="rect4302-7"
width="1"
height="0.99998969"
x="26.98"
y="-5325" />
<rect
y="-5323"
x="26.98"
height="0.99998969"
width="1"
id="rect4304-1"
style="fill:#aeb1b3;fill-opacity:1;stroke:none" />
<rect
y="-5324"
x="26.98"
height="0.99998969"
width="1"
id="rect4306-1"
style="fill:#c8c9c9;fill-opacity:1;stroke:none" />
</g>
<g
id="uifile_icon_32x32"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90"
transform="translate(0,-1036)">
<image
sodipodi:absref="C:\Users\aportale\dev\qtcreator-super\qtcreator\src\tools\icons\GenericDocumentIcon.iconset\icon_32x32.png"
xlink:href="GenericDocumentIcon.iconset\icon_32x32.png"
y="-5352"
x="32"
id="image3203"
height="32"
width="32" />
<text
sodipodi:linespacing="125%"
id="text3510"
y="-6087.4551"
x="39.699661"
style="font-style:normal;font-weight:normal;font-size:4.71243429px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none"
xml:space="preserve"
transform="scale(1.1435936,0.87443651)"><tspan
id="tspan3514"
y="-6087.4551"
x="39.699661"
sodipodi:role="line"
style="font-weight:bold;-inkscape-font-specification:'Sans Bold'">UI</tspan></text>
<image
sodipodi:absref="C:\Users\aportale\dev\qtcreator-super\qtcreator\src\tools\icons\designer_icon_16x16.png"
xlink:href="designer_icon_16x16.png"
width="16"
height="16"
preserveAspectRatio="none"
style="image-rendering:optimizeSpeed"
id="image5338"
x="40"
y="-5344" />
</g>
<g
id="uifile_icon_128x128"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90"
transform="translate(0,-1036)">
<image
sodipodi:absref="C:\Users\aportale\dev\qtcreator-super\qtcreator\src\tools\icons\GenericDocumentIcon.iconset\icon_128x128.png"
xlink:href="GenericDocumentIcon.iconset\icon_128x128.png"
y="-5448"
x="200"
id="image3214"
height="128"
width="128" />
<g
id="g4328"
clip-path="url(#clipPath6024)"
transform="translate(-1.6893267,0.99880497)">
<use
x="0"
y="0"
xlink:href="#text3510"
id="use4326"
transform="matrix(2.3826256,0,0,2.9999998,149.91558,10637.104)"
width="1920"
height="1080" />
</g>
<image
sodipodi:absref="C:\Users\aportale\dev\qtcreator-super\qtcreator\src\tools\icons\designer_icon_64x64.png"
xlink:href="designer_icon_64x64.png"
width="64"
height="64"
preserveAspectRatio="none"
style="image-rendering:optimizeSpeed"
id="image5457"
x="232"
y="-5416" />
</g>
<g
id="uifile_icon_256x256"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90"
transform="translate(0,-1036)">
<image
sodipodi:absref="C:\Users\aportale\dev\qtcreator-super\qtcreator\src\tools\icons\GenericDocumentIcon.iconset\icon_256x256.png"
xlink:href="GenericDocumentIcon.iconset\icon_256x256.png"
y="-5576"
x="328"
id="image3225"
height="256"
width="256" />
<use
height="1080"
width="1920"
transform="matrix(2,0,0,2,-72,5315.173)"
id="use4332"
xlink:href="#g4328"
y="0"
x="0" />
<image
sodipodi:absref="C:\Users\aportale\dev\qtcreator-super\qtcreator\src\tools\icons\designer_icon_128x128.png"
xlink:href="designer_icon_128x128.png"
y="-5512"
x="392"
id="image6519"
style="image-rendering:optimizeSpeed"
preserveAspectRatio="none"
height="128"
width="128" />
</g>
<g
id="uifile_icon_512x512"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90"
transform="translate(0,-1036)">
<image
sodipodi:absref="C:\Users\aportale\dev\qtcreator-super\qtcreator\src\tools\icons\GenericDocumentIcon.iconset\icon_512x512.png"
xlink:href="GenericDocumentIcon.iconset\icon_512x512.png"
y="-5832"
x="584"
id="image3236"
height="512"
width="512" />
<use
height="1080"
width="1920"
transform="matrix(2,0,0,2,-72,5320.6089)"
id="use4334"
xlink:href="#use4332"
y="0"
x="0" />
<image
sodipodi:absref="C:\Users\aportale\dev\qtcreator-super\qtcreator\src\tools\icons\designer_icon_256x256.png"
xlink:href="designer_icon_256x256.png"
width="256"
height="256"
preserveAspectRatio="none"
style="image-rendering:optimizeSpeed"
id="image4519"
x="712"
y="-5704" />
</g>
<g
transform="translate(0,-1560)"
inkscape:export-ydpi="90"
inkscape:export-xdpi="90"
id="uifile_icon_16x16@2x">
<image
sodipodi:absref="C:\Users\aportale\dev\qtcreator-super\qtcreator\src\tools\icons\GenericDocumentIcon.iconset\icon_16x16@2x.png"
xlink:href="GenericDocumentIcon.iconset\icon_16x16@2x.png"
width="32"
height="32"
id="image4080"
x="32"
y="-5352" />
<text
transform="scale(1.0533249,0.94937471)"
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:4.34046173px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none"
x="43.44009"
y="-5606.9463"
id="text4082"
sodipodi:linespacing="125%"><tspan
style="font-weight:bold;-inkscape-font-specification:'Sans Bold'"
sodipodi:role="line"
x="43.44009"
y="-5606.9463"
id="tspan4084">UI</tspan></text>
<image
sodipodi:absref="C:\Users\aportale\dev\qtcreator-super\qtcreator\src\tools\icons\designer_icon_16x16.png"
xlink:href="designer_icon_16x16.png"
width="16"
height="16"
preserveAspectRatio="none"
style="image-rendering:optimizeSpeed"
id="image5349"
x="40"
y="-5344" />
</g>
<g
id="uifile_icon_32x32@2x">
<image
sodipodi:absref="C:\Users\aportale\dev\qtcreator-super\qtcreator\src\tools\icons\GenericDocumentIcon.iconset\icon_32x32@2x.png"
xlink:href="GenericDocumentIcon.iconset\icon_32x32@2x.png"
y="-6944"
x="64"
id="image4120"
height="64"
width="64" />
<use
height="1"
width="1"
id="use4442"
xlink:href="#g4328"
y="0"
x="0"
transform="matrix(0.5,0,0,0.5,-35.699029,-4220.9125)" />
<image
sodipodi:absref="C:\Users\aportale\dev\qtcreator-super\qtcreator\src\tools\icons\designer_icon_32x32.png"
xlink:href="designer_icon_32x32.png"
width="32"
height="32"
preserveAspectRatio="none"
style="image-rendering:optimizeSpeed"
id="image4508"
x="80"
y="-6928" />
</g>
<g
transform="translate(0,-1560)"
inkscape:export-ydpi="90"
inkscape:export-xdpi="90"
id="uifile_icon_128x128@2x">
<image
sodipodi:absref="C:\Users\aportale\dev\qtcreator-super\qtcreator\src\tools\icons\GenericDocumentIcon.iconset\icon_128x128@2x.png"
xlink:href="GenericDocumentIcon.iconset\icon_128x128@2x.png"
width="256"
height="256"
id="image4101"
x="328"
y="-5576" />
<use
x="0"
y="0"
xlink:href="#g4328"
id="use4104"
transform="matrix(2,0,0,2,-72,5315.173)"
width="1920"
height="1080" />
<image
sodipodi:absref="C:\Users\aportale\dev\qtcreator-super\qtcreator\src\tools\icons\designer_icon_128x128.png"
xlink:href="designer_icon_128x128.png"
y="-5512"
x="392"
id="image6508"
style="image-rendering:optimizeSpeed"
preserveAspectRatio="none"
height="128"
width="128" />
</g>
<g
transform="translate(0,-1560)"
inkscape:export-ydpi="90"
inkscape:export-xdpi="90"
id="uifile_icon_256x256@2x">
<image
sodipodi:absref="C:\Users\aportale\dev\qtcreator-super\qtcreator\src\tools\icons\GenericDocumentIcon.iconset\icon_256x256@2x.png"
xlink:href="GenericDocumentIcon.iconset\icon_256x256@2x.png"
width="512"
height="512"
id="image4108"
x="584"
y="-5832" />
<use
x="0"
y="0"
xlink:href="#use4332"
id="use4110"
transform="matrix(2,0,0,2,-72,5320.6089)"
width="1920"
height="1080" />
<image
sodipodi:absref="C:\Users\aportale\dev\qtcreator-super\qtcreator\src\tools\icons\designer_icon_256x256.png"
xlink:href="designer_icon_256x256.png"
width="256"
height="256"
preserveAspectRatio="none"
style="image-rendering:optimizeSpeed"
id="image4497"
x="712"
y="-5704" />
</g>
<g
id="uifile_icon_512x512@2x"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90">
<image
sodipodi:absref="C:\Users\aportale\dev\qtcreator-super\qtcreator\src\tools\icons\GenericDocumentIcon.iconset\icon_512x512@2x.png"
xlink:href="GenericDocumentIcon.iconset\icon_512x512@2x.png"
y="-7905"
x="1096"
id="image4131"
height="1024"
width="1024" />
<use
height="1080"
width="1920"
transform="matrix(4,0,0,4,-216,14404.292)"
id="use5743"
xlink:href="#use4332"
y="0"
x="0" />
<image
sodipodi:absref="C:\Users\aportale\dev\qtcreator-super\qtcreator\src\tools\icons\designer_icon_512x512.png"
xlink:href="designer_icon_512x512.png"
width="512"
height="512"
preserveAspectRatio="none"
style="image-rendering:optimizeSpeed"
id="image4530"
x="1352"
y="-7649" />
</g>
<g
id="qtcreator-project_icon_16x16"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90"
transform="translate(0,-2600)">
<image
sodipodi:absref="C:\Users\aportale\dev\qtcreator-super\qtcreator\src\tools\icons\GenericDocumentIcon.iconset\icon_16x16.png"
xlink:href="GenericDocumentIcon.iconset\icon_16x16.png"
width="16"
height="16"
id="image3192-0"
x="16"
y="-5336" />
<use
transform="translate(-0.015625,0.01594865)"
x="0"
y="0"
xlink:href="#tinyqt"
id="use4802"
width="100%"
height="100%" />
</g>
<g
id="qtcreator-project_icon_32x32"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90"
transform="translate(0,-2600)">
<image
sodipodi:absref="C:\Users\aportale\dev\qtcreator-super\qtcreator\src\tools\icons\GenericDocumentIcon.iconset\icon_32x32.png"
xlink:href="GenericDocumentIcon.iconset\icon_32x32.png"
width="32"
height="32"
id="image3203-1"
x="32"
y="-5352" />
<image
sodipodi:absref="C:\Users\aportale\dev\qtcreator-super\qtcreator\src\tools\icons\qtcreator_icon_16x16.png"
xlink:href="qtcreator_icon_16x16.png"
width="16"
height="16"
preserveAspectRatio="none"
style="image-rendering:optimizeSpeed"
id="image4838"
x="40"
y="-5344" />
<text
sodipodi:linespacing="125%"
id="text3510-4"
y="-5421.4678"
x="40.865314"
style="font-style:normal;font-weight:normal;font-size:5.29114771px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none"
xml:space="preserve"
transform="scale(1.0185144,0.98182219)"><tspan
id="tspan3514-7"
y="-5421.4678"
x="40.865314"
sodipodi:role="line"
style="font-weight:bold;-inkscape-font-specification:'Sans Bold'">PRO</tspan></text>
</g>
<g
id="qtcreator-project_icon_128x128"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90"
transform="translate(0,-2600)">
<image
sodipodi:absref="C:\Users\aportale\dev\qtcreator-super\qtcreator\src\tools\icons\GenericDocumentIcon.iconset\icon_128x128.png"
xlink:href="GenericDocumentIcon.iconset\icon_128x128.png"
width="128"
height="128"
id="image3214-5"
x="200"
y="-5448" />
<image
sodipodi:absref="C:\Users\aportale\dev\qtcreator-super\qtcreator\src\tools\icons\qtcreator_icon_64x64.png"
xlink:href="qtcreator_icon_64x64.png"
width="64"
height="64"
preserveAspectRatio="none"
style="image-rendering:optimizeSpeed"
id="image4860"
x="232"
y="-5416" />
<text
sodipodi:linespacing="125%"
id="text3510-4-4"
y="-5432.687"
x="258.93604"
style="font-style:normal;font-weight:normal;font-size:12.62162399px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none"
xml:space="preserve"
transform="scale(1.0185144,0.98182216)"><tspan
id="tspan3514-7-2"
y="-5432.687"
x="258.93604"
sodipodi:role="line"
style="font-weight:bold;-inkscape-font-specification:'Sans Bold';text-align:center;text-anchor:middle">PRO</tspan></text>
</g>
<g
id="qtcreator-project_icon_256x256"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90"
transform="translate(0,-2600)">
<image
sodipodi:absref="C:\Users\aportale\dev\qtcreator-super\qtcreator\src\tools\icons\GenericDocumentIcon.iconset\icon_256x256.png"
xlink:href="GenericDocumentIcon.iconset\icon_256x256.png"
width="256"
height="256"
id="image3225-9"
x="328"
y="-5576" />
<image
sodipodi:absref="C:\Users\aportale\dev\qtcreator-super\qtcreator\src\tools\icons\qtcreator_icon_128x128.png"
xlink:href="qtcreator_icon_128x128.png"
width="128"
height="128"
preserveAspectRatio="none"
style="image-rendering:optimizeSpeed"
id="image4882"
x="392"
y="-5512" />
<text
sodipodi:linespacing="125%"
id="text3510-4-4-1"
y="-5446.8779"
x="447.18082"
style="font-style:normal;font-weight:normal;font-size:25.24324799px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none"
xml:space="preserve"
transform="scale(1.0185144,0.98182216)"><tspan
id="tspan3514-7-2-7"
y="-5446.8779"
x="447.18082"
sodipodi:role="line"
style="font-weight:bold;-inkscape-font-specification:'Sans Bold';text-align:center;text-anchor:middle">PRO</tspan></text>
</g>
<g
id="qtcreator-project_icon_512x512"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90"
transform="translate(0,-2600)">
<image
sodipodi:absref="C:\Users\aportale\dev\qtcreator-super\qtcreator\src\tools\icons\GenericDocumentIcon.iconset\icon_512x512.png"
xlink:href="GenericDocumentIcon.iconset\icon_512x512.png"
width="512"
height="512"
id="image3236-4"
x="584"
y="-5832" />
<image
sodipodi:absref="C:\Users\aportale\dev\qtcreator-super\qtcreator\src\tools\icons\qtcreator_icon_256x256.png"
xlink:href="qtcreator_icon_256x256.png"
width="256"
height="256"
preserveAspectRatio="none"
style="image-rendering:optimizeSpeed"
id="image4904"
x="712"
y="-5704" />
<text
sodipodi:linespacing="125%"
id="text3510-4-4-79"
y="-5475.2593"
x="823.67059"
style="font-style:normal;font-weight:normal;font-size:50.48649597px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none"
xml:space="preserve"
transform="scale(1.0185144,0.98182216)"><tspan
id="tspan3514-7-2-3"
y="-5475.2593"
x="823.67059"
sodipodi:role="line"
style="font-weight:bold;-inkscape-font-specification:'Sans Bold';text-align:center;text-anchor:middle">PRO</tspan></text>
</g>
<g
transform="translate(0,-3124)"
inkscape:export-ydpi="90"
inkscape:export-xdpi="90"
id="qtcreator-project_icon_16x16@2x">
<image
sodipodi:absref="C:\Users\aportale\dev\qtcreator-super\qtcreator\src\tools\icons\GenericDocumentIcon.iconset\icon_16x16@2x.png"
xlink:href="GenericDocumentIcon.iconset\icon_16x16@2x.png"
y="-5352"
x="32"
id="image4080-8"
height="32"
width="32" />
<image
sodipodi:absref="C:\Users\aportale\dev\qtcreator-super\qtcreator\src\tools\icons\qtcreator_icon_16x16.png"
xlink:href="qtcreator_icon_16x16.png"
y="-5344"
x="40"
id="image4827"
style="image-rendering:optimizeSpeed"
preserveAspectRatio="none"
height="16"
width="16" />
<use
transform="translate(0.8660239,-0.03536906)"
x="0"
y="0"
xlink:href="#text3510-4"
id="use5027"
width="100%"
height="100%" />
</g>
<g
transform="translate(0,-1564)"
id="qtcreator-project_icon_32x32@2x">
<image
sodipodi:absref="C:\Users\aportale\dev\qtcreator-super\qtcreator\src\tools\icons\GenericDocumentIcon.iconset\icon_32x32@2x.png"
xlink:href="GenericDocumentIcon.iconset\icon_32x32@2x.png"
width="64"
height="64"
id="image4120-3"
x="64"
y="-6944" />
<image
sodipodi:absref="C:\Users\aportale\dev\qtcreator-super\qtcreator\src\tools\icons\qtcreator_icon_32x32.png"
xlink:href="qtcreator_icon_32x32.png"
width="32"
height="32"
preserveAspectRatio="none"
style="image-rendering:optimizeSpeed"
id="image4849"
x="80"
y="-6928" />
<text
sodipodi:linespacing="125%"
id="text3510-4-9"
y="-6551.9634"
x="91.546913"
style="font-style:normal;font-weight:normal;font-size:7.6833334px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none"
xml:space="preserve"
transform="scale(0.9513572,1.0511299)"><tspan
id="tspan3514-7-8"
y="-6551.9634"
x="91.546913"
sodipodi:role="line"
style="font-weight:bold;-inkscape-font-specification:'Sans Bold'">PRO</tspan></text>
</g>
<g
transform="translate(0,-3124)"
inkscape:export-ydpi="90"
inkscape:export-xdpi="90"
id="qtcreator-project_icon_128x128@2x">
<image
sodipodi:absref="C:\Users\aportale\dev\qtcreator-super\qtcreator\src\tools\icons\GenericDocumentIcon.iconset\icon_128x128@2x.png"
xlink:href="GenericDocumentIcon.iconset\icon_128x128@2x.png"
y="-5576"
x="328"
id="image4101-4"
height="256"
width="256" />
<image
sodipodi:absref="C:\Users\aportale\dev\qtcreator-super\qtcreator\src\tools\icons\qtcreator_icon_128x128.png"
xlink:href="qtcreator_icon_128x128.png"
width="128"
height="128"
preserveAspectRatio="none"
style="image-rendering:optimizeSpeed"
id="image4871"
x="392"
y="-5512" />
<text
sodipodi:linespacing="125%"
id="text3510-4-4-7"
y="-5446.8779"
x="447.18088"
style="font-style:normal;font-weight:normal;font-size:25.24324799px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none"
xml:space="preserve"
transform="scale(1.0185144,0.98182216)"><tspan
id="tspan3514-7-2-5"
y="-5446.8779"
x="447.18088"
sodipodi:role="line"
style="font-weight:bold;-inkscape-font-specification:'Sans Bold';text-align:center;text-anchor:middle">PRO</tspan></text>
</g>
<g
transform="translate(0,-3124)"
inkscape:export-ydpi="90"
inkscape:export-xdpi="90"
id="qtcreator-project_icon_256x256@2x">
<image
sodipodi:absref="C:\Users\aportale\dev\qtcreator-super\qtcreator\src\tools\icons\GenericDocumentIcon.iconset\icon_256x256@2x.png"
xlink:href="GenericDocumentIcon.iconset\icon_256x256@2x.png"
y="-5832"
x="584"
id="image4108-5"
height="512"
width="512" />
<image
sodipodi:absref="C:\Users\aportale\dev\qtcreator-super\qtcreator\src\tools\icons\qtcreator_icon_256x256.png"
xlink:href="qtcreator_icon_256x256.png"
width="256"
height="256"
preserveAspectRatio="none"
style="image-rendering:optimizeSpeed"
id="image4893"
x="712"
y="-5704" />
<text
sodipodi:linespacing="125%"
id="text3510-4-4-77"
y="-5473.2202"
x="823.67059"
style="font-style:normal;font-weight:normal;font-size:50.48649597px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none"
xml:space="preserve"
transform="scale(1.0185144,0.98182216)"><tspan
id="tspan3514-7-2-6"
y="-5473.2202"
x="823.67059"
sodipodi:role="line"
style="font-weight:bold;-inkscape-font-specification:'Sans Bold';text-align:center;text-anchor:middle">PRO</tspan></text>
</g>
<g
transform="translate(0,-1564)"
id="qtcreator-project_icon_512x512@2x"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90">
<image
sodipodi:absref="C:\Users\aportale\dev\qtcreator-super\qtcreator\src\tools\icons\GenericDocumentIcon.iconset\icon_512x512@2x.png"
xlink:href="GenericDocumentIcon.iconset\icon_512x512@2x.png"
width="1024"
height="1024"
id="image4131-2"
x="1096"
y="-7905" />
<image
sodipodi:absref="C:\Users\aportale\dev\qtcreator-super\qtcreator\src\tools\icons\qtcreator_icon_512x512.png"
xlink:href="qtcreator_icon_512x512.png"
width="512"
height="512"
preserveAspectRatio="none"
style="image-rendering:optimizeSpeed"
id="image4915"
x="1352"
y="-7649" />
<text
sodipodi:linespacing="125%"
id="text3510-4-4-11"
y="-7121.9185"
x="1576.6501"
style="font-style:normal;font-weight:normal;font-size:100.97299194px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none"
xml:space="preserve"
transform="scale(1.0185144,0.98182216)"><tspan
id="tspan3514-7-2-0"
y="-7121.9185"
x="1576.6501"
sodipodi:role="line"
style="font-weight:bold;-inkscape-font-specification:'Sans Bold';text-align:center;text-anchor:middle">PRO</tspan></text>
</g>
</g>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="app-icon-images"
transform="translate(-16,11069)" />
</svg>

Before

Width:  |  Height:  |  Size: 31 KiB

View File

@@ -1,102 +0,0 @@
#!/bin/sh
# Copyright (C) 2016 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
# This script creates several application icon files by using
# Inkscape to rasterize .svg items to .png, adding shadows via
# imagemagick, creating .ico files via imagemagick and .icns
# files via iconutil (OSX only).
# optipng is required by this script
if ! hash optipng 2>/dev/null; then
echo "optipng was not found in PATH" >&2
exit 1
fi
# Imagemagick convert is required by this script
if ! hash convert 2>/dev/null; then
echo "Imagemagick convert was not found in PATH" >&2
exit 1
fi
cd `dirname $0`
applicationNames="qtcreator designer linguist assistant qdbusviewer qmlviewer"
applicationIconDimensions="16:0 24:0 32:1 48:1 64:1 128:2 256:3 512:7 1024:15"
# Creating the list of svg IDs to export
for applicationName in $applicationNames;\
do
for applicationIconDimension in $applicationIconDimensions;\
do
applicationIconSize=`echo $applicationIconDimension | awk -F: '{ print $1 }'`
iconIDs="${iconIDs} ${applicationName}_icon_${applicationIconSize}x${applicationIconSize}"
done
done
# Copying the logos for Qt Creator's sources. Without shadows!
creatorLogoDir="logo"
rm -rf $creatorLogoDir
mkdir $creatorLogoDir
for uiFileIconSize in 16 24 32 48 64 128 256 512;\
do
creatorLogoSource="qtcreator_icon_${uiFileIconSize}x${uiFileIconSize}.png"
creatorLogoTargetDir="${creatorLogoDir}/${uiFileIconSize}"
creatorLogoTarget="${creatorLogoTargetDir}/QtProject-qtcreator.png"
optipng $creatorLogoSource -o 7 -strip all
mkdir $creatorLogoTargetDir
cp $creatorLogoSource $creatorLogoTarget
done
# Adding the shadows to the .png files
for applicationName in $applicationNames;\
do
for applicationIconDimension in $applicationIconDimensions;\
do
iconSize=`echo $applicationIconDimension | awk -F: '{ print $1 }'`
shadowSize=`echo $applicationIconDimension | awk -F: '{ print $2 }'`
iconFile=${applicationName}_icon_${iconSize}x${iconSize}.png
if [ "$shadowSize" != "0" ]
then
convert -page ${iconSize}x${iconSize} ${iconFile} \( +clone -background black -shadow 25x1+0+0 \) +swap -background none -flatten ${iconFile}
convert -page ${iconSize}x${iconSize} ${iconFile} \( +clone -background black -shadow 40x${shadowSize}+0+${shadowSize} \) +swap -background none -flatten ${iconFile}
fi
done
done
# Creating the .ico files
iconSizes="256 128 64 48 32 24 16"
for applicationName in $applicationNames;\
do
icoFiles=""
for iconSize in $iconSizes;\
do
icoFiles="$icoFiles ${applicationName}_icon_${iconSize}x${iconSize}.png"
done
convert ${icoFiles} ${applicationName}.ico
done
# Optimizing the .pngs
for iconID in $iconIDs;\
do
optipng "${iconID}.png" -o 7 -strip all
done
# Preparing application .iconsets for the conversion to .icns
for applicationName in $applicationNames;\
do
inconsetName=${applicationName}.iconset
rm -rf $inconsetName
mkdir $inconsetName
cp ${applicationName}_icon_16x16.png ${inconsetName}/icon_16x16.png
cp ${applicationName}_icon_32x32.png ${inconsetName}/icon_32x32.png
cp ${applicationName}_icon_128x128.png ${inconsetName}/icon_128x128.png
cp ${applicationName}_icon_256x256.png ${inconsetName}/icon_256x256.png
cp ${applicationName}_icon_512x512.png ${inconsetName}/icon_512x512.png
cp ${applicationName}_icon_32x32.png ${inconsetName}/icon_16x16@2x.png
cp ${applicationName}_icon_64x64.png ${inconsetName}/icon_32x32@2x.png
cp ${applicationName}_icon_256x256.png ${inconsetName}/icon_128x128@2x.png
cp ${applicationName}_icon_512x512.png ${inconsetName}/icon_256x256@2x.png
cp ${applicationName}_icon_1024x1024.png ${inconsetName}/icon_512x512@2x.png
done

View File

@@ -1,32 +0,0 @@
#!/bin/sh
# Copyright (C) 2016 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
# optipng is required by this script
if ! hash optipng 2>/dev/null; then
echo "optipng was not found in PATH" >&2
exit 1
fi
cd `dirname $0`
# Adding the icons for the OSX document type icon for .ui files
for documentTypeName in "uifile" "qtcreator-project";\
do
inconsetName=${documentTypeName}.iconset
rm -rf $inconsetName
mkdir $inconsetName
for iconSize in 16 32 128 256 512;\
do
iconShortID="icon_${iconSize}x${iconSize}"
iconLongID="${documentTypeName}_${iconShortID}"
for sizeVariation in "" "@2x";\
do
iconSourcePng="${iconLongID}${sizeVariation}.png"
iconTargetPng="${inconsetName}/${iconShortID}${sizeVariation}.png"
optipng $iconSourcePng -o 7 -strip all
cp $iconSourcePng $iconTargetPng
done
done
done

View File

@@ -653,6 +653,14 @@
width="100%"
height="100%"
transform="matrix(1.5,0,0,1.5,0,-242)" />
<use
x="0"
y="0"
xlink:href="#backgroundRect"
id="backgroundRect_12"
width="100%"
height="100%"
transform="matrix(0.75,0,0,0.75,-24,97)" />
<rect
y="452"
x="-16"
@@ -2965,7 +2973,7 @@
<use
height="100%"
width="100%"
transform="matrix(-1,0,0,1,2336,0)"
transform="matrix(-1,0,0,1,2338,0)"
id="use6797"
xlink:href="#g6795"
y="0"
@@ -3147,6 +3155,68 @@
d="m 1078,478.85469 1.189,13.30208 m -4.1861,-1.62746 L 1086.5,495 m -17,0 9.272,-7.52758"
sodipodi:nodetypes="cccccc" />
</g>
<g
id="src/plugins/terminal/images/settingscategory_terminal">
<use
x="0"
y="0"
xlink:href="#backgroundRect_24"
id="use4838"
width="100%"
height="100%"
transform="translate(1115,64)"
style="display:inline;fill:none" />
<rect
style="fill:none;stroke:#000000;stroke-opacity:1.0"
id="rect2040"
width="15"
height="12"
x="1095.5"
y="481.5" />
<path
id="path5004"
style="fill:none;stroke:#000000;stroke-opacity:1.0"
d="m 1100,488.5 h 3 m -5.75,-5.25 2.25,2.25 -2.25,2.25" />
</g>
<g
id="src/plugins/copilot/images/settingscategory_copilot">
<use
x="0"
y="0"
xlink:href="#backgroundRect_24"
id="use4838-1"
width="100%"
height="100%"
transform="translate(1141,64)" />
<use
x="0"
y="0"
xlink:href="#src/plugins/copilot/images/copilot"
id="use13883"
style="display:inline"
transform="matrix(1.3271416,0,0,1.27511,-1468.1838,-246.66424)" />
</g>
<g
id="src/plugins/haskell/images/settingscategory_haskell">
<use
x="0"
y="0"
xlink:href="#backgroundRect_24"
id="use5402"
width="100%"
height="100%"
transform="translate(1166,64)" />
<path
style="fill:#000000;fill-opacity:1"
d="m 1150,482 h 2.5 l 8.67,13 h -2.5 l -3.085,-4.625 L 1152.51,495 h -2.5 l 4.335,-6.5 z"
id="path7771"
sodipodi:nodetypes="ccccccccc" />
<path
id="path10150-5"
style="fill:#606060;fill-opacity:1"
d="m 1160,491 h 2 v -2 h -3.335 z m -2,-3 h 4 v -2 h -5.335 z m -9.5,-6 4.335,6.5 -4.335,6.5 h -2.5 l 4.335,-6.5 L 1146,482 Z"
sodipodi:nodetypes="ccccccccccccccccc" />
</g>
<g
id="src/plugins/valgrind/images/kcachegrind"
transform="translate(112)">
@@ -3484,6 +3554,56 @@
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccc" />
</g>
<g
id="src/plugins/terminal/images/terminal">
<use
style="display:inline"
transform="translate(1948,132)"
height="100%"
width="100%"
id="use1987"
xlink:href="#backgroundRect"
y="0"
x="0" />
<path
id="path5004-3"
style="fill:none;stroke:#000000"
d="m 1936.25,571.25 2.25,2.25 -2.25,2.25 m -2.75,-6.25 h 8 v 8 h -8 z" />
</g>
<g
id="src/plugins/copilot/images/copilot"
transform="translate(828,88.5)"
style="display:inline">
<use
style="display:inline"
transform="translate(1137,43.5)"
height="100%"
width="100%"
id="use1987-3"
xlink:href="#backgroundRect"
y="0"
x="0" />
<g
id="g2022"
transform="translate(0,0.5)">
<path
style="fill:#000000"
d="m 1135,493 c 0,0 0,-4.5 0,-6 0,-2 -0.5,-6 -6,-6 v 6 c 5,2.5 6,6 6,6 z"
id="path5346"
sodipodi:nodetypes="ccccc" />
<path
id="path7819"
style="fill:#ffffff;stroke:none"
d="m 1130,484.5 c 0,1.23611 0.4442,2.26438 1.9319,2.54447 1.4877,0.28009 2.0454,-1.0336 2.0454,-1.97641 0,-0.94281 -0.4262,-1.72947 -1.9539,-2.12425 -1.5277,-0.39477 -2.0185,0.32008 -2.0234,1.55619 z m -1.002,-0.5 v 1 h 0.502 v -1 z m -0.01,2 c 0.012,4.5 1.012,3.5 5.0083,5.5 V 488 l -0.16,-0.63611 c -1.2971,1.18069 -3.8728,0.64494 -4.34,-1.36389 z"
sodipodi:nodetypes="zsszzccccccccccc" />
</g>
<use
x="0"
y="0"
xlink:href="#g2022"
id="use3673"
transform="matrix(-1,0,0,1,2258,0)" />
</g>
</g>
<g
inkscape:groupmode="layer"
@@ -6453,6 +6573,27 @@
d="m 347,597.33936 0.60019,0.60645 3.49128,-3.49127 3.09695,3.09695 c 0.29088,-0.96173 0.20375,-2.0863 -0.1875,-3.07155 l 3.68179,-3.68179 0.55968,0.52841 0.75761,-0.75762 -4.51473,-4.51475 -0.80193,0.80194 0.53076,0.51509 -3.60205,3.60206 c -1.04768,-0.37523 -2.22553,-0.48941 -3.20237,-0.15625 l 3.0615,3.0615 z"
style="fill:#000000" />
</g>
<g
id="src/libs/utils/images/pinned_small">
<use
style="display:inline"
x="0"
y="0"
xlink:href="#backgroundRect_12"
id="use1988"
width="100%"
height="100%"
transform="translate(397,160)" />
<g
id="g6007"
transform="rotate(45,366.14645,589.64645)">
<path
style="fill:#000000;fill-opacity:1"
d="m 369.5,585 v 1 h -1 l 0.5,3 h 1 v 1 h -2.5 l -0.2,5 h -0.6 l -0.2,-5 H 364 v -1 h 1 l 0.5,-3 h -1 v -1 z"
id="path5401"
sodipodi:nodetypes="ccccccccccccccccc" />
</g>
</g>
</g>
<g
inkscape:groupmode="layer"
@@ -9250,6 +9391,20 @@
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccccccccc" />
</g>
<g
id="src/libs/utils/images/iconoverlay_close_small">
<rect
id="rect5336"
height="16"
width="16"
y="363"
x="649"
style="fill:#ffffff" />
<path
id="path4779-7"
style="stroke:#000000;stroke-width:2"
d="m 656.5,370.5 7,7 m -7,0 7,-7" />
</g>
<g
id="src/libs/utils/images/iconoverlay_add"
transform="translate(112)">

Before

Width:  |  Height:  |  Size: 356 KiB

After

Width:  |  Height:  |  Size: 361 KiB

View File

@@ -0,0 +1,12 @@
add_qtc_executable(qtcreator_process_stub
DEPENDS Qt::Core Qt::Network
SOURCES
main.cpp
)
if (WIN32)
extend_qtc_executable(qtcreator_process_stub
DEFINES _UNICODE UNICODE _CRT_SECURE_NO_WARNINGS
)
endif()

View File

@@ -0,0 +1,572 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
#include <QCommandLineParser>
#include <QCoreApplication>
#include <QDir>
#include <QLocalSocket>
#include <QLoggingCategory>
#include <QMutex>
#include <QProcess>
#include <QSocketNotifier>
#include <QThread>
#include <QTimer>
#include <QWinEventNotifier>
#ifdef Q_OS_WIN
#include <windows.h>
#else
#include <optional>
#include <signal.h>
#include <sys/mman.h>
#include <unistd.h>
#endif
#ifdef Q_OS_LINUX
#include <sys/ptrace.h>
#endif
#include <iostream>
Q_LOGGING_CATEGORY(log, "qtc.process_stub", QtWarningMsg);
// Global variables
QCommandLineParser commandLineParser;
// The inferior command and arguments
QStringList inferiorCmdAndArguments;
// Whether to Suspend the inferior process on startup (to allow a debugger to attach)
bool debugMode = false;
// Whether to run in test mode (i.e. to start manually from the command line)
bool testMode = false;
// The control socket used to communicate with Qt Creator
QLocalSocket controlSocket;
// Environment variables to set for the inferior process
std::optional<QStringList> environmentVariables;
QProcess inferiorProcess;
int inferiorId{0};
#ifndef Q_OS_WIN
#ifdef Q_OS_DARWIN
// A memory mapped helper to retrieve the pid of the inferior process in debugMode
static int *shared_child_pid = nullptr;
#endif
using OSSocketNotifier = QSocketNotifier;
#else
Q_PROCESS_INFORMATION *win_process_information = nullptr;
using OSSocketNotifier = QWinEventNotifier;
#endif
// Helper to read a single character from stdin in testMode
OSSocketNotifier *stdInNotifier;
QThread processThread;
// Helper to create the shared memory mapped segment
void setupSharedPid();
// Parses the command line, returns a status code in case of error
std::optional<int> tryParseCommandLine(QCoreApplication &app);
// Sets the working directory, returns a status code in case of error
std::optional<int> trySetWorkingDir();
// Reads the environment variables from the env file, returns a status code in case of error
std::optional<int> readEnvFile();
void setupControlSocket();
void setupSignalHandlers();
void startProcess(const QString &program, const QStringList &arguments, const QString &workingDir);
void readKey();
void sendSelfPid();
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
setupSharedPid();
auto error = tryParseCommandLine(a);
if (error)
return error.value();
qCInfo(log) << "Debug helper started: ";
qCInfo(log) << "Socket:" << commandLineParser.value("socket");
qCInfo(log) << "Inferior:" << inferiorCmdAndArguments.join(QChar::Space);
qCInfo(log) << "Working Directory" << commandLineParser.value("workingDir");
qCInfo(log) << "Env file:" << commandLineParser.value("envfile");
qCInfo(log) << "Mode:"
<< QLatin1String(testMode ? "test | " : "")
+ QLatin1String(debugMode ? "debug" : "run");
error = trySetWorkingDir();
if (error)
return error.value();
error = readEnvFile();
if (error)
return error.value();
if (testMode) {
sendSelfPid();
setupSignalHandlers();
startProcess(inferiorCmdAndArguments[0],
inferiorCmdAndArguments.mid(1),
commandLineParser.value("workingDir"));
if (debugMode) {
qDebug() << "Press 'c' to continue or 'k' to kill, followed by 'enter'";
readKey();
}
return a.exec();
}
setupControlSocket();
return a.exec();
}
void sendMsg(const QByteArray &msg)
{
if (controlSocket.state() == QLocalSocket::ConnectedState) {
controlSocket.write(msg);
} else {
qDebug() << "MSG:" << msg;
}
}
void sendPid(int inferiorPid)
{
sendMsg(QString("pid %1\n").arg(inferiorPid).toUtf8());
}
void sendThreadId(int inferiorThreadPid)
{
sendMsg(QString("thread %1\n").arg(inferiorThreadPid).toUtf8());
}
void sendSelfPid()
{
sendMsg(QString("spid %1\n").arg(QCoreApplication::applicationPid()).toUtf8());
}
void sendExit(int exitCode)
{
sendMsg(QString("exit %1\n").arg(exitCode).toUtf8());
}
void sendCrash(int exitCode)
{
sendMsg(QString("crash %1\n").arg(exitCode).toUtf8());
}
void sendErrChDir()
{
sendMsg(QString("err:chdir %1\n").arg(errno).toUtf8());
}
void doExit(int exitCode)
{
if (controlSocket.state() == QLocalSocket::ConnectedState && controlSocket.bytesToWrite())
controlSocket.waitForBytesWritten(1000);
if (!commandLineParser.value("wait").isEmpty()) {
std::cout << commandLineParser.value("wait").toStdString();
std::cin.get();
}
exit(exitCode);
}
void onInferiorFinished(int exitCode, QProcess::ExitStatus status)
{
qCInfo(log) << "Inferior finished";
if (status == QProcess::CrashExit) {
sendCrash(exitCode);
doExit(exitCode);
} else {
sendExit(exitCode);
doExit(exitCode);
}
}
void onInferiorErrorOccurered(QProcess::ProcessError error)
{
qCInfo(log) << "Inferior error: " << error << inferiorProcess.errorString();
sendCrash(inferiorProcess.exitCode());
doExit(1);
}
void onInferiorStarted()
{
inferiorId = inferiorProcess.processId();
qCInfo(log) << "Inferior started ( pid:" << inferiorId << ")";
#ifdef Q_OS_WIN
sendThreadId(win_process_information->dwThreadId);
sendPid(inferiorId);
#elif defined(Q_OS_DARWIN)
// In debug mode we use the poll timer to send the pid.
if (!debugMode)
sendPid(inferiorId);
#else
ptrace(PTRACE_DETACH, inferiorId, 0, SIGSTOP);
sendPid(inferiorId);
#endif
}
void setupUnixInferior()
{
#ifndef Q_OS_WIN
if (debugMode) {
qCInfo(log) << "Debug mode enabled";
#ifdef Q_OS_DARWIN
// We are using raise(SIGSTOP) to stop the child process, macOS does not support ptrace(...)
inferiorProcess.setChildProcessModifier([] {
// Let the parent know our pid ...
*shared_child_pid = getpid();
// Suspend ourselves ...
raise(SIGSTOP);
});
#else
// PTRACE_TRACEME will stop execution of the child process as soon as execve is called.
inferiorProcess.setChildProcessModifier([] { ptrace(PTRACE_TRACEME, 0, 0, 0); });
#endif
}
#endif
}
void setupWindowsInferior()
{
#ifdef Q_OS_WIN
inferiorProcess.setCreateProcessArgumentsModifier([](QProcess::CreateProcessArguments *args) {
if (debugMode)
args->flags |= CREATE_SUSPENDED;
win_process_information = args->processInformation;
});
#endif
}
void setupPidPollTimer()
{
#ifdef Q_OS_DARWIN
if (!debugMode)
return;
static QTimer pollPidTimer;
pollPidTimer.setInterval(1);
pollPidTimer.setSingleShot(false);
QObject::connect(&pollPidTimer, &QTimer::timeout, &pollPidTimer, [&] {
if (*shared_child_pid) {
qCInfo(log) << "Received pid during polling:" << *shared_child_pid;
inferiorId = *shared_child_pid;
sendPid(inferiorId);
pollPidTimer.stop();
munmap(shared_child_pid, sizeof(int));
} else {
qCDebug(log) << "Waiting for inferior to start...";
}
});
pollPidTimer.start();
#endif
}
enum class Out { StdOut, StdErr };
void writeToOut(const QByteArray &data, Out out)
{
#ifdef Q_OS_WIN
static const HANDLE outHandle = GetStdHandle(STD_OUTPUT_HANDLE);
static const HANDLE errHandle = GetStdHandle(STD_ERROR_HANDLE);
WriteFile(out == Out::StdOut ? outHandle : errHandle,
data.constData(),
data.size(),
nullptr,
nullptr);
#else
auto fp = out == Out::StdOut ? stdout : stderr;
::fwrite(data.constData(), 1, data.size(), fp);
::fflush(fp);
#endif
}
void startProcess(const QString &executable, const QStringList &arguments, const QString &workingDir)
{
setupPidPollTimer();
qCInfo(log) << "Starting Inferior";
QObject::connect(&inferiorProcess,
&QProcess::finished,
QCoreApplication::instance(),
&onInferiorFinished);
QObject::connect(&inferiorProcess,
&QProcess::errorOccurred,
QCoreApplication::instance(),
&onInferiorErrorOccurered);
QObject::connect(&inferiorProcess,
&QProcess::started,
QCoreApplication::instance(),
&onInferiorStarted);
inferiorProcess.setProcessChannelMode(QProcess::ForwardedChannels);
if (!(testMode && debugMode))
inferiorProcess.setInputChannelMode(QProcess::ForwardedInputChannel);
inferiorProcess.setWorkingDirectory(workingDir);
inferiorProcess.setProgram(executable);
inferiorProcess.setArguments(arguments);
if (environmentVariables)
inferiorProcess.setEnvironment(*environmentVariables);
setupWindowsInferior();
setupUnixInferior();
inferiorProcess.start();
}
std::optional<int> readEnvFile()
{
if (!commandLineParser.isSet("envfile"))
return std::nullopt;
const QString path = commandLineParser.value("envfile");
qCInfo(log) << "Reading env file: " << path << "...";
QFile file(path);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
qCWarning(log) << "Failed to open env file: " << path;
return 1;
}
environmentVariables = QStringList{};
while (!file.atEnd()) {
QByteArray data = file.readAll();
if (!data.isEmpty()) {
for (const auto &line : data.split('\0')) {
if (!line.isEmpty())
*environmentVariables << QString::fromUtf8(line);
}
}
}
qCDebug(log) << "Env: ";
for (const auto &env : *environmentVariables)
qCDebug(log) << env;
return std::nullopt;
}
#ifndef Q_OS_WIN
void forwardSignal(int signum)
{
qCDebug(log) << "SIGTERM received, terminating inferior...";
kill(inferiorId, signum);
}
#else
static BOOL WINAPI ctrlHandler(DWORD dwCtrlType)
{
if (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT) {
qCDebug(log) << "Terminate inferior...";
inferiorProcess.terminate();
return TRUE;
}
return FALSE;
}
#endif
void setupSignalHandlers()
{
#ifdef Q_OS_WIN
SetConsoleCtrlHandler(ctrlHandler, TRUE);
#else
struct sigaction act;
memset(&act, 0, sizeof(act));
act.sa_handler = SIG_IGN;
if (sigaction(SIGTTOU, &act, NULL)) {
qCWarning(log) << "sigaction SIGTTOU: " << strerror(errno);
doExit(3);
}
act.sa_handler = forwardSignal;
if (sigaction(SIGTERM, &act, NULL)) {
qCWarning(log) << "sigaction SIGTERM: " << strerror(errno);
doExit(3);
}
if (sigaction(SIGINT, &act, NULL)) {
qCWarning(log) << "sigaction SIGINT: " << strerror(errno);
doExit(3);
}
qCDebug(log) << "Signals set up";
#endif
}
std::optional<int> tryParseCommandLine(QCoreApplication &app)
{
commandLineParser.setApplicationDescription("Debug helper for QtCreator");
commandLineParser.addHelpOption();
commandLineParser.addOption(QCommandLineOption({"d", "debug"}, "Start inferior in debug mode"));
commandLineParser.addOption(QCommandLineOption({"t", "test"}, "Don't start the control socket"));
commandLineParser.addOption(
QCommandLineOption({"s", "socket"}, "Path to the unix socket", "socket"));
commandLineParser.addOption(
QCommandLineOption({"w", "workingDir"}, "Working directory for inferior", "workingDir"));
commandLineParser.addOption(QCommandLineOption({"v", "verbose"}, "Print debug messages"));
commandLineParser.addOption(QCommandLineOption({"e", "envfile"}, "Path to env file", "envfile"));
commandLineParser.addOption(
QCommandLineOption("wait",
"Message to display to the user while waiting for key press",
"waitmessage",
"Press enter to continue ..."));
commandLineParser.process(app);
inferiorCmdAndArguments = commandLineParser.positionalArguments();
debugMode = commandLineParser.isSet("debug");
testMode = commandLineParser.isSet("test");
if (!(commandLineParser.isSet("socket") || testMode) || inferiorCmdAndArguments.isEmpty()) {
commandLineParser.showHelp(1);
return 1;
}
if (commandLineParser.isSet("verbose"))
QLoggingCategory::setFilterRules("qtc.process_stub=true");
return std::nullopt;
}
std::optional<int> trySetWorkingDir()
{
if (commandLineParser.isSet("workingDir")) {
if (!QDir::setCurrent(commandLineParser.value("workingDir"))) {
qCWarning(log) << "Failed to change working directory to: "
<< commandLineParser.value("workingDir");
sendErrChDir();
return 1;
}
}
return std::nullopt;
}
void setupSharedPid()
{
#ifdef Q_OS_DARWIN
shared_child_pid = (int *) mmap(NULL,
sizeof *shared_child_pid,
PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS,
-1,
0);
*shared_child_pid = 0;
#endif
}
void onControlSocketConnected()
{
qCInfo(log) << "Connected to control socket";
sendSelfPid();
setupSignalHandlers();
startProcess(inferiorCmdAndArguments[0],
inferiorCmdAndArguments.mid(1),
commandLineParser.value("workingDir"));
}
void resumeInferior()
{
qCDebug(log) << "Continuing inferior... (" << inferiorId << ")";
#ifdef Q_OS_WIN
ResumeThread(win_process_information->hThread);
#else
kill(inferiorId, SIGCONT);
#endif
}
void killInferior()
{
#ifdef Q_OS_WIN
inferiorProcess.kill();
#else
kill(inferiorId, SIGKILL);
#endif
}
void onControlSocketReadyRead()
{
//k = kill, i = interrupt, c = continue, s = shutdown
QByteArray data = controlSocket.readAll();
for (auto ch : data) {
qCDebug(log) << "Received:" << ch;
switch (ch) {
case 'k': {
qCDebug(log) << "Killing inferior...";
killInferior();
break;
}
#ifndef Q_OS_WIN
case 'i': {
qCDebug(log) << "Interrupting inferior...";
kill(inferiorId, SIGINT);
break;
}
#endif
case 'c': {
resumeInferior();
break;
}
case 's': {
qCDebug(log) << "Shutting down...";
doExit(0);
break;
}
}
}
}
void onControlSocketErrorOccurred(QLocalSocket::LocalSocketError socketError)
{
qCWarning(log) << "Control socket error:" << socketError;
doExit(1);
}
void setupControlSocket()
{
QObject::connect(&controlSocket, &QLocalSocket::connected, &onControlSocketConnected);
QObject::connect(&controlSocket, &QLocalSocket::readyRead, &onControlSocketReadyRead);
QObject::connect(&controlSocket, &QLocalSocket::errorOccurred, &onControlSocketErrorOccurred);
qCInfo(log) << "Waiting for connection...";
controlSocket.connectToServer(commandLineParser.value("socket"));
}
void onStdInReadyRead()
{
char ch;
std::cin >> ch;
if (ch == 'k') {
killInferior();
} else {
resumeInferior();
}
}
void readKey()
{
#ifdef Q_OS_WIN
stdInNotifier = new QWinEventNotifier(GetStdHandle(STD_INPUT_HANDLE));
#else
stdInNotifier = new QSocketNotifier(fileno(stdin), QSocketNotifier::Read);
#endif
QObject::connect(stdInNotifier, &OSSocketNotifier::activated, &onStdInReadyRead);
}

View File

@@ -0,0 +1,10 @@
import qbs 1.0
QtcTool {
name: "qtcreator_process_stub"
consoleApplication: true
Depends { name: "Qt"; submodules: ["core", "network"]; }
files: [ "main.cpp" ]
}

View File

@@ -1,7 +1,8 @@
set(LIBSDIR "${PROJECT_SOURCE_DIR}/src/libs")
set(UTILSDIR "${PROJECT_SOURCE_DIR}/src/libs/utils")
add_qtc_executable(qtcreator_processlauncher
INCLUDES "${UTILSDIR}"
INCLUDES "${LIBSDIR}"
DEPENDS Qt::Core Qt::Network
DEFINES UTILS_STATIC_LIBRARY
SOURCES

View File

@@ -2,10 +2,10 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "launchersockethandler.h"
#include "launcherlogging.h"
#include "processreaper.h"
#include "processutils.h"
#include <utils/processreaper.h>
#include <utils/processutils.h>
#include <QCoreApplication>
#include <QLocalSocket>
@@ -14,11 +14,11 @@
namespace Utils {
namespace Internal {
class Process : public ProcessHelper
class ProcessWithToken : public ProcessHelper
{
Q_OBJECT
public:
Process(quintptr token, QObject *parent = nullptr) :
ProcessWithToken(quintptr token, QObject *parent = nullptr) :
ProcessHelper(parent), m_token(token) { }
quintptr token() const { return m_token; }
@@ -41,7 +41,7 @@ LauncherSocketHandler::LauncherSocketHandler(QString serverPath, QObject *parent
LauncherSocketHandler::~LauncherSocketHandler()
{
for (auto it = m_processes.cbegin(); it != m_processes.cend(); ++it) {
Process *p = it.value();
ProcessWithToken *p = it.value();
if (p->state() != QProcess::NotRunning)
logWarn(QStringLiteral("Shutting down while process %1 is running").arg(p->program()));
ProcessReaper::reap(p);
@@ -114,7 +114,7 @@ void LauncherSocketHandler::handleSocketClosed()
qApp->quit();
}
void LauncherSocketHandler::handleProcessError(Process *process)
void LauncherSocketHandler::handleProcessError(ProcessWithToken *process)
{
// In case of FailedToStart we won't receive finished signal, so we send the error
// packet and remove the process here and now. For all other errors we should expect
@@ -124,7 +124,7 @@ void LauncherSocketHandler::handleProcessError(Process *process)
handleProcessFinished(process);
}
void LauncherSocketHandler::handleProcessStarted(Process *process)
void LauncherSocketHandler::handleProcessStarted(ProcessWithToken *process)
{
ProcessStartedPacket packet(process->token());
packet.processId = process->processId();
@@ -132,21 +132,21 @@ void LauncherSocketHandler::handleProcessStarted(Process *process)
sendPacket(packet);
}
void LauncherSocketHandler::handleReadyReadStandardOutput(Process *process)
void LauncherSocketHandler::handleReadyReadStandardOutput(ProcessWithToken *process)
{
ReadyReadStandardOutputPacket packet(process->token());
packet.standardChannel = process->readAllStandardOutput();
sendPacket(packet);
}
void LauncherSocketHandler::handleReadyReadStandardError(Process *process)
void LauncherSocketHandler::handleReadyReadStandardError(ProcessWithToken *process)
{
ReadyReadStandardErrorPacket packet(process->token());
packet.standardChannel = process->readAllStandardError();
sendPacket(packet);
}
void LauncherSocketHandler::handleProcessFinished(Process *process)
void LauncherSocketHandler::handleProcessFinished(ProcessWithToken *process)
{
ProcessDonePacket packet(process->token());
packet.exitCode = process->exitCode();
@@ -162,7 +162,7 @@ void LauncherSocketHandler::handleProcessFinished(Process *process)
void LauncherSocketHandler::handleStartPacket()
{
Process *& process = m_processes[m_packetParser.token()];
ProcessWithToken *& process = m_processes[m_packetParser.token()];
if (!process)
process = setupProcess(m_packetParser.token());
if (process->state() != QProcess::NotRunning) {
@@ -172,6 +172,7 @@ void LauncherSocketHandler::handleStartPacket()
const auto packet = LauncherPacket::extractPacket<StartProcessPacket>(
m_packetParser.token(),
m_packetParser.packetData());
process->setEnvironment(packet.env);
process->setWorkingDirectory(packet.workingDir);
// Forwarding is handled by the LauncherInterface
@@ -179,10 +180,10 @@ void LauncherSocketHandler::handleStartPacket()
? QProcess::MergedChannels : QProcess::SeparateChannels);
process->setStandardInputFile(packet.standardInputFile);
ProcessStartHandler *handler = process->processStartHandler();
handler->setWindowsSpecificStartupFlags(packet.belowNormalPriority,
packet.createConsoleOnWindows);
handler->setProcessMode(packet.processMode);
handler->setWriteData(packet.writeData);
if (packet.belowNormalPriority)
handler->setBelowNormalPriority();
handler->setNativeArguments(packet.nativeArguments);
if (packet.lowPriority)
process->setLowPriority();
@@ -196,7 +197,7 @@ void LauncherSocketHandler::handleStartPacket()
void LauncherSocketHandler::handleWritePacket()
{
Process * const process = m_processes.value(m_packetParser.token());
ProcessWithToken * const process = m_processes.value(m_packetParser.token());
if (!process) {
logWarn("Got write request for unknown process");
return;
@@ -213,7 +214,7 @@ void LauncherSocketHandler::handleWritePacket()
void LauncherSocketHandler::handleControlPacket()
{
Process * const process = m_processes.value(m_packetParser.token());
ProcessWithToken * const process = m_processes.value(m_packetParser.token());
if (!process) {
// This can happen when the process finishes on its own at about the same time the client
// sends the request. In this case the process was already deleted.
@@ -252,9 +253,9 @@ void LauncherSocketHandler::sendPacket(const LauncherPacket &packet)
m_socket->write(packet.serialize());
}
Process *LauncherSocketHandler::setupProcess(quintptr token)
ProcessWithToken *LauncherSocketHandler::setupProcess(quintptr token)
{
const auto p = new Process(token, this);
const auto p = new ProcessWithToken(token, this);
connect(p, &QProcess::started, this, [this, p] { handleProcessStarted(p); });
connect(p, &QProcess::errorOccurred, this, [this, p] { handleProcessError(p); });
connect(p, &QProcess::finished, this, [this, p] { handleProcessFinished(p); });
@@ -271,7 +272,7 @@ void LauncherSocketHandler::removeProcess(quintptr token)
if (it == m_processes.constEnd())
return;
Process *process = it.value();
ProcessWithToken *process = it.value();
m_processes.erase(it);
ProcessReaper::reap(process, process->reaperTimeout());
}
@@ -279,4 +280,4 @@ void LauncherSocketHandler::removeProcess(quintptr token)
} // namespace Internal
} // namespace Utils
#include <launchersockethandler.moc>
#include "launchersockethandler.moc"

View File

@@ -3,7 +3,7 @@
#pragma once
#include <launcherpackets.h>
#include <utils/launcherpackets.h>
#include <QByteArray>
#include <QHash>
@@ -15,7 +15,7 @@ QT_END_NAMESPACE
namespace Utils {
namespace Internal {
class Process;
class ProcessWithToken;
class LauncherSocketHandler : public QObject
{
@@ -31,11 +31,11 @@ private:
void handleSocketError();
void handleSocketClosed();
void handleProcessStarted(Process *process);
void handleProcessError(Process *process);
void handleProcessFinished(Process *process);
void handleReadyReadStandardOutput(Process *process);
void handleReadyReadStandardError(Process *process);
void handleProcessStarted(ProcessWithToken *process);
void handleProcessError(ProcessWithToken *process);
void handleProcessFinished(ProcessWithToken *process);
void handleReadyReadStandardOutput(ProcessWithToken *process);
void handleReadyReadStandardError(ProcessWithToken *process);
void handleStartPacket();
void handleWritePacket();
@@ -44,13 +44,13 @@ private:
void sendPacket(const LauncherPacket &packet);
Process *setupProcess(quintptr token);
ProcessWithToken *setupProcess(quintptr token);
void removeProcess(quintptr token);
const QString m_serverPath;
QLocalSocket * const m_socket;
PacketParser m_packetParser;
QHash<quintptr, Process *> m_processes;
QHash<quintptr, ProcessWithToken *> m_processes;
};
} // namespace Internal

View File

@@ -3,7 +3,8 @@
#include "launcherlogging.h"
#include "launchersockethandler.h"
#include "singleton.h"
#include <utils/singleton.h>
#include <QtCore/qcoreapplication.h>
#include <QtCore/qscopeguard.h>

View File

@@ -7,7 +7,7 @@ QtcTool {
Depends { name: "Qt.network" }
cpp.defines: base.concat("UTILS_STATIC_LIBRARY")
cpp.includePaths: base.concat(pathToUtils)
cpp.includePaths: base.concat(pathToLibs)
Properties {
condition: qbs.targetOS.contains("windows")
@@ -24,6 +24,7 @@ QtcTool {
"processlauncher-main.cpp",
]
property string pathToLibs: sourceDirectory + "/../../libs"
property string pathToUtils: sourceDirectory + "/../../libs/utils"
Group {
name: "protocol sources"

View File

@@ -29,8 +29,6 @@ else()
set(QT_VERSION_MAJOR ${Qt6_VERSION_MAJOR})
endif()
configure_file(../../app/app_version.h.cmakein app/app_version.h ESCAPE_QUOTES)
if (NOT TARGET QmlPuppetCommunication)
include(../../libs/qmlpuppetcommunication/QmlPuppetCommunication.cmake)
endif()
@@ -46,28 +44,32 @@ add_qtc_executable(qml2puppet
${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}
SOURCES
qml2puppet/qml2puppetmain.cpp
qml2puppet/qmlbase.h qml2puppet/appmetadata.h
qml2puppet/qmlbase.h
qml2puppet/appmetadata.cpp qml2puppet/appmetadata.h
qml2puppet/qmlpuppet.h qml2puppet/qmlpuppet.cpp qml2puppet/configcrashpad.h
qmlpuppet.qrc
PROPERTIES
OUTPUT_NAME qml2puppet-${IDE_VERSION}
)
if(TARGET qml2puppet)
if (TARGET qml2puppet)
execute_process(
COMMAND git describe --tags --always --dirty=+
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
RESULT_VARIABLE GIT_SHA_RESULT
OUTPUT_VARIABLE GIT_SHA_OUTPUT
OUTPUT_VARIABLE GIT_SHA
ERROR_VARIABLE GIT_SHA_ERROR
OUTPUT_STRIP_TRAILING_WHITESPACE
)
#if we are not a git repository use the .tag file
if(NOT GIT_SHA_OUTPUT)
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/../../../.tag GIT_SHA_OUTPUT)
if(NOT GIT_SHA)
file(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/../../../.tag GIT_SHA LIMIT_COUNT 1)
endif()
add_definitions( -D GIT_SHA=${GIT_SHA_OUTPUT} )
set(IDE_REVISION_STR ${GIT_SHA})
configure_file(../../app/app_version.h.cmakein app/app_version.h ESCAPE_QUOTES)
endif()
extend_qtc_executable(qml2puppet

View File

@@ -0,0 +1,51 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
#include "appmetadata.h"
#include <app/app_version.h>
namespace QDSMeta::AppInfo {
void printAppInfo()
{
qInfo() << Qt::endl
<< "<< QDS Meta Info >>" << Qt::endl
<< "App Info" << Qt::endl
<< " - Name :" << Core::Constants::IDE_ID << Qt::endl
<< " - Version :" << Core::Constants::IDE_VERSION_DISPLAY << Qt::endl
<< " - Author :" << Core::Constants::IDE_AUTHOR << Qt::endl
<< " - Year :" << Core::Constants::IDE_YEAR << Qt::endl
<< " - App :" << QCoreApplication::applicationName() << Qt::endl
<< "Build Info " << Qt::endl
<< " - Date :" << __DATE__ << Qt::endl
<< " - Commit :" << QStringLiteral(QDS_STRINGIFY(IDE_REVISION_STR)) << Qt::endl
<< " - Qt Version :" << QT_VERSION_STR << Qt::endl
<< "Compiler Info " << Qt::endl
#if defined(__GNUC__)
<< " - GCC :" << __GNUC__ << Qt::endl
<< " - GCC Minor :" << __GNUC_MINOR__ << Qt::endl
<< " - GCC Patch :" << __GNUC_PATCHLEVEL__ << Qt::endl
#endif
#if defined(_MSC_VER)
<< " - MSC Short :" << _MSC_VER << Qt::endl
<< " - MSC Full :" << _MSC_FULL_VER << Qt::endl
#endif
#if defined(__clang__)
<< " - clang maj :" << __clang_major__ << Qt::endl
<< " - clang min :" << __clang_minor__ << Qt::endl
<< " - clang patch :" << __clang_patchlevel__ << Qt::endl
#endif
<< "<< End Of QDS Meta Info >>" << Qt::endl;
exit(0);
}
void registerAppInfo(const QString &appName)
{
QCoreApplication::setOrganizationName(Core::Constants::IDE_AUTHOR);
QCoreApplication::setOrganizationDomain("qt-project.org");
QCoreApplication::setApplicationName(appName);
QCoreApplication::setApplicationVersion(Core::Constants::IDE_VERSION_LONG);
}
} // namespace QDSMeta::AppInfo

View File

@@ -5,8 +5,6 @@
#include <QCommandLineParser>
#include <QLoggingCategory>
#include <app/app_version.h>
// Common functions can be used in all QDS apps
namespace QDSMeta {
@@ -50,46 +48,8 @@ namespace AppInfo {
#define STRINGIFY_INTERNAL(x) #x
#define QDS_STRINGIFY(x) STRINGIFY_INTERNAL(x)
inline void printAppInfo()
{
qInfo() << Qt::endl
<< "<< QDS Meta Info >>" << Qt::endl
<< "App Info" << Qt::endl
<< " - Name :" << Core::Constants::IDE_ID << Qt::endl
<< " - Version :" << Core::Constants::IDE_VERSION_DISPLAY << Qt::endl
<< " - Author :" << Core::Constants::IDE_AUTHOR << Qt::endl
<< " - Year :" << Core::Constants::IDE_YEAR << Qt::endl
<< " - App :" << QCoreApplication::applicationName() << Qt::endl
<< "Build Info " << Qt::endl
<< " - Date :" << __DATE__ << Qt::endl
<< " - Commit :" << QStringLiteral(QDS_STRINGIFY(GIT_SHA)) << Qt::endl
<< " - Qt Version :" << QT_VERSION_STR << Qt::endl
<< "Compiler Info " << Qt::endl
#if defined(__GNUC__)
<< " - GCC :" << __GNUC__ << Qt::endl
<< " - GCC Minor :" << __GNUC_MINOR__ << Qt::endl
<< " - GCC Patch :" << __GNUC_PATCHLEVEL__ << Qt::endl
#endif
#if defined(_MSC_VER)
<< " - MSC Short :" << _MSC_VER << Qt::endl
<< " - MSC Full :" << _MSC_FULL_VER << Qt::endl
#endif
#if defined(__clang__)
<< " - clang maj :" << __clang_major__ << Qt::endl
<< " - clang min :" << __clang_minor__ << Qt::endl
<< " - clang patch :" << __clang_patchlevel__ << Qt::endl
#endif
<< "<< End Of QDS Meta Info >>" << Qt::endl;
exit(0);
}
inline void registerAppInfo(const QString &appName)
{
QCoreApplication::setOrganizationName(Core::Constants::IDE_AUTHOR);
QCoreApplication::setOrganizationDomain("qt-project.org");
QCoreApplication::setApplicationName(appName);
QCoreApplication::setApplicationVersion(Core::Constants::IDE_VERSION_LONG);
}
void printAppInfo();
void registerAppInfo(const QString &appName);
} // namespace AppInfo
} // namespace QDSMeta

View File

@@ -8,6 +8,7 @@
#include <sqlitelibraryinitializer.h>
#endif
#include <app/app_version.h>
#include <qml2puppet/iconrenderer/iconrenderer.h>
#include <qml2puppet/import3d/import3d.h>

View File

@@ -520,7 +520,7 @@ int main(int argc, char *argv[])
}
if (debug)
qDebug() << "Mode=" << optMode << " PID=" << argProcessId << " Evt=" << argWinCrashEvent;
bool ex = 0;
int ex = 0;
switch (optMode) {
case HelpMode:
usage(QCoreApplication::applicationFilePath(), errorMessage);

View File

@@ -161,7 +161,7 @@ public:
QCoreApplication::quit();
});
using namespace Utils::Layouting;
using namespace Layouting;
Column {
Row { m_iconLabel, m_introLabel, st },
@@ -205,11 +205,11 @@ CrashHandlerDialog::~CrashHandlerDialog()
bool CrashHandlerDialog::runDebuggerWhileBacktraceNotFinished()
{
// Check settings.
QSettings settings(QSettings::IniFormat, QSettings::UserScope,
QSettings settings(QSettings::IniFormat,
QSettings::UserScope,
QLatin1String(Core::Constants::IDE_SETTINGSVARIANT_STR),
QLatin1String(SettingsApplication));
if (settings.value(QLatin1String(SettingsKeySkipWarningAbortingBacktrace), false).toBool())
return true;
Utils::CheckableMessageBox::initialize(&settings);
// Ask user.
const QString title = tr("Run Debugger And Abort Collecting Backtrace?");
@@ -219,15 +219,16 @@ bool CrashHandlerDialog::runDebuggerWhileBacktraceNotFinished()
"<p>You have requested to run the debugger while collecting the backtrace was not "
"finished.</p>"
"</body></html>");
const QString checkBoxText = tr("Do not &ask again.");
bool checkBoxSetting = false;
const QDialogButtonBox::StandardButton button = Utils::CheckableMessageBox::question(this,
title, message, checkBoxText, &checkBoxSetting,
QDialogButtonBox::Yes | QDialogButtonBox::No, QDialogButtonBox::No);
if (checkBoxSetting)
settings.setValue(QLatin1String(SettingsKeySkipWarningAbortingBacktrace), checkBoxSetting);
return button == QDialogButtonBox::Yes;
const QMessageBox::StandardButton button
= Utils::CheckableMessageBox::question(this,
title,
message,
QString(SettingsKeySkipWarningAbortingBacktrace),
QMessageBox::Yes | QMessageBox::No,
QMessageBox::No);
return button == QMessageBox::Yes;
}
void CrashHandlerDialog::setToFinalState()

View File

@@ -66,33 +66,7 @@ add_qtc_library(sdktoolLib
rmqtoperation.cpp rmqtoperation.h
rmtoolchainoperation.cpp rmtoolchainoperation.h
settings.cpp settings.h
)
extend_qtc_library(sdktoolLib
SOURCES_PREFIX "${UtilsSourcesDir}"
PUBLIC_DEFINES UTILS_STATIC_LIBRARY
SOURCES
commandline.cpp commandline.h
devicefileaccess.cpp devicefileaccess.h
environment.cpp environment.h
filepath.cpp filepath.h
fileutils.cpp fileutils.h
hostosinfo.cpp hostosinfo.h
macroexpander.cpp macroexpander.h
namevaluedictionary.cpp namevaluedictionary.h
namevalueitem.cpp namevalueitem.h
persistentsettings.cpp persistentsettings.h
qtcassert.cpp qtcassert.h
savefile.cpp savefile.h
stringutils.cpp stringutils.h
)
extend_qtc_library(sdktoolLib CONDITION APPLE
SOURCES_PREFIX "${UtilsSourcesDir}"
SOURCES
fileutils_mac.mm fileutils_mac.h
PUBLIC_DEPENDS
${FWFoundation}
sdkpersistentsettings.cpp sdkpersistentsettings.h
)
if (MSVC)
@@ -120,7 +94,7 @@ add_qtc_executable(sdktool
main.cpp
)
if (MSVC AND TARGET sdktool AND Qt5_VERSION VERSION_LESS 6.0.0)
if (MSVC AND TARGET sdktool AND TARGET Qt5::Core)
# find out if Qt is static and set /MT if so
get_target_property(_input_type Qt5::Core TYPE)
if (${_input_type} STREQUAL "STATIC_LIBRARY")

View File

@@ -4,13 +4,10 @@
#include "addcmakeoperation.h"
#include "addkeysoperation.h"
#include "findkeyoperation.h"
#include "findvalueoperation.h"
#include "getoperation.h"
#include "rmkeysoperation.h"
#include "settings.h"
#ifdef WITH_TESTS
#include <QTest>
#endif
@@ -205,7 +202,7 @@ QVariantMap AddCMakeData::addCMake(const QVariantMap &map) const
data << KeyValuePair({cm, ID_KEY}, QVariant(m_id));
data << KeyValuePair({cm, DISPLAYNAME_KEY}, QVariant(m_displayName));
data << KeyValuePair({cm, AUTODETECTED_KEY}, QVariant(true));
data << KeyValuePair({cm, PATH_KEY}, Utils::FilePath::fromUserInput(m_path).toVariant());
data << KeyValuePair({cm, PATH_KEY}, QVariant(m_path));
KeyValuePairList extraList;
for (const KeyValuePair &pair : std::as_const(m_extra))
extraList << KeyValuePair(QStringList({cm}) << pair.key, pair.value);

View File

@@ -222,8 +222,7 @@ QVariantMap AddDebuggerData::addDebugger(const QVariantMap &map) const
data << KeyValuePair(QStringList() << debugger << QLatin1String(ABIS), QVariant(m_abis));
data << KeyValuePair(QStringList() << debugger << QLatin1String(ENGINE_TYPE), QVariant(m_engine));
data << KeyValuePair(QStringList() << debugger << QLatin1String(BINARY),
Utils::FilePath::fromUserInput(m_binary).toSettings());
data << KeyValuePair(QStringList() << debugger << QLatin1String(BINARY), QVariant(m_binary));
data << KeyValuePair(QStringList() << QLatin1String(COUNT), QVariant(count + 1));

View File

@@ -15,6 +15,7 @@
#include "settings.h"
#include <QDir>
#include <QLoggingCategory>
#include <QRegularExpression>
@@ -685,8 +686,7 @@ QVariantMap AddKitData::addKit(const QVariantMap &map,
if (!m_buildDevice.isNull())
data << KeyValuePair({kit, DATA, BUILDDEVICE_ID}, QVariant(m_buildDevice));
if (!m_sysRoot.isNull())
data << KeyValuePair({kit, DATA, SYSROOT},
Utils::FilePath::fromUserInput(m_sysRoot).toSettings());
data << KeyValuePair({kit, DATA, SYSROOT}, QVariant(QDir::cleanPath(m_sysRoot)));
for (auto i = m_tcs.constBegin(); i != m_tcs.constEnd(); ++i)
data << KeyValuePair({kit, DATA, TOOLCHAIN, i.key()}, QVariant(i.value()));
if (!qtId.isNull())

View File

@@ -11,19 +11,16 @@
#include "settings.h"
#include <utils/filepath.h>
#ifdef WITH_TESTS
#include <QTest>
#endif
#include <QDir>
#include <QLoggingCategory>
#include <QRegularExpression>
Q_LOGGING_CATEGORY(log, "qtc.sdktool.operations.addqt", QtWarningMsg)
using namespace Utils;
// Qt version file stuff:
const char PREFIX[] = "QtVersion.";
const char VERSION[] = "Version";
@@ -282,7 +279,7 @@ QVariantMap AddQtData::addQt(const QVariantMap &map) const
const QString qt = QString::fromLatin1(PREFIX) + QString::number(versionCount);
// Sanitize qmake path:
FilePath saneQmake = FilePath::fromUserInput(m_qmake).cleanPath();
QString saneQmake = QDir::cleanPath(m_qmake);
// insert data:
KeyValuePairList data;
@@ -291,7 +288,7 @@ QVariantMap AddQtData::addQt(const QVariantMap &map) const
data << KeyValuePair(QStringList() << qt << QLatin1String(AUTODETECTED), QVariant(true));
data << KeyValuePair(QStringList() << qt << QLatin1String(AUTODETECTION_SOURCE), QVariant(sdkId));
data << KeyValuePair(QStringList() << qt << QLatin1String(QMAKE), saneQmake.toSettings());
data << KeyValuePair(QStringList() << qt << QLatin1String(QMAKE), QVariant(saneQmake));
data << KeyValuePair(QStringList() << qt << QLatin1String(TYPE), QVariant(m_type));
data << KeyValuePair(QStringList() << qt << ABIS, QVariant(m_abis));

View File

@@ -4,13 +4,10 @@
#include "addtoolchainoperation.h"
#include "addkeysoperation.h"
#include "findkeyoperation.h"
#include "findvalueoperation.h"
#include "getoperation.h"
#include "rmkeysoperation.h"
#include "settings.h"
#include <iostream>
#ifdef WITH_TESTS
@@ -283,7 +280,7 @@ QVariantMap AddToolChainData::addToolChain(const QVariantMap &map) const
data << KeyValuePair({tc, LANGUAGE_KEY_V2}, QVariant(newLang));
data << KeyValuePair({tc, DISPLAYNAME}, QVariant(m_displayName));
data << KeyValuePair({tc, AUTODETECTED}, QVariant(true));
data << KeyValuePair({tc, PATH}, Utils::FilePath::fromUserInput(m_path).toSettings());
data << KeyValuePair({tc, PATH}, QVariant(m_path));
data << KeyValuePair({tc, TARGET_ABI}, QVariant(m_targetAbi));
QVariantList abis;
const QStringList abiStrings = m_supportedAbis.split(',');

View File

@@ -28,8 +28,10 @@
#include <app/app_version.h>
#include <iostream>
#include <memory>
#include <QCoreApplication>
#include <QDir>
#include <QLibraryInfo>
#include <QStringList>
@@ -60,10 +62,7 @@ void printHelp(const std::vector<std::unique_ptr<Operation>> &operations)
std::cout << " --sdkpath=PATH|-s PATH Set the path to the SDK files" << std::endl << std::endl;
std::cout << "Default sdkpath is \""
<< qPrintable(QDir::cleanPath(
Utils::FilePath::fromString(QCoreApplication::applicationDirPath())
.pathAppended(DATA_PATH)
.toUserOutput()))
<< qPrintable(QDir::cleanPath(QCoreApplication::applicationDirPath() + '/' + DATA_PATH))
<< "\"" << std::endl
<< std::endl;
@@ -105,7 +104,7 @@ int parseArguments(const QStringList &args, Settings *s,
// sdkpath
if (current.startsWith(QLatin1String("--sdkpath="))) {
s->sdkPath = Utils::FilePath::fromString(current.mid(10));
s->sdkPath = current.mid(10);
continue;
}
if (current == QLatin1String("-s")) {
@@ -114,7 +113,7 @@ int parseArguments(const QStringList &args, Settings *s,
printHelp(operations);
return 1;
}
s->sdkPath = Utils::FilePath::fromString(next);
s->sdkPath = next;
++i; // skip next;
continue;
}

View File

@@ -4,8 +4,7 @@
#include "operation.h"
#include "settings.h"
#include <utils/persistentsettings.h>
#include "sdkpersistentsettings.h"
#include <QDir>
#include <QFile>
@@ -65,9 +64,9 @@ QVariantMap Operation::load(const QString &file)
QVariantMap map;
// Read values from original file:
Utils::FilePath path = Settings::instance()->getPath(file);
if (path.exists()) {
Utils::PersistentSettingsReader reader;
QString path = Settings::instance()->getPath(file);
if (QFileInfo::exists(path)) {
SdkPersistentSettingsReader reader;
if (!reader.load(path))
return QVariantMap();
map = reader.restoreValues();
@@ -78,32 +77,32 @@ QVariantMap Operation::load(const QString &file)
bool Operation::save(const QVariantMap &map, const QString &file) const
{
Utils::FilePath path = Settings::instance()->getPath(file);
QString path = Settings::instance()->getPath(file);
if (path.isEmpty()) {
std::cerr << "Error: No path found for " << qPrintable(file) << "." << std::endl;
return false;
}
Utils::FilePath dirName = path.parentDir();
QDir dir(dirName.toString());
QString dirName = QDir::cleanPath(path + "/..");
QDir dir(dirName);
if (!dir.exists() && !dir.mkpath(QLatin1String("."))) {
std::cerr << "Error: Could not create directory " << qPrintable(dirName.toString())
std::cerr << "Error: Could not create directory " << qPrintable(dirName)
<< "." << std::endl;
return false;
}
Utils::PersistentSettingsWriter writer(path, QLatin1String("QtCreator")
SdkPersistentSettingsWriter writer(path, QLatin1String("QtCreator")
+ file[0].toUpper() + file.mid(1));
QString errorMessage;
if (!writer.save(map, &errorMessage)) {
std::cerr << "Error: Could not save settings " << qPrintable(path.toString())
std::cerr << "Error: Could not save settings " << qPrintable(path)
<< "." << std::endl;
return false;
}
if (!path.setPermissions(QFile::ReadOwner | QFile::WriteOwner
if (!QFile(path).setPermissions(QFile::ReadOwner | QFile::WriteOwner
| QFile::ReadGroup | QFile::ReadOther)) {
std::cerr << "Error: Could not set permissions for " << qPrintable(path.toString())
std::cerr << "Error: Could not set permissions for " << qPrintable(path)
<< "." << std::endl;
return false;
}

View File

@@ -3,8 +3,6 @@
#pragma once
#include <utils/fileutils.h>
#include <QStringList>
#include <QVariant>

View File

@@ -0,0 +1,871 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "sdkpersistentsettings.h"
#include <QCoreApplication>
#include <QDataStream>
#include <QDateTime>
#include <QDebug>
#include <QDir>
#include <QRect>
#include <QRegularExpression>
#include <QStack>
#include <QTextStream>
#include <QXmlStreamAttributes>
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
#include <QTemporaryFile>
#ifdef Q_OS_WIN
# include <windows.h>
# include <io.h>
#else
# include <unistd.h>
# include <sys/stat.h>
#endif
#define QTC_ASSERT_STRINGIFY_HELPER(x) #x
#define QTC_ASSERT_STRINGIFY(x) QTC_ASSERT_STRINGIFY_HELPER(x)
#define QTC_ASSERT_STRING(cond) writeAssertLocation(\
"\"" cond"\" in " __FILE__ ":" QTC_ASSERT_STRINGIFY(__LINE__))
// The 'do {...} while (0)' idiom is not used for the main block here to be
// able to use 'break' and 'continue' as 'actions'.
#define QTC_ASSERT(cond, action) if (Q_LIKELY(cond)) {} else { QTC_ASSERT_STRING(#cond); action; } do {} while (0)
#define QTC_CHECK(cond) if (Q_LIKELY(cond)) {} else { QTC_ASSERT_STRING(#cond); } do {} while (0)
#define QTC_GUARD(cond) ((Q_LIKELY(cond)) ? true : (QTC_ASSERT_STRING(#cond), false))
void writeAssertLocation(const char *msg)
{
const QByteArray time = QTime::currentTime().toString(Qt::ISODateWithMs).toLatin1();
static bool goBoom = qEnvironmentVariableIsSet("QTC_FATAL_ASSERTS");
if (goBoom)
qFatal("SOFT ASSERT [%s] made fatal: %s", time.data(), msg);
else
qDebug("SOFT ASSERT [%s]: %s", time.data(), msg);
}
static QFile::Permissions m_umask;
class SdkSaveFile : public QFile
{
public:
explicit SdkSaveFile(const QString &filePath) : m_finalFilePath(filePath) {}
~SdkSaveFile() override;
bool open(OpenMode flags = QIODevice::WriteOnly) override;
void rollback();
bool commit();
static void initializeUmask();
private:
const QString m_finalFilePath;
std::unique_ptr<QTemporaryFile> m_tempFile;
bool m_finalized = true;
};
SdkSaveFile::~SdkSaveFile()
{
if (!m_finalized)
rollback();
}
bool SdkSaveFile::open(OpenMode flags)
{
if (m_finalFilePath.isEmpty()) {
qWarning("Save file path empty");
return false;
}
QFile ofi(m_finalFilePath);
// Check whether the existing file is writable
if (ofi.exists() && !ofi.open(QIODevice::ReadWrite)) {
setErrorString(ofi.errorString());
return false;
}
m_tempFile = std::make_unique<QTemporaryFile>(m_finalFilePath);
m_tempFile->setAutoRemove(false);
if (!m_tempFile->open())
return false;
setFileName(m_tempFile->fileName());
if (!QFile::open(flags))
return false;
m_finalized = false; // needs clean up in the end
if (ofi.exists()) {
setPermissions(ofi.permissions()); // Ignore errors
} else {
Permissions permAll = QFile::ReadOwner
| QFile::ReadGroup
| QFile::ReadOther
| QFile::WriteOwner
| QFile::WriteGroup
| QFile::WriteOther;
// set permissions with respect to the current umask
setPermissions(permAll & ~m_umask);
}
return true;
}
void SdkSaveFile::rollback()
{
close();
if (m_tempFile)
m_tempFile->remove();
m_finalized = true;
}
static QString resolveSymlinks(QString current)
{
int links = 16;
while (links--) {
const QFileInfo info(current);
if (!info.isSymLink())
return {};
current = info.symLinkTarget();
}
return current;
}
bool SdkSaveFile::commit()
{
QTC_ASSERT(!m_finalized && m_tempFile, return false;);
m_finalized = true;
if (!flush()) {
close();
m_tempFile->remove();
return false;
}
#ifdef Q_OS_WIN
FlushFileBuffers(reinterpret_cast<HANDLE>(_get_osfhandle(handle())));
#elif _POSIX_SYNCHRONIZED_IO > 0
fdatasync(handle());
#else
fsync(handle());
#endif
close();
m_tempFile->close();
if (error() != NoError) {
m_tempFile->remove();
return false;
}
QString finalFileName = resolveSymlinks(m_finalFilePath);
#ifdef Q_OS_WIN
// Release the file lock
m_tempFile.reset();
bool result = ReplaceFile(finalFileName.toStdWString().data(),
fileName().toStdWString().data(),
nullptr, REPLACEFILE_IGNORE_MERGE_ERRORS, nullptr, nullptr);
if (!result) {
DWORD replaceErrorCode = GetLastError();
QString errorStr;
if (!QFile::exists(finalFileName)) {
// Replace failed because finalFileName does not exist, try rename.
if (!(result = rename(finalFileName)))
errorStr = errorString();
} else {
if (replaceErrorCode == ERROR_UNABLE_TO_REMOVE_REPLACED) {
// If we do not get the rights to remove the original final file we still might try
// to replace the file contents
result = MoveFileEx(fileName().toStdWString().data(),
finalFileName.toStdWString().data(),
MOVEFILE_COPY_ALLOWED
| MOVEFILE_REPLACE_EXISTING
| MOVEFILE_WRITE_THROUGH);
if (!result)
replaceErrorCode = GetLastError();
}
if (!result) {
wchar_t messageBuffer[256];
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr, replaceErrorCode,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
messageBuffer, sizeof(messageBuffer), nullptr);
errorStr = QString::fromWCharArray(messageBuffer);
}
}
if (!result) {
remove();
setErrorString(errorStr);
}
}
return result;
#else
const QString backupName = finalFileName + '~';
// Back up current file.
// If it's opened by another application, the lock follows the move.
if (QFile::exists(finalFileName)) {
// Kill old backup. Might be useful if creator crashed before removing backup.
QFile::remove(backupName);
QFile finalFile(finalFileName);
if (!finalFile.rename(backupName)) {
m_tempFile->remove();
setErrorString(finalFile.errorString());
return false;
}
}
bool result = true;
if (!m_tempFile->rename(finalFileName)) {
// The case when someone else was able to create finalFileName after we've renamed it.
// Higher level call may try to save this file again but here we do nothing and
// return false while keeping the error string from last rename call.
const QString &renameError = m_tempFile->errorString();
m_tempFile->remove();
setErrorString(renameError);
QFile::rename(backupName, finalFileName); // rollback to backup if possible ...
return false; // ... or keep the backup copy at least
}
QFile::remove(backupName);
return result;
#endif
}
void SdkSaveFile::initializeUmask()
{
#ifdef Q_OS_WIN
m_umask = QFile::WriteGroup | QFile::WriteOther;
#else
// Get the current process' file creation mask (umask)
// umask() is not thread safe so this has to be done by single threaded
// application initialization
mode_t mask = umask(0); // get current umask
umask(mask); // set it back
m_umask = ((mask & S_IRUSR) ? QFile::ReadOwner : QFlags<QFile::Permission>())
| ((mask & S_IWUSR) ? QFile::WriteOwner : QFlags<QFile::Permission>())
| ((mask & S_IXUSR) ? QFile::ExeOwner : QFlags<QFile::Permission>())
| ((mask & S_IRGRP) ? QFile::ReadGroup : QFlags<QFile::Permission>())
| ((mask & S_IWGRP) ? QFile::WriteGroup : QFlags<QFile::Permission>())
| ((mask & S_IXGRP) ? QFile::ExeGroup : QFlags<QFile::Permission>())
| ((mask & S_IROTH) ? QFile::ReadOther : QFlags<QFile::Permission>())
| ((mask & S_IWOTH) ? QFile::WriteOther : QFlags<QFile::Permission>())
| ((mask & S_IXOTH) ? QFile::ExeOther : QFlags<QFile::Permission>());
#endif
}
class SdkFileSaverBase
{
public:
SdkFileSaverBase() = default;
virtual ~SdkFileSaverBase() = default;
QString filePath() const { return m_filePath; }
bool hasError() const { return m_hasError; }
QString errorString() const { return m_errorString; }
virtual bool finalize();
bool finalize(QString *errStr);
bool write(const char *data, int len);
bool write(const QByteArray &bytes);
bool setResult(QTextStream *stream);
bool setResult(QDataStream *stream);
bool setResult(QXmlStreamWriter *stream);
bool setResult(bool ok);
QFile *file() { return m_file.get(); }
protected:
std::unique_ptr<QFile> m_file;
QString m_filePath;
QString m_errorString;
bool m_hasError = false;
};
bool SdkFileSaverBase::finalize()
{
m_file->close();
setResult(m_file->error() == QFile::NoError);
m_file.reset();
return !m_hasError;
}
bool SdkFileSaverBase::finalize(QString *errStr)
{
if (finalize())
return true;
if (errStr)
*errStr = errorString();
return false;
}
bool SdkFileSaverBase::write(const char *data, int len)
{
if (m_hasError)
return false;
return setResult(m_file->write(data, len) == len);
}
bool SdkFileSaverBase::write(const QByteArray &bytes)
{
if (m_hasError)
return false;
return setResult(m_file->write(bytes) == bytes.count());
}
bool SdkFileSaverBase::setResult(bool ok)
{
if (!ok && !m_hasError) {
if (!m_file->errorString().isEmpty()) {
m_errorString = QString("Cannot write file %1: %2")
.arg(m_filePath, m_file->errorString());
} else {
m_errorString = QString("Cannot write file %1. Disk full?")
.arg(m_filePath);
}
m_hasError = true;
}
return ok;
}
bool SdkFileSaverBase::setResult(QTextStream *stream)
{
stream->flush();
return setResult(stream->status() == QTextStream::Ok);
}
bool SdkFileSaverBase::setResult(QDataStream *stream)
{
return setResult(stream->status() == QDataStream::Ok);
}
bool SdkFileSaverBase::setResult(QXmlStreamWriter *stream)
{
return setResult(!stream->hasError());
}
// SdkFileSaver
class SdkFileSaver : public SdkFileSaverBase
{
public:
// QIODevice::WriteOnly is implicit
explicit SdkFileSaver(const QString &filePath, QIODevice::OpenMode mode = QIODevice::NotOpen);
bool finalize() override;
private:
bool m_isSafe = false;
};
SdkFileSaver::SdkFileSaver(const QString &filePath, QIODevice::OpenMode mode)
{
m_filePath = filePath;
// Workaround an assert in Qt -- and provide a useful error message, too:
#ifdef Q_OS_WIN
// Taken from: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
static const QStringList reservedNames
= {"CON", "PRN", "AUX", "NUL",
"COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9",
"LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"};
const QString fn = QFileInfo(filePath).baseName().toUpper();
if (reservedNames.contains(fn)) {
m_errorString = QString("%1: Is a reserved filename on Windows. Cannot save.").arg(filePath);
m_hasError = true;
return;
}
#endif
if (mode & (QIODevice::ReadOnly | QIODevice::Append)) {
m_file.reset(new QFile{filePath});
m_isSafe = false;
} else {
m_file.reset(new SdkSaveFile(filePath));
m_isSafe = true;
}
if (!m_file->open(QIODevice::WriteOnly | mode)) {
QString err = QFileInfo::exists(filePath) ?
QString("Cannot overwrite file %1: %2") : QString("Cannot create file %1: %2");
m_errorString = err.arg(filePath, m_file->errorString());
m_hasError = true;
}
}
bool SdkFileSaver::finalize()
{
if (!m_isSafe)
return SdkFileSaverBase::finalize();
auto sf = static_cast<SdkSaveFile *>(m_file.get());
if (m_hasError) {
if (sf->isOpen())
sf->rollback();
} else {
setResult(sf->commit());
}
m_file.reset();
return !m_hasError;
}
// Read and write rectangle in X11 resource syntax "12x12+4+3"
static QString rectangleToString(const QRect &r)
{
QString result;
QTextStream str(&result);
str << r.width() << 'x' << r.height();
if (r.x() >= 0)
str << '+';
str << r.x();
if (r.y() >= 0)
str << '+';
str << r.y();
return result;
}
static QRect stringToRectangle(const QString &v)
{
static QRegularExpression pattern("^(\\d+)x(\\d+)([-+]\\d+)([-+]\\d+)$");
Q_ASSERT(pattern.isValid());
const QRegularExpressionMatch match = pattern.match(v);
return match.hasMatch() ?
QRect(QPoint(match.captured(3).toInt(), match.captured(4).toInt()),
QSize(match.captured(1).toInt(), match.captured(2).toInt())) :
QRect();
}
/*!
\class SdkPersistentSettingsReader
\note This is aQString based fork of Utils::PersistentSettigsReader
\brief The SdkPersistentSettingsReader class reads a QVariantMap of arbitrary,
nested data structures from an XML file.
Handles all string-serializable simple types and QVariantList and QVariantMap. Example:
\code
<qtcreator>
<data>
<variable>ProjectExplorer.Project.ActiveTarget</variable>
<value type="int">0</value>
</data>
<data>
<variable>ProjectExplorer.Project.EditorSettings</variable>
<valuemap type="QVariantMap">
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
</valuemap>
</data>
\endcode
When parsing the structure, a parse stack of ParseValueStackEntry is used for each
<data> element. ParseValueStackEntry is a variant/union of:
\list
\li simple value
\li map
\li list
\endlist
You can register string-serialize functions for custom types by registering them in the Qt Meta
type system. Example:
\code
QMetaType::registerConverter(&MyCustomType::toString);
QMetaType::registerConverter<QString, MyCustomType>(&myCustomTypeFromString);
\endcode
When entering a value element ( \c <value> / \c <valuelist> , \c <valuemap> ), entry is pushed
accordingly. When leaving the element, the QVariant-value of the entry is taken off the stack
and added to the stack entry below (added to list or inserted into map). The first element
of the stack is the value of the <data> element.
\sa SdkPersistentSettingsWriter
*/
struct Context // Basic context containing element name string constants.
{
Context() {}
const QString qtCreatorElement = QString("qtcreator");
const QString dataElement = QString("data");
const QString variableElement = QString("variable");
const QString typeAttribute = QString("type");
const QString valueElement = QString("value");
const QString valueListElement = QString("valuelist");
const QString valueMapElement = QString("valuemap");
const QString keyAttribute = QString("key");
};
struct ParseValueStackEntry
{
explicit ParseValueStackEntry(QVariant::Type t = QVariant::Invalid, const QString &k = QString()) : type(t), key(k) {}
explicit ParseValueStackEntry(const QVariant &aSimpleValue, const QString &k);
QVariant value() const;
void addChild(const QString &key, const QVariant &v);
QVariant::Type type;
QString key;
QVariant simpleValue;
QVariantList listValue;
QVariantMap mapValue;
};
ParseValueStackEntry::ParseValueStackEntry(const QVariant &aSimpleValue, const QString &k) :
type(aSimpleValue.type()), key(k), simpleValue(aSimpleValue)
{
QTC_ASSERT(simpleValue.isValid(), return);
}
QVariant ParseValueStackEntry::value() const
{
switch (type) {
case QVariant::Invalid:
return QVariant();
case QVariant::Map:
return QVariant(mapValue);
case QVariant::List:
return QVariant(listValue);
default:
break;
}
return simpleValue;
}
void ParseValueStackEntry::addChild(const QString &key, const QVariant &v)
{
switch (type) {
case QVariant::Map:
mapValue.insert(key, v);
break;
case QVariant::List:
listValue.push_back(v);
break;
default:
qWarning() << "ParseValueStackEntry::Internal error adding " << key << v << " to "
<< QVariant::typeToName(type) << value();
break;
}
}
class ParseContext : public Context
{
public:
QVariantMap parse(const QString &file);
private:
enum Element { QtCreatorElement, DataElement, VariableElement,
SimpleValueElement, ListValueElement, MapValueElement, UnknownElement };
Element element(const QStringView &r) const;
static inline bool isValueElement(Element e)
{ return e == SimpleValueElement || e == ListValueElement || e == MapValueElement; }
QVariant readSimpleValue(QXmlStreamReader &r, const QXmlStreamAttributes &attributes) const;
bool handleStartElement(QXmlStreamReader &r);
bool handleEndElement(const QStringView &name);
static QString formatWarning(const QXmlStreamReader &r, const QString &message);
QStack<ParseValueStackEntry> m_valueStack;
QVariantMap m_result;
QString m_currentVariableName;
};
static QByteArray fileContents(const QString &path)
{
QFile f(path);
if (!f.exists())
return {};
if (!f.open(QFile::ReadOnly))
return {};
return f.readAll();
}
QVariantMap ParseContext::parse(const QString &file)
{
QXmlStreamReader r(fileContents(file));
m_result.clear();
m_currentVariableName.clear();
while (!r.atEnd()) {
switch (r.readNext()) {
case QXmlStreamReader::StartElement:
if (handleStartElement(r))
return m_result;
break;
case QXmlStreamReader::EndElement:
if (handleEndElement(r.name()))
return m_result;
break;
case QXmlStreamReader::Invalid:
qWarning("Error reading %s:%d: %s", qPrintable(file),
int(r.lineNumber()), qPrintable(r.errorString()));
return QVariantMap();
default:
break;
} // switch token
} // while (!r.atEnd())
return m_result;
}
bool ParseContext::handleStartElement(QXmlStreamReader &r)
{
const QStringView name = r.name();
const Element e = element(name);
if (e == VariableElement) {
m_currentVariableName = r.readElementText();
return false;
}
if (!ParseContext::isValueElement(e))
return false;
const QXmlStreamAttributes attributes = r.attributes();
const QString key = attributes.hasAttribute(keyAttribute) ?
attributes.value(keyAttribute).toString() : QString();
switch (e) {
case SimpleValueElement: {
// This reads away the end element, so, handle end element right here.
const QVariant v = readSimpleValue(r, attributes);
if (!v.isValid()) {
qWarning() << ParseContext::formatWarning(r, QString::fromLatin1("Failed to read element \"%1\".").arg(name.toString()));
return false;
}
m_valueStack.push_back(ParseValueStackEntry(v, key));
return handleEndElement(name);
}
case ListValueElement:
m_valueStack.push_back(ParseValueStackEntry(QVariant::List, key));
break;
case MapValueElement:
m_valueStack.push_back(ParseValueStackEntry(QVariant::Map, key));
break;
default:
break;
}
return false;
}
bool ParseContext::handleEndElement(const QStringView &name)
{
const Element e = element(name);
if (ParseContext::isValueElement(e)) {
QTC_ASSERT(!m_valueStack.isEmpty(), return true);
const ParseValueStackEntry top = m_valueStack.pop();
if (m_valueStack.isEmpty()) { // Last element? -> Done with that variable.
QTC_ASSERT(!m_currentVariableName.isEmpty(), return true);
m_result.insert(m_currentVariableName, top.value());
m_currentVariableName.clear();
return false;
}
m_valueStack.top().addChild(top.key, top.value());
}
return e == QtCreatorElement;
}
QString ParseContext::formatWarning(const QXmlStreamReader &r, const QString &message)
{
QString result = QLatin1String("Warning reading ");
if (const QIODevice *device = r.device())
if (const auto file = qobject_cast<const QFile *>(device))
result += QDir::toNativeSeparators(file->fileName()) + QLatin1Char(':');
result += QString::number(r.lineNumber());
result += QLatin1String(": ");
result += message;
return result;
}
ParseContext::Element ParseContext::element(const QStringView &r) const
{
if (r == valueElement)
return SimpleValueElement;
if (r == valueListElement)
return ListValueElement;
if (r == valueMapElement)
return MapValueElement;
if (r == qtCreatorElement)
return QtCreatorElement;
if (r == dataElement)
return DataElement;
if (r == variableElement)
return VariableElement;
return UnknownElement;
}
QVariant ParseContext::readSimpleValue(QXmlStreamReader &r, const QXmlStreamAttributes &attributes) const
{
// Simple value
const QStringView type = attributes.value(typeAttribute);
const QString text = r.readElementText();
if (type == QLatin1String("QChar")) { // Workaround: QTBUG-12345
QTC_ASSERT(text.size() == 1, return QVariant());
return QVariant(QChar(text.at(0)));
}
if (type == QLatin1String("QRect")) {
const QRect rectangle = stringToRectangle(text);
return rectangle.isValid() ? QVariant(rectangle) : QVariant();
}
QVariant value;
value.setValue(text);
value.convert(QMetaType::type(type.toLatin1().constData()));
return value;
}
// =================================== SdkPersistentSettingsReader
SdkPersistentSettingsReader::SdkPersistentSettingsReader() = default;
QVariant SdkPersistentSettingsReader::restoreValue(const QString &variable, const QVariant &defaultValue) const
{
if (m_valueMap.contains(variable))
return m_valueMap.value(variable);
return defaultValue;
}
QVariantMap SdkPersistentSettingsReader::restoreValues() const
{
return m_valueMap;
}
bool SdkPersistentSettingsReader::load(const QString &fileName)
{
m_valueMap.clear();
if (QFileInfo(fileName).size() == 0) // skip empty files
return false;
ParseContext ctx;
m_valueMap = ctx.parse(fileName);
return true;
}
/*!
\class SdkPersistentSettingsWriter
\note This is a fork of Utils::PersistentSettingsWriter
\brief The SdkPersistentSettingsWriter class serializes a QVariantMap of
arbitrary, nested data structures to an XML file.
\sa SdkPersistentSettingsReader
*/
static void writeVariantValue(QXmlStreamWriter &w, const Context &ctx,
const QVariant &variant, const QString &key = QString())
{
switch (static_cast<int>(variant.type())) {
case static_cast<int>(QVariant::StringList):
case static_cast<int>(QVariant::List): {
w.writeStartElement(ctx.valueListElement);
w.writeAttribute(ctx.typeAttribute, QLatin1String(QVariant::typeToName(QVariant::List)));
if (!key.isEmpty())
w.writeAttribute(ctx.keyAttribute, key);
const QList<QVariant> list = variant.toList();
for (const QVariant &var : list)
writeVariantValue(w, ctx, var);
w.writeEndElement();
break;
}
case static_cast<int>(QVariant::Map): {
w.writeStartElement(ctx.valueMapElement);
w.writeAttribute(ctx.typeAttribute, QLatin1String(QVariant::typeToName(QVariant::Map)));
if (!key.isEmpty())
w.writeAttribute(ctx.keyAttribute, key);
const QVariantMap varMap = variant.toMap();
const QVariantMap::const_iterator cend = varMap.constEnd();
for (QVariantMap::const_iterator i = varMap.constBegin(); i != cend; ++i)
writeVariantValue(w, ctx, i.value(), i.key());
w.writeEndElement();
}
break;
case static_cast<int>(QMetaType::QObjectStar): // ignore QObjects!
case static_cast<int>(QMetaType::VoidStar): // ignore void pointers!
break;
default:
w.writeStartElement(ctx.valueElement);
w.writeAttribute(ctx.typeAttribute, QLatin1String(variant.typeName()));
if (!key.isEmpty())
w.writeAttribute(ctx.keyAttribute, key);
switch (variant.type()) {
case QVariant::Rect:
w.writeCharacters(rectangleToString(variant.toRect()));
break;
default:
w.writeCharacters(variant.toString());
break;
}
w.writeEndElement();
break;
}
}
SdkPersistentSettingsWriter::SdkPersistentSettingsWriter(const QString &fileName, const QString &docType) :
m_fileName(fileName), m_docType(docType)
{ }
bool SdkPersistentSettingsWriter::save(const QVariantMap &data, QString *errorString) const
{
if (data == m_savedData)
return true;
return write(data, errorString);
}
QString SdkPersistentSettingsWriter::fileName() const
{ return m_fileName; }
//** * @brief Set contents of file (e.g. from data read from it). */
void SdkPersistentSettingsWriter::setContents(const QVariantMap &data)
{
m_savedData = data;
}
bool SdkPersistentSettingsWriter::write(const QVariantMap &data, QString *errorString) const
{
const QString parentDir = QDir::cleanPath(m_fileName + "/..");
const QFileInfo fi(parentDir);
if (!(fi.exists() && fi.isDir() && fi.isWritable())) {
bool res = QDir().mkpath(parentDir);
if (!res)
return false;
}
SdkFileSaver saver(m_fileName, QIODevice::Text);
if (!saver.hasError()) {
const Context ctx;
QXmlStreamWriter w(saver.file());
w.setAutoFormatting(true);
w.setAutoFormattingIndent(1); // Historical, used to be QDom.
w.writeStartDocument();
w.writeDTD(QLatin1String("<!DOCTYPE ") + m_docType + QLatin1Char('>'));
w.writeComment(QString::fromLatin1(" Written by %1 %2, %3. ").
arg(QCoreApplication::applicationName(),
QCoreApplication::applicationVersion(),
QDateTime::currentDateTime().toString(Qt::ISODate)));
w.writeStartElement(ctx.qtCreatorElement);
const QVariantMap::const_iterator cend = data.constEnd();
for (QVariantMap::const_iterator it = data.constBegin(); it != cend; ++it) {
w.writeStartElement(ctx.dataElement);
w.writeTextElement(ctx.variableElement, it.key());
writeVariantValue(w, ctx, it.value());
w.writeEndElement();
}
w.writeEndDocument();
saver.setResult(&w);
}
bool ok = saver.finalize();
if (ok) {
m_savedData = data;
} else if (errorString) {
m_savedData.clear();
*errorString = saver.errorString();
}
return ok;
}

View File

@@ -0,0 +1,37 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#pragma once
#include <QVariant>
class SdkPersistentSettingsReader
{
public:
SdkPersistentSettingsReader();
QVariant restoreValue(const QString &variable, const QVariant &defaultValue = QVariant()) const;
QVariantMap restoreValues() const;
bool load(const QString &fileName);
private:
QMap<QString, QVariant> m_valueMap;
};
class SdkPersistentSettingsWriter
{
public:
SdkPersistentSettingsWriter(const QString &fileName, const QString &docType);
bool save(const QVariantMap &data, QString *errorString) const;
QString fileName() const;
void setContents(const QVariantMap &data);
private:
bool write(const QVariantMap &data, QString *errorString) const;
const QString m_fileName;
const QString m_docType;
mutable QMap<QString, QVariant> m_savedData;
};

View File

@@ -85,34 +85,7 @@ QtcLibrary {
"rmtoolchainoperation.h",
"settings.cpp",
"settings.h",
"sdkpersistentsettings.cpp",
"sdkpersistentsettings.h",
]
Group {
name: "Utils"
prefix: libsDir + "/utils/"
files: [
"commandline.cpp", "commandline.h",
"devicefileaccess.cpp", "devicefileaccess.h",
"environment.cpp", "environment.h",
"filepath.cpp", "filepath.h",
"fileutils.cpp", "fileutils.h",
"hostosinfo.cpp", "hostosinfo.h",
"macroexpander.cpp", "macroexpander.h",
"namevaluedictionary.cpp", "namevaluedictionary.h",
"namevalueitem.cpp", "namevalueitem.h",
"persistentsettings.cpp", "persistentsettings.h",
"qtcassert.cpp", "qtcassert.h",
"savefile.cpp", "savefile.h",
"stringutils.cpp"
]
}
Group {
name: "Utils/macOS"
condition: qbs.targetOS.contains("macos")
prefix: libsDir + "/utils/"
files: [
"fileutils_mac.h",
"fileutils_mac.mm",
]
}
}

View File

@@ -2,11 +2,11 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "settings.h"
#include "operation.h"
#include <app/app_version.h>
#include <QCoreApplication>
#include <QDir>
static Settings *m_instance = nullptr;
@@ -21,28 +21,28 @@ Settings::Settings()
m_instance = this;
// autodetect sdk dir:
sdkPath = Utils::FilePath::fromUserInput(QCoreApplication::applicationDirPath())
.pathAppended(DATA_PATH).cleanPath()
.pathAppended(Core::Constants::IDE_SETTINGSVARIANT_STR)
.pathAppended(Core::Constants::IDE_ID);
sdkPath = QDir::cleanPath(QCoreApplication::applicationDirPath()
+ '/' + DATA_PATH
+ '/' + Core::Constants::IDE_SETTINGSVARIANT_STR
+ '/' + Core::Constants::IDE_ID);
}
Utils::FilePath Settings::getPath(const QString &file)
QString Settings::getPath(const QString &file)
{
Utils::FilePath result = sdkPath;
QString result = sdkPath;
const QString lowerFile = file.toLower();
const QStringList identical = {
"android", "cmaketools", "debuggers", "devices", "profiles", "qtversions", "toolchains", "abi"
};
if (lowerFile == "cmake")
result = result.pathAppended("cmaketools");
result += "/cmaketools";
else if (lowerFile == "kits")
result = result.pathAppended("profiles");
result += "/profiles";
else if (lowerFile == "qtversions")
result = result.pathAppended("qtversion");
result += "/qtversion";
else if (identical.contains(lowerFile))
result = result.pathAppended(lowerFile);
result += '/' + lowerFile;
else
result = result.pathAppended(file); // handle arbitrary file names not known yet
return result.stringAppended(".xml");
result += '/' + file; // handle arbitrary file names not known yet
return result += ".xml";
}

View File

@@ -3,7 +3,7 @@
#pragma once
#include <utils/fileutils.h>
#include <QString>
class Operation;
@@ -13,8 +13,8 @@ public:
Settings();
static Settings *instance();
Utils::FilePath getPath(const QString &file);
QString getPath(const QString &file);
Utils::FilePath sdkPath;
QString sdkPath;
Operation *operation = nullptr;
};

View File

@@ -7,6 +7,7 @@ Project {
"buildoutputparser/buildoutputparser.qbs",
"cplusplustools.qbs",
"disclaim/disclaim.qbs",
"process_stub/process_stub.qbs",
"processlauncher/processlauncher.qbs",
"qml2puppet/qml2puppet.qbs",
"qtcdebugger/qtcdebugger.qbs",