Merge remote-tracking branch 'origin/5.0'

Change-Id: I074571dac56b26a8a1449c29aef53b9052d8e304
This commit is contained in:
hjk
2021-07-22 14:53:39 +02:00
31 changed files with 2335 additions and 1767 deletions

View File

@@ -167,6 +167,26 @@ void registerNodeInstanceMetaObject(QObject *object, QQmlEngine *engine)
QQuickDesignerSupportProperties::registerNodeInstanceMetaObject(object, engine); QQuickDesignerSupportProperties::registerNodeInstanceMetaObject(object, engine);
} }
static bool isQuickStyleItemMetaObject(const QMetaObject *metaObject)
{
if (metaObject) {
if (metaObject->className() == QByteArrayLiteral("QQuickStyleItem"))
return true;
return isQuickStyleItemMetaObject(metaObject->superClass());
}
return false;
}
static bool isQuickStyleItem(QObject *object)
{
if (object)
return isQuickStyleItemMetaObject(object->metaObject());
return false;
}
// This is used in share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp // This is used in share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp
QObject *createPrimitive(const QString &typeName, int majorNumber, int minorNumber, QQmlContext *context) QObject *createPrimitive(const QString &typeName, int majorNumber, int minorNumber, QQmlContext *context)
{ {
@@ -357,12 +377,15 @@ void doComponentCompleteRecursive(QObject *object, NodeInstanceServer *nodeInsta
doComponentCompleteRecursive(child, nodeInstanceServer); doComponentCompleteRecursive(child, nodeInstanceServer);
} }
if (item) { if (!isQuickStyleItem(item)) {
static_cast<QQmlParserStatus*>(item)->componentComplete(); qDebug() << Q_FUNC_INFO << item;
} else { if (item) {
QQmlParserStatus *qmlParserStatus = dynamic_cast< QQmlParserStatus*>(object); static_cast<QQmlParserStatus *>(item)->componentComplete();
if (qmlParserStatus) } else {
qmlParserStatus->componentComplete(); QQmlParserStatus *qmlParserStatus = dynamic_cast<QQmlParserStatus *>(object);
if (qmlParserStatus)
qmlParserStatus->componentComplete();
}
} }
} }
} }

View File

@@ -413,7 +413,7 @@ SecondColumnLayout {
id: transparentIndicator id: transparentIndicator
icon: StudioTheme.Constants.transparent icon: StudioTheme.Constants.transparent
pixelSize: StudioTheme.Values.myIconFontSize * 1.4 pixelSize: StudioTheme.Values.myIconFontSize * 1.4
tooltip: qsTr("Transparent TODO") tooltip: qsTr("Transparent")
onClicked: { onClicked: {
colorPicker.alpha = 0 colorPicker.alpha = 0
colorPicker.updateColor() colorPicker.updateColor()
@@ -575,22 +575,29 @@ SecondColumnLayout {
onRightMouseButtonClicked: contextMenu.popup(colorPicker) onRightMouseButtonClicked: contextMenu.popup(colorPicker)
onColorInvalidated: { onColorInvalidated: {
if (colorPicker.saturation > 0.0 && colorPicker.lightness > 0.0) { switch (colorPicker.mode) {
hueSpinBox.value = colorPicker.hue case ColorPicker.Mode.HSLA:
hslHueSpinBox.value = colorPicker.hue
hslSaturationSpinBox.value = colorPicker.saturationHSL
hslLightnessSpinBox.value = colorPicker.lightness
hslAlphaSpinBox.value = colorPicker.alpha
break
case ColorPicker.Mode.RGBA:
redSpinBox.value = (colorPicker.color.r * 255)
greenSpinBox.value = (colorPicker.color.g * 255)
blueSpinBox.value = (colorPicker.color.b * 255)
rgbAlphaSpinBox.value = (colorPicker.alpha * 255)
break
case ColorPicker.Mode.HSVA:
default:
hsvHueSpinBox.value = colorPicker.hue
hsvSaturationSpinBox.value = colorPicker.saturationHSV
hsvValueSpinBox.value = colorPicker.value
hsvAlphaSpinBox.value = colorPicker.alpha
break
} }
if (colorPicker.lightness > 0.0)
saturationSpinBox.value = colorPicker.saturation
else
colorPicker.saturation = saturationSpinBox.value
lightnessSpinBox.value = colorPicker.lightness
hslaAlphaSpinBox.value = colorPicker.alpha
redSpinBox.value = (colorPicker.color.r * 255)
greenSpinBox.value = (colorPicker.color.g * 255)
blueSpinBox.value = (colorPicker.color.b * 255)
rgbaAlphaSpinBox.value = (colorPicker.alpha * 255)
} }
} }
@@ -766,29 +773,22 @@ SecondColumnLayout {
+ 4 * StudioTheme.Values.colorEditorPopupSpinBoxWidth + 4 * StudioTheme.Values.colorEditorPopupSpinBoxWidth
width: implicitWidth width: implicitWidth
actionIndicatorVisible: false actionIndicatorVisible: false
model: ["RGBA", "HSLA"] textRole: "text"
onActivated: { valueRole: "value"
switch (colorMode.currentText) { model: [
case "RGBA": { value: ColorPicker.Mode.HSVA, text: "HSVA" },
rgbaRow.visible = true { value: ColorPicker.Mode.RGBA, text: "RGBA" },
hslaRow.visible = false { value: ColorPicker.Mode.HSLA, text: "HSLA" }
break ]
case "HSLA":
rgbaRow.visible = false onActivated: colorPicker.mode = colorMode.currentValue
hslaRow.visible = true
break
default:
console.log("Unknown color mode selected.")
rgbaRow.visible = true
hslaRow.visible = false
}
}
} }
} }
RowLayout { RowLayout {
id: rgbaRow id: rgbaRow
visible: colorPicker.mode === ColorPicker.Mode.RGBA
Layout.fillWidth: true Layout.fillWidth: true
spacing: StudioTheme.Values.controlGap spacing: StudioTheme.Values.controlGap
@@ -847,7 +847,7 @@ SecondColumnLayout {
} }
DoubleSpinBox { DoubleSpinBox {
id: rgbaAlphaSpinBox id: rgbAlphaSpinBox
width: StudioTheme.Values.colorEditorPopupSpinBoxWidth width: StudioTheme.Values.colorEditorPopupSpinBoxWidth
stepSize: 1 stepSize: 1
@@ -856,7 +856,7 @@ SecondColumnLayout {
decimals: 0 decimals: 0
onValueModified: { onValueModified: {
var tmp = rgbaAlphaSpinBox.value / 255.0 var tmp = rgbAlphaSpinBox.value / 255.0
if (colorPicker.alpha !== tmp && !colorPicker.block) { if (colorPicker.alpha !== tmp && !colorPicker.block) {
colorPicker.alpha = tmp colorPicker.alpha = tmp
colorPicker.updateColor() colorPicker.updateColor()
@@ -868,49 +868,109 @@ SecondColumnLayout {
RowLayout { RowLayout {
id: hslaRow id: hslaRow
visible: false visible: colorPicker.mode === ColorPicker.Mode.HSLA
Layout.fillWidth: true Layout.fillWidth: true
spacing: StudioTheme.Values.controlGap spacing: StudioTheme.Values.controlGap
DoubleSpinBox { DoubleSpinBox {
id: hueSpinBox id: hslHueSpinBox
width: StudioTheme.Values.colorEditorPopupSpinBoxWidth width: StudioTheme.Values.colorEditorPopupSpinBoxWidth
onValueModified: { onValueModified: {
if (colorPicker.hue !== hueSpinBox.value && !colorPicker.block) { if (colorPicker.hue !== hslHueSpinBox.value
colorPicker.hue = hueSpinBox.value && !colorPicker.block) {
colorPicker.hue = hslHueSpinBox.value
colorPicker.updateColor() colorPicker.updateColor()
} }
} }
} }
DoubleSpinBox { DoubleSpinBox {
id: saturationSpinBox id: hslSaturationSpinBox
width: StudioTheme.Values.colorEditorPopupSpinBoxWidth width: StudioTheme.Values.colorEditorPopupSpinBoxWidth
onValueModified: { onValueModified: {
if (colorPicker.saturation !== saturationSpinBox.value && !colorPicker.block) { if (colorPicker.saturationHSL !== hslSaturationSpinBox.value
colorPicker.saturation = saturationSpinBox.value && !colorPicker.block) {
colorPicker.saturationHSL = hslSaturationSpinBox.value
colorPicker.updateColor() colorPicker.updateColor()
} }
} }
} }
DoubleSpinBox { DoubleSpinBox {
id: lightnessSpinBox id: hslLightnessSpinBox
width: StudioTheme.Values.colorEditorPopupSpinBoxWidth width: StudioTheme.Values.colorEditorPopupSpinBoxWidth
onValueModified: { onValueModified: {
if (colorPicker.lightness !== lightnessSpinBox.value && !colorPicker.block) { if (colorPicker.lightness !== hslLightnessSpinBox.value
colorPicker.lightness = lightnessSpinBox.value && !colorPicker.block) {
colorPicker.lightness = hslLightnessSpinBox.value
colorPicker.updateColor() colorPicker.updateColor()
} }
} }
} }
DoubleSpinBox { DoubleSpinBox {
id: hslaAlphaSpinBox id: hslAlphaSpinBox
width: StudioTheme.Values.colorEditorPopupSpinBoxWidth width: StudioTheme.Values.colorEditorPopupSpinBoxWidth
onValueModified: { onValueModified: {
if (colorPicker.alpha !== hslaAlphaSpinBox.value && !colorPicker.block) { if (colorPicker.alpha !== hslAlphaSpinBox.value
colorPicker.alpha = hslaAlphaSpinBox.value && !colorPicker.block) {
colorPicker.alpha = hslAlphaSpinBox.value
colorPicker.updateColor()
}
}
}
}
RowLayout {
id: hsvaRow
visible: colorPicker.mode === ColorPicker.Mode.HSVA
Layout.fillWidth: true
spacing: StudioTheme.Values.controlGap
DoubleSpinBox {
id: hsvHueSpinBox
width: StudioTheme.Values.colorEditorPopupSpinBoxWidth
onValueModified: {
if (colorPicker.hue !== hsvHueSpinBox.value
&& !colorPicker.block) {
colorPicker.hue = hsvHueSpinBox.value
colorPicker.updateColor()
}
}
}
DoubleSpinBox {
id: hsvSaturationSpinBox
width: StudioTheme.Values.colorEditorPopupSpinBoxWidth
onValueModified: {
if (colorPicker.saturationHSV !== hsvSaturationSpinBox.value
&& !colorPicker.block) {
colorPicker.saturationHSV = hsvSaturationSpinBox.value
colorPicker.updateColor()
}
}
}
DoubleSpinBox {
id: hsvValueSpinBox
width: StudioTheme.Values.colorEditorPopupSpinBoxWidth
onValueModified: {
if (colorPicker.value !== hsvValueSpinBox.value
&& !colorPicker.block) {
colorPicker.value = hsvValueSpinBox.value
colorPicker.updateColor()
}
}
}
DoubleSpinBox {
id: hsvAlphaSpinBox
width: StudioTheme.Values.colorEditorPopupSpinBoxWidth
onValueModified: {
if (colorPicker.alpha !== hsvAlphaSpinBox.value
&& !colorPicker.block) {
colorPicker.alpha = hsvAlphaSpinBox.value
colorPicker.updateColor() colorPicker.updateColor()
} }
} }

View File

@@ -29,15 +29,26 @@ import StudioTheme 1.0 as StudioTheme
Column { Column {
id: root id: root
enum Mode {
HSVA,
RGBA,
HSLA
}
property int mode: ColorPicker.Mode.HSVA
property color color property color color
property real alpha: 1
property real hue: 0 property real hue: 0
property real saturation: 0 property real saturationHSL: 0
property real saturationHSV: 0
property real lightness: 0 property real lightness: 0
property real value: 0
property real alpha: 1
property bool achromatic: false
property int sliderMargins: 6 property int sliderMargins: 6
property bool block: false property bool block: false
signal updateColor signal updateColor
@@ -46,30 +57,84 @@ Column {
spacing: 10 spacing: 10
onAlphaChanged: invalidateColor() onModeChanged: {
onSaturationChanged: invalidateColor() switch (root.mode) {
onLightnessChanged: invalidateColor() case ColorPicker.Mode.RGBA:
onHueChanged: invalidateColor() root.color = Qt.rgba(root.color.r, root.color.g, root.color.b, root.alpha)
onColorChanged: { break
var myAlpha = root.color.a case ColorPicker.Mode.HSLA:
rgbToHsl(root.color) root.color = Qt.hsla(root.hue, root.saturationHSL, root.lightness, root.alpha)
root.alpha = myAlpha break
case ColorPicker.Mode.HSVA:
default:
root.color = Qt.hsva(root.hue, root.saturationHSV, root.value, root.alpha)
break
}
gradientOverlay.requestPaint()
} }
onHueChanged: {
if (root.mode === ColorPicker.Mode.HSLA)
root.color.hslHue = root.hue
else
root.color.hsvHue = root.hue
}
onSaturationHSLChanged: {
root.color.hslSaturation = root.saturationHSL
invalidateColor()
}
onSaturationHSVChanged: {
root.color.hsvSaturation = root.saturationHSV
}
onLightnessChanged: {
root.color.hslLightness = root.lightness
}
onValueChanged: {
root.color.hsvValue = root.value
}
onAlphaChanged: invalidateColor()
onColorChanged: invalidateColor()
function invalidateColor() { function invalidateColor() {
if (root.block) if (root.block)
return return
root.block = true root.block = true
root.color = Qt.hsla(root.hue, if (root.color.hsvSaturation > 0.0
root.saturation, && root.color.hsvValue > 0.0
root.lightness, && root.color.hsvHue !== -1.0)
root.alpha) root.hue = root.color.hsvHue
if (root.saturation > 0.0 && root.lightness > 0.0) if (root.color.hslSaturation > 0.0
hueSlider.value = root.hue && root.color.hslLightness > 0.0
&& root.color.hslHue !== -1.0)
root.hue = root.color.hslHue
if (root.color.hslLightness !== 0.0 && root.color.hslLightness !== 1.0 && !root.achromatic)
root.saturationHSL = root.color.hslSaturation
if (root.color.hsvValue !== 0.0 && root.color.hsvValue !== 1.0 && !root.achromatic)
root.saturationHSV = root.color.hsvSaturation
root.lightness = root.color.hslLightness
root.value = root.color.hsvValue
if (root.color.hslLightness === 0.0 || root.color.hslLightness === 1.0
|| root.color.hsvValue === 0.0 || root.color.hsvValue === 1.0
|| root.color.hsvHue === -1.0 || root.color.hslHue === -1.0)
root.achromatic = true
else
root.achromatic = false
if (root.mode === ColorPicker.Mode.HSLA)
root.color = Qt.hsla(root.hue, root.saturationHSL, root.lightness, root.alpha)
else
root.color = Qt.hsva(root.hue, root.saturationHSV, root.value, root.alpha)
luminanceSlider.value = (1.0 - root.value)
hueSlider.value = root.hue
opacitySlider.value = (1.0 - root.alpha) opacitySlider.value = (1.0 - root.alpha)
root.colorInvalidated() root.colorInvalidated()
@@ -77,39 +142,51 @@ Column {
root.block = false root.block = false
} }
function rgbToHsl(color) { function drawHSVA(ctx) {
var r = color.r for (var row = 0; row < gradientOverlay.height; row++) {
var g = color.g var gradient = ctx.createLinearGradient(0, 0, gradientOverlay.width, 0)
var b = color.b var v = Math.abs(row - gradientOverlay.height) / gradientOverlay.height
var max = Math.max(r, g, b), min = Math.min(r, g, b) gradient.addColorStop(0, Qt.hsva(root.hue, 0, v, 1))
var h, s, l = (max + min) / 2 gradient.addColorStop(1, Qt.hsva(root.hue, 1, v, 1))
if (max === min) { ctx.fillStyle = gradient
h = 0 ctx.fillRect(0, row, gradientOverlay.width, 1)
s = 0
} else {
var d = max - min
s = l > 0.5 ? d / (2 - max - min) : d / (max + min)
switch (max) {
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
case g: h = (b - r) / d + 2; break;
case b: h = (r - g) / d + 4; break;
}
h /= 6
} }
}
root.block = true function drawRGBA(ctx) {
var gradient = ctx.createLinearGradient(0, 0, gradientOverlay.width, 0)
gradient.addColorStop(0.000, Qt.rgba(1, 0, 0, 1))
gradient.addColorStop(0.167, Qt.rgba(1, 1, 0, 1))
gradient.addColorStop(0.333, Qt.rgba(0, 1, 0, 1))
gradient.addColorStop(0.500, Qt.rgba(0, 1, 1, 1))
gradient.addColorStop(0.667, Qt.rgba(0, 0, 1, 1))
gradient.addColorStop(0.833, Qt.rgba(1, 0, 1, 1))
gradient.addColorStop(1.000, Qt.rgba(1, 0, 0, 1))
if (s > 0) ctx.fillStyle = gradient
root.hue = h ctx.fillRect(0, 0, gradientOverlay.width, gradientOverlay.height)
root.saturation = s gradient = ctx.createLinearGradient(0, 0, 0, gradientOverlay.height)
root.lightness = l gradient.addColorStop(0.000, Qt.rgba(0, 0, 0, 0))
gradient.addColorStop(1.000, Qt.rgba(1, 1, 1, 1))
root.block = false ctx.fillStyle = gradient
invalidateColor() ctx.fillRect(0, 0, gradientOverlay.width, gradientOverlay.height)
}
function drawHSLA(ctx) {
for (var row = 0; row < gradientOverlay.height; row++) {
var gradient = ctx.createLinearGradient(0, 0, gradientOverlay.width, 0)
var l = Math.abs(row - gradientOverlay.height) / gradientOverlay.height
gradient.addColorStop(0, Qt.hsla(root.hue, 0, l, 1))
gradient.addColorStop(1, Qt.hsla(root.hue, 1, l, 1))
ctx.fillStyle = gradient
ctx.fillRect(0, row, gradientOverlay.width, 1)
}
} }
Rectangle { Rectangle {
@@ -133,26 +210,30 @@ Column {
Canvas { Canvas {
id: gradientOverlay id: gradientOverlay
property real hue: root.hue
anchors.fill: parent anchors.fill: parent
opacity: root.alpha opacity: root.color.a
Connections {
target: root
function onHueChanged() { gradientOverlay.requestPaint() }
}
onHueChanged: requestPaint()
onPaint: { onPaint: {
var ctx = gradientOverlay.getContext('2d') var ctx = gradientOverlay.getContext('2d')
ctx.save() ctx.save()
ctx.clearRect(0, 0, gradientOverlay.width, gradientOverlay.height) ctx.clearRect(0, 0, gradientOverlay.width, gradientOverlay.height)
for (var row = 0; row < gradientOverlay.height; row++) { switch (root.mode) {
var gradient = ctx.createLinearGradient(0, 0, gradientOverlay.width,0) case ColorPicker.Mode.RGBA:
var l = Math.abs(row - gradientOverlay.height) / gradientOverlay.height root.drawRGBA(ctx)
break
gradient.addColorStop(0, Qt.hsla(gradientOverlay.hue, 0, l, 1)) case ColorPicker.Mode.HSLA:
gradient.addColorStop(1, Qt.hsla(gradientOverlay.hue, 1, l, 1)) root.drawHSLA(ctx)
break
ctx.fillStyle = gradient case ColorPicker.Mode.HSVA:
ctx.fillRect(0, row, gradientOverlay.width, 1) default:
root.drawHSVA(ctx)
break
} }
ctx.restore() ctx.restore()
@@ -162,25 +243,41 @@ Column {
Canvas { Canvas {
id: pickerCross id: pickerCross
property real cavnasSaturation: root.saturation
property real canvasLightness: root.lightness
property color strokeStyle: "lightGray" property color strokeStyle: "lightGray"
opacity: 0.8 opacity: 0.8
anchors.fill: parent anchors.fill: parent
antialiasing: true antialiasing: true
onCavnasSaturationChanged: requestPaint(); Connections {
onCanvasLightnessChanged: requestPaint(); target: root
function onColorInvalidated() { pickerCross.requestPaint() }
function onColorChanged() { pickerCross.requestPaint() }
function onModeChanged() { pickerCross.requestPaint() }
}
onPaint: { onPaint: {
var ctx = pickerCross.getContext('2d') var ctx = pickerCross.getContext('2d')
ctx.save() ctx.save()
ctx.clearRect(0, 0, pickerCross.width, pickerCross.height) ctx.clearRect(0, 0, pickerCross.width, pickerCross.height)
var yy = pickerCross.height -root.lightness * pickerCross.height var yy, xx = 0
var xx = root.saturation * pickerCross.width
switch (root.mode) {
case ColorPicker.Mode.RGBA:
yy = pickerCross.height - root.saturationHSV * pickerCross.height
xx = root.hue * pickerCross.width
break
case ColorPicker.Mode.HSLA:
yy = pickerCross.height - root.lightness * pickerCross.height
xx = root.saturationHSL * pickerCross.width
break
case ColorPicker.Mode.HSVA:
default:
yy = pickerCross.height - root.value * pickerCross.height
xx = root.saturationHSV * pickerCross.width
break
}
ctx.strokeStyle = pickerCross.strokeStyle ctx.strokeStyle = pickerCross.strokeStyle
ctx.lineWidth = 1 ctx.lineWidth = 1
@@ -200,24 +297,37 @@ Column {
} }
MouseArea { MouseArea {
id: mapMouseArea id: mouseArea
anchors.fill: parent anchors.fill: parent
preventStealing: true preventStealing: true
acceptedButtons: Qt.LeftButton | Qt.RightButton acceptedButtons: Qt.LeftButton | Qt.RightButton
onPositionChanged: function(mouse) { onPositionChanged: function(mouse) {
if (pressed && mouse.buttons === Qt.LeftButton) { if (mouseArea.pressed && mouse.buttons === Qt.LeftButton) {
var xx = Math.max(0, Math.min(mouse.x, parent.width)) var xx = Math.max(0, Math.min(mouse.x, parent.width))
var yy = Math.max(0, Math.min(mouse.y, parent.height)) var yy = Math.max(0, Math.min(mouse.y, parent.height))
root.lightness = 1.0 - yy / parent.height switch (root.mode) {
root.saturation = xx / parent.width case ColorPicker.Mode.RGBA:
root.saturationHSV = 1.0 - yy / parent.height
root.hue = xx / parent.width
break
case ColorPicker.Mode.HSLA:
root.saturationHSL = xx / parent.width
root.lightness = 1.0 - yy / parent.height
break
case ColorPicker.Mode.HSVA:
default:
root.saturationHSV = xx / parent.width
root.value = 1.0 - yy / parent.height
break
}
} }
} }
onPressed: function(mouse) { onPressed: function(mouse) {
if (mouse.button === Qt.LeftButton) if (mouse.button === Qt.LeftButton)
positionChanged(mouse) mouseArea.positionChanged(mouse)
} }
onReleased: function(mouse) { onReleased: function(mouse) {
if (mouse.button === Qt.LeftButton) if (mouse.button === Qt.LeftButton)
@@ -233,10 +343,23 @@ Column {
HueSlider { HueSlider {
id: hueSlider id: hueSlider
visible: root.mode !== ColorPicker.Mode.RGBA
width: parent.width width: parent.width
onValueChanged: { onValueChanged: {
if (root.hue !== value) if (root.hue !== hueSlider.value)
root.hue = value root.hue = hueSlider.value
}
onClicked: root.updateColor()
}
LuminanceSlider {
id: luminanceSlider
visible: root.mode === ColorPicker.Mode.RGBA
width: parent.width
color: Qt.hsva(root.hue, root.color.hsvSaturation, 1, 1)
onValueChanged: {
if (root.value !== luminanceSlider.value)
root.value = (1.0 - luminanceSlider.value)
} }
onClicked: root.updateColor() onClicked: root.updateColor()
} }
@@ -246,8 +369,8 @@ Column {
width: parent.width width: parent.width
color: Qt.rgba(root.color.r, root.color.g, root.color.b, 1) color: Qt.rgba(root.color.r, root.color.g, root.color.b, 1)
onValueChanged: { onValueChanged: {
if (root.alpha !== value) if (root.alpha !== opacitySlider.value)
root.alpha = (1.0 - value) root.alpha = (1.0 - opacitySlider.value)
} }
onClicked: root.updateColor() onClicked: root.updateColor()
} }

View File

@@ -0,0 +1,121 @@
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
import QtQuick 2.15
import StudioTheme 1.0 as StudioTheme
Item {
id: root
property real value: 1
property real minimum: 0
property real maximum: 1
property bool pressed: mouseArea.pressed
property bool integer: false
property color color
signal clicked
height: StudioTheme.Values.hueSliderHeight
function updatePos() {
if (root.maximum > root.minimum) {
var pos = (track.width - handle.width) * (root.value - root.minimum) / (root.maximum - root.minimum)
return Math.min(Math.max(pos, 0), track.width - handle.width)
} else {
return 0
}
}
Item {
id: track
width: parent.width
height: parent.height
Image {
id: checkerboard
anchors.fill: parent
source: "images/checkers.png"
fillMode: Image.Tile
}
Rectangle {
anchors.fill: parent
border.color: StudioTheme.Values.themeControlOutline
border.width: StudioTheme.Values.border
gradient: Gradient {
orientation: Gradient.Horizontal
GradientStop { position: 0.000; color: root.color }
GradientStop { position: 1.000; color: "black" }
}
}
Rectangle {
id: handle
width: StudioTheme.Values.hueSliderHandleWidth
height: track.height - 4
anchors.verticalCenter: parent.verticalCenter
smooth: true
color: "transparent"
radius: 2
border.color: "black"
border.width: 1
x: root.updatePos()
y: 2
z: 1
Rectangle {
anchors.fill: parent
anchors.margins: 1
color: "transparent"
radius: 1
border.color: "white"
border.width: 1
}
}
MouseArea {
id: mouseArea
anchors.fill: parent
preventStealing: true
function calculateValue() {
var handleX = Math.max(0, Math.min(mouseArea.mouseX, mouseArea.width))
var realValue = (root.maximum - root.minimum) * handleX / mouseArea.width + root.minimum
root.value = root.integer ? Math.round(realValue) : realValue
}
onPressed: calculateValue()
onReleased: root.clicked()
onPositionChanged: {
if (pressed)
calculateValue()
}
}
}
}

View File

@@ -45,6 +45,7 @@ Label 2.0 Label.qml
LineEdit 2.0 LineEdit.qml LineEdit 2.0 LineEdit.qml
LinkIndicator2D 2.0 LinkIndicator2D.qml LinkIndicator2D 2.0 LinkIndicator2D.qml
ListViewComboBox 2.0 ListViewComboBox.qml ListViewComboBox 2.0 ListViewComboBox.qml
LuminanceSlider 2.0 LuminanceSlider.qml
MarginSection 2.0 MarginSection.qml MarginSection 2.0 MarginSection.qml
MultiIconLabel 2.0 MultiIconLabel.qml MultiIconLabel 2.0 MultiIconLabel.qml
OpacitySlider 2.0 OpacitySlider.qml OpacitySlider 2.0 OpacitySlider.qml

View File

@@ -52,6 +52,7 @@ add_qtc_library(Utils
filecrumblabel.cpp filecrumblabel.h filecrumblabel.cpp filecrumblabel.h
fileinprojectfinder.cpp fileinprojectfinder.h fileinprojectfinder.cpp fileinprojectfinder.h
filenamevalidatinglineedit.cpp filenamevalidatinglineedit.h filenamevalidatinglineedit.cpp filenamevalidatinglineedit.h
filepath.cpp filepath.h
filesearch.cpp filesearch.h filesearch.cpp filesearch.h
filesystemwatcher.cpp filesystemwatcher.h filesystemwatcher.cpp filesystemwatcher.h
fileutils.cpp fileutils.h fileutils.cpp fileutils.h

1295
src/libs/utils/filepath.cpp Normal file

File diff suppressed because it is too large Load Diff

193
src/libs/utils/filepath.h Normal file
View File

@@ -0,0 +1,193 @@
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "utils_global.h"
#include "hostosinfo.h"
#include <QDir>
#include <QMetaType>
#include <functional>
#include <memory>
QT_BEGIN_NAMESPACE
class QDateTime;
class QDebug;
class QFileInfo;
class QUrl;
QT_END_NAMESPACE
class tst_fileutils; // This becomes a friend of Utils::FilePath for testing private methods.
namespace Utils {
class Environment;
class QTCREATOR_UTILS_EXPORT FilePath
{
public:
FilePath();
static FilePath fromString(const QString &filepath);
static FilePath fromFileInfo(const QFileInfo &info);
static FilePath fromStringWithExtension(const QString &filepath, const QString &defaultExtension);
static FilePath fromUserInput(const QString &filepath);
static FilePath fromUtf8(const char *filepath, int filepathSize = -1);
static FilePath fromVariant(const QVariant &variant);
QString toString() const;
FilePath onDevice(const FilePath &deviceTemplate) const;
FilePath withNewPath(const QString &newPath) const;
QFileInfo toFileInfo() const;
QVariant toVariant() const;
QDir toDir() const;
QString toUserOutput() const;
QString shortNativePath() const;
QString fileName() const;
QString fileNameWithPathComponents(int pathComponents) const;
QString baseName() const;
QString completeBaseName() const;
QString suffix() const;
QString completeSuffix() const;
QString scheme() const { return m_scheme; }
void setScheme(const QString &scheme);
QString host() const { return m_host; }
void setHost(const QString &host);
QString path() const { return m_data; }
void setPath(const QString &path) { m_data = path; }
bool needsDevice() const;
bool exists() const;
bool isWritablePath() const { return isWritableDir(); } // Remove.
bool isWritableDir() const;
bool isWritableFile() const;
bool ensureWritableDir() const;
bool ensureExistingFile() const;
bool isExecutableFile() const;
bool isReadableFile() const;
bool isReadableDir() const;
bool isRelativePath() const;
bool isAbsolutePath() const { return !isRelativePath(); }
bool isFile() const;
bool isDir() const;
bool createDir() const;
QList<FilePath> dirEntries(const QStringList &nameFilters,
QDir::Filters filters,
QDir::SortFlags sort = QDir::NoSort) const;
QList<FilePath> dirEntries(QDir::Filters filters) const;
QByteArray fileContents(qint64 maxSize = -1, qint64 offset = 0) const;
bool writeFileContents(const QByteArray &data) const;
FilePath parentDir() const;
FilePath absolutePath() const;
FilePath absoluteFilePath() const;
FilePath absoluteFilePath(const FilePath &tail) const;
FilePath absoluteFromRelativePath(const FilePath &anchor) const;
bool operator==(const FilePath &other) const;
bool operator!=(const FilePath &other) const;
bool operator<(const FilePath &other) const;
bool operator<=(const FilePath &other) const;
bool operator>(const FilePath &other) const;
bool operator>=(const FilePath &other) const;
FilePath operator+(const QString &s) const;
bool isChildOf(const FilePath &s) const;
bool isChildOf(const QDir &dir) const;
bool startsWith(const QString &s) const;
bool endsWith(const QString &s) const;
bool isNewerThan(const QDateTime &timeStamp) const;
QDateTime lastModified() const;
QFile::Permissions permissions() const;
OsType osType() const;
bool removeFile() const;
bool removeRecursively(QString *error = nullptr) const;
bool copyFile(const FilePath &target) const;
bool renameFile(const FilePath &target) const;
Qt::CaseSensitivity caseSensitivity() const;
FilePath relativeChildPath(const FilePath &parent) const;
FilePath relativePath(const FilePath &anchor) const;
FilePath pathAppended(const QString &str) const;
FilePath stringAppended(const QString &str) const;
FilePath resolvePath(const QString &fileName) const;
FilePath cleanPath() const;
FilePath canonicalPath() const;
FilePath symLinkTarget() const;
FilePath resolveSymlinks() const;
FilePath withExecutableSuffix() const;
FilePath operator/(const QString &str) const;
void clear();
bool isEmpty() const;
uint hash(uint seed) const;
// NOTE: Most FilePath operations on FilePath created from URL currently
// do not work. Among the working are .toVariant() and .toUrl().
static FilePath fromUrl(const QUrl &url);
QUrl toUrl() const;
FilePath searchOnDevice(const QList<FilePath> &dirs) const;
Environment deviceEnvironment() const;
static QString formatFilePaths(const QList<FilePath> &files, const QString &separator);
static void removeDuplicates(QList<FilePath> &files);
static void sort(QList<FilePath> &files);
private:
friend class ::tst_fileutils;
static QString calcRelativePath(const QString &absolutePath, const QString &absoluteAnchorPath);
QString m_scheme;
QString m_host;
QString m_data;
};
using FilePaths = QList<FilePath>;
} // namespace Utils
QT_BEGIN_NAMESPACE
QTCREATOR_UTILS_EXPORT QDebug operator<<(QDebug dbg, const Utils::FilePath &c);
QT_END_NAMESPACE
Q_DECLARE_METATYPE(Utils::FilePath)

File diff suppressed because it is too large Load Diff

View File

@@ -27,6 +27,7 @@
#include "utils_global.h" #include "utils_global.h"
#include "filepath.h"
#include "hostosinfo.h" #include "hostosinfo.h"
#include <QCoreApplication> #include <QCoreApplication>
@@ -40,33 +41,17 @@
#include <functional> #include <functional>
#include <memory> #include <memory>
namespace Utils {
class Environment;
class FilePath;
} // Utils
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QDataStream; class QDataStream;
class QDateTime;
class QDir;
class QFile;
class QFileInfo;
class QTemporaryFile;
class QTextStream; class QTextStream;
class QWidget; class QWidget;
QTCREATOR_UTILS_EXPORT QDebug operator<<(QDebug dbg, const Utils::FilePath &c);
// for withNtfsPermissions // for withNtfsPermissions
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
extern Q_CORE_EXPORT int qt_ntfs_permission_lookup; extern Q_CORE_EXPORT int qt_ntfs_permission_lookup;
#endif #endif
QT_END_NAMESPACE QT_END_NAMESPACE
// tst_fileutils becomes a friend of Utils::FilePath for testing private method
class tst_fileutils;
namespace Utils { namespace Utils {
class DeviceFileHooks class DeviceFileHooks
@@ -99,152 +84,6 @@ public:
std::function<Environment(const FilePath &)> environment; std::function<Environment(const FilePath &)> environment;
}; };
class QTCREATOR_UTILS_EXPORT FilePath
{
public:
FilePath();
static FilePath fromString(const QString &filepath);
static FilePath fromFileInfo(const QFileInfo &info);
static FilePath fromStringWithExtension(const QString &filepath, const QString &defaultExtension);
static FilePath fromUserInput(const QString &filepath);
static FilePath fromUtf8(const char *filepath, int filepathSize = -1);
static FilePath fromVariant(const QVariant &variant);
QString toString() const;
FilePath onDevice(const FilePath &deviceTemplate) const;
FilePath withNewPath(const QString &newPath) const;
QFileInfo toFileInfo() const;
QVariant toVariant() const;
QDir toDir() const;
QString toUserOutput() const;
QString shortNativePath() const;
QString fileName() const;
QString fileNameWithPathComponents(int pathComponents) const;
QString baseName() const;
QString completeBaseName() const;
QString suffix() const;
QString completeSuffix() const;
QString scheme() const { return m_scheme; }
void setScheme(const QString &scheme);
QString host() const { return m_host; }
void setHost(const QString &host);
QString path() const { return m_data; }
void setPath(const QString &path) { m_data = path; }
bool needsDevice() const;
bool exists() const;
bool isWritablePath() const { return isWritableDir(); } // Remove.
bool isWritableDir() const;
bool isWritableFile() const;
bool ensureWritableDir() const;
bool ensureExistingFile() const;
bool isExecutableFile() const;
bool isReadableFile() const;
bool isReadableDir() const;
bool isRelativePath() const;
bool isAbsolutePath() const { return !isRelativePath(); }
bool isFile() const;
bool isDir() const;
bool createDir() const;
QList<FilePath> dirEntries(const QStringList &nameFilters,
QDir::Filters filters,
QDir::SortFlags sort = QDir::NoSort) const;
QList<FilePath> dirEntries(QDir::Filters filters) const;
QByteArray fileContents(qint64 maxSize = -1, qint64 offset = 0) const;
bool writeFileContents(const QByteArray &data) const;
FilePath parentDir() const;
FilePath absolutePath() const;
FilePath absoluteFilePath() const;
FilePath absoluteFilePath(const FilePath &tail) const;
FilePath absoluteFromRelativePath(const FilePath &anchor) const;
bool operator==(const FilePath &other) const;
bool operator!=(const FilePath &other) const;
bool operator<(const FilePath &other) const;
bool operator<=(const FilePath &other) const;
bool operator>(const FilePath &other) const;
bool operator>=(const FilePath &other) const;
FilePath operator+(const QString &s) const;
bool isChildOf(const FilePath &s) const;
bool isChildOf(const QDir &dir) const;
bool startsWith(const QString &s) const;
bool endsWith(const QString &s) const;
bool isNewerThan(const QDateTime &timeStamp) const;
QDateTime lastModified() const;
QFile::Permissions permissions() const;
OsType osType() const;
bool removeFile() const;
bool removeRecursively(QString *error = nullptr) const;
bool copyFile(const FilePath &target) const;
bool renameFile(const FilePath &target) const;
Qt::CaseSensitivity caseSensitivity() const;
FilePath relativeChildPath(const FilePath &parent) const;
FilePath relativePath(const FilePath &anchor) const;
FilePath pathAppended(const QString &str) const;
FilePath stringAppended(const QString &str) const;
FilePath resolvePath(const QString &fileName) const;
FilePath resolveSymlinkTarget() const;
FilePath cleanPath() const;
FilePath canonicalPath() const;
FilePath symLinkTarget() const;
FilePath resolveSymlinks() const;
FilePath withExecutableSuffix() const;
FilePath operator/(const QString &str) const;
void clear();
bool isEmpty() const;
uint hash(uint seed) const;
// NOTE: Most FilePath operations on FilePath created from URL currently
// do not work. Among the working are .toVariant() and .toUrl().
static FilePath fromUrl(const QUrl &url);
QUrl toUrl() const;
static void setDeviceFileHooks(const DeviceFileHooks &hooks);
FilePath searchOnDevice(const QList<FilePath> &dirs) const;
Environment deviceEnvironment() const;
static QString formatFilePaths(const QList<FilePath> &files, const QString &separator);
static void removeDuplicates(QList<FilePath> &files);
static void sort(QList<FilePath> &files);
static QList<FilePath> filterEntriesHelper(const FilePath &base,
const QStringList &entries,
const QStringList &nameFilters,
QDir::Filters filters,
QDir::SortFlags sort);
private:
friend class ::tst_fileutils;
static QString calcRelativePath(const QString &absolutePath, const QString &absoluteAnchorPath);
QString m_scheme;
QString m_host;
QString m_data;
};
QTCREATOR_UTILS_EXPORT QTextStream &operator<<(QTextStream &s, const FilePath &fn);
using FilePaths = QList<FilePath>;
class QTCREATOR_UTILS_EXPORT FileUtils { class QTCREATOR_UTILS_EXPORT FileUtils {
public: public:
#ifdef QT_GUI_LIB #ifdef QT_GUI_LIB
@@ -287,6 +126,8 @@ public:
static QByteArray fileId(const FilePath &fileName); static QByteArray fileId(const FilePath &fileName);
static FilePath homePath(); static FilePath homePath();
static bool renameFile(const FilePath &srcFilePath, const FilePath &tgtFilePath); static bool renameFile(const FilePath &srcFilePath, const FilePath &tgtFilePath);
static void setDeviceFileHooks(const DeviceFileHooks &hooks);
}; };
template<typename T> template<typename T>
@@ -432,6 +273,8 @@ private:
bool m_autoRemove = true; bool m_autoRemove = true;
}; };
QTCREATOR_UTILS_EXPORT QTextStream &operator<<(QTextStream &s, const FilePath &fn);
inline uint qHash(const Utils::FilePath &a, uint seed = 0) { return a.hash(seed); } inline uint qHash(const Utils::FilePath &a, uint seed = 0) { return a.hash(seed); }
} // namespace Utils } // namespace Utils
@@ -445,4 +288,3 @@ template<> struct QTCREATOR_UTILS_EXPORT hash<Utils::FilePath>
}; };
} // namespace std } // namespace std
Q_DECLARE_METATYPE(Utils::FilePath)

View File

@@ -554,7 +554,13 @@ void QtcProcess::start()
{ {
d->clearForRun(); d->clearForRun();
QTC_CHECK(d->m_writeData.isEmpty()); // FIXME: Use it. if (!d->m_writeData.isEmpty()) {
connect(d->m_process, &ProcessInterface::started, this, [this] {
const qint64 bytesWritten = write(d->m_writeData);
QTC_CHECK(bytesWritten == d->m_writeData.size());
closeWriteChannel(); // FIXME: Is this good?
});
}
if (d->m_commandLine.executable().needsDevice()) { if (d->m_commandLine.executable().needsDevice()) {
QTC_ASSERT(s_deviceHooks.startProcessHook, return); QTC_ASSERT(s_deviceHooks.startProcessHook, return);
@@ -1219,6 +1225,7 @@ void QtcProcess::setExitCodeInterpreter(const ExitCodeInterpreter &interpreter)
void QtcProcess::setWriteData(const QByteArray &writeData) void QtcProcess::setWriteData(const QByteArray &writeData)
{ {
d->m_writeData = writeData; d->m_writeData = writeData;
setKeepWriteChannelOpen();
} }
#ifdef QT_GUI_LIB #ifdef QT_GUI_LIB
@@ -1231,11 +1238,9 @@ static bool isGuiThread()
void QtcProcess::runBlocking() void QtcProcess::runBlocking()
{ {
// FIXME: Implement properly // FIXME: Implement properly
if (d->m_commandLine.executable().needsDevice()) { if (d->m_commandLine.executable().needsDevice()) {
// writeData ?
QtcProcess::start(); QtcProcess::start();
waitForFinished(); waitForFinished();
return; return;
}; };

View File

@@ -62,6 +62,7 @@ SOURCES += \
$$PWD/fancylineedit.cpp \ $$PWD/fancylineedit.cpp \
$$PWD/qtcolorbutton.cpp \ $$PWD/qtcolorbutton.cpp \
$$PWD/savefile.cpp \ $$PWD/savefile.cpp \
$$PWD/filepath.cpp \
$$PWD/fileutils.cpp \ $$PWD/fileutils.cpp \
$$PWD/textfileformat.cpp \ $$PWD/textfileformat.cpp \
$$PWD/consoleprocess.cpp \ $$PWD/consoleprocess.cpp \
@@ -196,6 +197,7 @@ HEADERS += \
$$PWD/qtcolorbutton.h \ $$PWD/qtcolorbutton.h \
$$PWD/consoleprocess.h \ $$PWD/consoleprocess.h \
$$PWD/savefile.h \ $$PWD/savefile.h \
$$PWD/filepath.h \
$$PWD/fileutils.h \ $$PWD/fileutils.h \
$$PWD/textfileformat.h \ $$PWD/textfileformat.h \
$$PWD/uncommentselection.h \ $$PWD/uncommentselection.h \

View File

@@ -115,6 +115,8 @@ Project {
"fileinprojectfinder.h", "fileinprojectfinder.h",
"filenamevalidatinglineedit.cpp", "filenamevalidatinglineedit.cpp",
"filenamevalidatinglineedit.h", "filenamevalidatinglineedit.h",
"filepath.cpp",
"filepath.h",
"filesearch.cpp", "filesearch.cpp",
"filesearch.h", "filesearch.h",
"filesystemwatcher.cpp", "filesystemwatcher.cpp",

View File

@@ -1066,13 +1066,20 @@ AndroidDeviceInfo AndroidConfigurations::showDeviceDialog(Project *project,
if (!serialNumber.isEmpty()) if (!serialNumber.isEmpty())
break; break;
} }
const AndroidDeviceInfo defaultDevice = AndroidDeviceDialog::defaultDeviceInfo(serialNumber);
if (defaultDevice.isValid())
return defaultDevice;
AndroidDeviceDialog dialog(apiLevel, abis, serialNumber, Core::ICore::dialogParent()); AndroidDeviceDialog dialog(apiLevel, abis, serialNumber, Core::ICore::dialogParent());
AndroidDeviceInfo info = dialog.device(); AndroidDeviceInfo info = dialog.showAndGetSelectedDevice();
if (dialog.saveDeviceSelection() && info.isValid()) { if (dialog.saveDeviceSelection() && info.isValid()) {
const QString serialNumber = info.type == AndroidDeviceInfo::Hardware ? const QString newSerialNumber = info.type == AndroidDeviceInfo::Hardware ?
info.serialNumber : info.avdname; info.serialNumber : info.avdname;
if (!serialNumber.isEmpty()) if (!newSerialNumber.isEmpty()) {
AndroidConfigurations::setDefaultDevice(project, AndroidManager::devicePreferredAbi(info.cpuAbi, abis), serialNumber); const QString preferredAbi = AndroidManager::devicePreferredAbi(info.cpuAbi, abis);
AndroidConfigurations::setDefaultDevice(project, preferredAbi, newSerialNumber);
}
} }
return info; return info;
} }

View File

@@ -44,6 +44,8 @@ using namespace Android::Internal;
namespace Android { namespace Android {
namespace Internal { namespace Internal {
QVector<AndroidDeviceInfo> AndroidDeviceDialog::m_connectedDevices = {};
// yeah, writing tree models is fun! // yeah, writing tree models is fun!
class AndroidDeviceModelNode class AndroidDeviceModelNode
{ {
@@ -481,26 +483,30 @@ AndroidDeviceDialog::~AndroidDeviceDialog()
delete m_ui; delete m_ui;
} }
AndroidDeviceInfo AndroidDeviceDialog::device() AndroidDeviceInfo AndroidDeviceDialog::defaultDeviceInfo(const QString &serialNumber)
{ {
AndroidDeviceDialog::updateConnectedDevicesList();
if (serialNumber.isEmpty())
return {};
return Utils::findOrDefault(m_connectedDevices, [serialNumber](const AndroidDeviceInfo &info) {
return info.serialNumber == serialNumber || info.avdname == serialNumber;
});
}
AndroidDeviceInfo AndroidDeviceDialog::showAndGetSelectedDevice()
{
auto dev = defaultDeviceInfo(m_defaultDevice);
if (dev.isValid())
return dev;
refreshDeviceList(); refreshDeviceList();
if (!m_defaultDevice.isEmpty()) {
auto device = std::find_if(m_connectedDevices.cbegin(),
m_connectedDevices.cend(),
[this](const AndroidDeviceInfo &info) {
return info.serialNumber == m_defaultDevice ||
info.avdname == m_defaultDevice;
});
if (device != m_connectedDevices.cend())
return *device;
m_defaultDevice.clear();
}
if (exec() == QDialog::Accepted) if (exec() == QDialog::Accepted)
return m_model->device(m_ui->deviceView->currentIndex()); return m_model->device(m_ui->deviceView->currentIndex());
return AndroidDeviceInfo();
return {};
} }
bool AndroidDeviceDialog::saveDeviceSelection() const bool AndroidDeviceDialog::saveDeviceSelection() const
@@ -508,11 +514,16 @@ bool AndroidDeviceDialog::saveDeviceSelection() const
return m_ui->defaultDeviceCheckBox->isChecked(); return m_ui->defaultDeviceCheckBox->isChecked();
} }
void AndroidDeviceDialog::updateConnectedDevicesList()
{
m_connectedDevices = AndroidConfig::connectedDevices(AndroidConfigurations::currentConfig()
.adbToolPath());
}
void AndroidDeviceDialog::refreshDeviceList() void AndroidDeviceDialog::refreshDeviceList()
{ {
m_ui->refreshDevicesButton->setEnabled(false); m_ui->refreshDevicesButton->setEnabled(false);
m_progressIndicator->show(); m_progressIndicator->show();
m_connectedDevices = AndroidConfig::connectedDevices(AndroidConfigurations::currentConfig().adbToolPath());
m_futureWatcherRefreshDevices.setFuture(m_avdManager->avdList()); m_futureWatcherRefreshDevices.setFuture(m_avdManager->avdList());
} }

View File

@@ -56,7 +56,8 @@ public:
const QString &serialNumber, QWidget *parent = nullptr); const QString &serialNumber, QWidget *parent = nullptr);
~AndroidDeviceDialog() override; ~AndroidDeviceDialog() override;
AndroidDeviceInfo device(); AndroidDeviceInfo showAndGetSelectedDevice();
static AndroidDeviceInfo defaultDeviceInfo(const QString &serialNumber);
bool saveDeviceSelection() const; bool saveDeviceSelection() const;
@@ -68,6 +69,7 @@ private:
void devicesRefreshed(); void devicesRefreshed();
void enableOkayButton(); void enableOkayButton();
void defaultDeviceClear(); void defaultDeviceClear();
static void updateConnectedDevicesList();
AndroidDeviceModel *m_model; AndroidDeviceModel *m_model;
Ui::AndroidDeviceDialog *m_ui; Ui::AndroidDeviceDialog *m_ui;
@@ -76,8 +78,8 @@ private:
QStringList m_abis; QStringList m_abis;
QString m_avdNameFromAdd; QString m_avdNameFromAdd;
QString m_defaultDevice; QString m_defaultDevice;
static QVector<AndroidDeviceInfo> m_connectedDevices;
std::unique_ptr<AndroidAvdManager> m_avdManager; std::unique_ptr<AndroidAvdManager> m_avdManager;
QVector<AndroidDeviceInfo> m_connectedDevices;
QFutureWatcher<CreateAvdInfo> m_futureWatcherAddDevice; QFutureWatcher<CreateAvdInfo> m_futureWatcherAddDevice;
QFutureWatcher<AndroidDeviceInfoList> m_futureWatcherRefreshDevices; QFutureWatcher<AndroidDeviceInfoList> m_futureWatcherRefreshDevices;
}; };

View File

@@ -515,7 +515,7 @@ void CMakeBuildSettingsWidget::batchEditConfiguration()
[expander](const QString &s) { [expander](const QString &s) {
return expander->expand(s); return expander->expand(s);
}); });
const CMakeConfig config = CMakeConfigItem::itemsFromArguments(expandedLines); const CMakeConfig config = CMakeConfig::fromArguments(expandedLines);
m_configModel->setBatchEditConfiguration(config); m_configModel->setBatchEditConfiguration(config);
}); });
@@ -1048,7 +1048,7 @@ bool CMakeBuildConfiguration::fromMap(const QVariantMap &map)
}(); }();
if (initialCMakeArguments().isEmpty()) { if (initialCMakeArguments().isEmpty()) {
QStringList initialArgs = defaultInitialCMakeArguments(kit(), buildTypeName) QStringList initialArgs = defaultInitialCMakeArguments(kit(), buildTypeName)
+ Utils::transform(conf, [this](const CMakeConfigItem &i) { + Utils::transform(conf.toList(), [this](const CMakeConfigItem &i) {
return i.toArgument(macroExpander()); return i.toArgument(macroExpander());
}); });
@@ -1110,7 +1110,8 @@ CMakeConfig CMakeBuildConfiguration::configurationChanges() const
QStringList CMakeBuildConfiguration::configurationChangesArguments() const QStringList CMakeBuildConfiguration::configurationChangesArguments() const
{ {
return Utils::transform(m_configurationChanges, [](const CMakeConfigItem &i) { return i.toArgument(); }); return Utils::transform(m_configurationChanges.toList(),
[](const CMakeConfigItem &i) { return i.toArgument(); });
} }
QStringList CMakeBuildConfiguration::initialCMakeArguments() const QStringList CMakeBuildConfiguration::initialCMakeArguments() const
@@ -1296,9 +1297,9 @@ BuildInfo CMakeBuildConfigurationFactory::createBuildInfo(BuildType buildType)
BuildConfiguration::BuildType CMakeBuildConfiguration::buildType() const BuildConfiguration::BuildType CMakeBuildConfiguration::buildType() const
{ {
QByteArray cmakeBuildTypeName = CMakeConfigItem::valueOf("CMAKE_BUILD_TYPE", m_configurationFromCMake); QByteArray cmakeBuildTypeName = m_configurationFromCMake.valueOf("CMAKE_BUILD_TYPE");
if (cmakeBuildTypeName.isEmpty()) { if (cmakeBuildTypeName.isEmpty()) {
QByteArray cmakeCfgTypes = CMakeConfigItem::valueOf("CMAKE_CONFIGURATION_TYPES", m_configurationFromCMake); QByteArray cmakeCfgTypes = m_configurationFromCMake.valueOf("CMAKE_CONFIGURATION_TYPES");
if (!cmakeCfgTypes.isEmpty()) if (!cmakeCfgTypes.isEmpty())
cmakeBuildTypeName = cmakeBuildType().toUtf8(); cmakeBuildTypeName = cmakeBuildType().toUtf8();
} }
@@ -1352,14 +1353,14 @@ QString CMakeBuildConfiguration::cmakeBuildType() const
QString errorMessage; QString errorMessage;
config = CMakeBuildSystem::parseCMakeCacheDotTxt(cmakeCacheTxt, &errorMessage); config = CMakeBuildSystem::parseCMakeCacheDotTxt(cmakeCacheTxt, &errorMessage);
} else { } else {
config = CMakeConfigItem::itemsFromArguments(initialCMakeArguments()); config = CMakeConfig::fromArguments(initialCMakeArguments());
} }
} else if (!hasCMakeCache) { } else if (!hasCMakeCache) {
config = CMakeConfigItem::itemsFromArguments(initialCMakeArguments()); config = CMakeConfig::fromArguments(initialCMakeArguments());
} }
if (!config.isEmpty() && !isMultiConfig()) { if (!config.isEmpty() && !isMultiConfig()) {
cmakeBuildType = CMakeConfigItem::stringValueOf("CMAKE_BUILD_TYPE", config); cmakeBuildType = config.stringValueOf("CMAKE_BUILD_TYPE");
const_cast<CMakeBuildConfiguration*>(this)->setCMakeBuildType(cmakeBuildType); const_cast<CMakeBuildConfiguration*>(this)->setCMakeBuildType(cmakeBuildType);
} }

View File

@@ -838,7 +838,7 @@ void CMakeBuildSystem::wireUpConnections()
QString errorMessage; QString errorMessage;
const CMakeConfig config = CMakeBuildSystem::parseCMakeCacheDotTxt(cmakeCacheTxt, &errorMessage); const CMakeConfig config = CMakeBuildSystem::parseCMakeCacheDotTxt(cmakeCacheTxt, &errorMessage);
if (!config.isEmpty() && errorMessage.isEmpty()) { if (!config.isEmpty() && errorMessage.isEmpty()) {
QString cmakeBuildTypeName = CMakeConfigItem::stringValueOf("CMAKE_BUILD_TYPE", config); QString cmakeBuildTypeName = config.stringValueOf("CMAKE_BUILD_TYPE");
cmakeBuildConfiguration()->setCMakeBuildType(cmakeBuildTypeName, true); cmakeBuildConfiguration()->setCMakeBuildType(cmakeBuildTypeName, true);
} }
} }
@@ -1057,7 +1057,7 @@ CMakeConfig CMakeBuildSystem::parseCMakeCacheDotTxt(const Utils::FilePath &cache
*errorMessage = tr("CMakeCache.txt file not found."); *errorMessage = tr("CMakeCache.txt file not found.");
return {}; return {};
} }
CMakeConfig result = CMakeConfigItem::itemsFromFile(cacheFile, errorMessage); CMakeConfig result = CMakeConfig::fromFile(cacheFile, errorMessage);
if (!errorMessage->isEmpty()) if (!errorMessage->isEmpty())
return {}; return {};
return result; return result;
@@ -1210,7 +1210,7 @@ void CMakeBuildSystem::updateQmlJSCodeModel(const QStringList &extraHeaderPaths,
}; };
const CMakeConfig &cm = cmakeBuildConfiguration()->configurationFromCMake(); const CMakeConfig &cm = cmakeBuildConfiguration()->configurationFromCMake();
addImports(CMakeConfigItem::stringValueOf("QML_IMPORT_PATH", cm)); addImports(cm.stringValueOf("QML_IMPORT_PATH"));
addImports(kit()->value(QtSupport::KitQmlImportPath::id()).toString()); addImports(kit()->value(QtSupport::KitQmlImportPath::id()).toString());
for (const QString &extraHeaderPath : extraHeaderPaths) for (const QString &extraHeaderPath : extraHeaderPaths)
@@ -1244,7 +1244,7 @@ void CMakeBuildSystem::updateInitialCMakeExpandableVars()
{ {
const CMakeConfig &cm = cmakeBuildConfiguration()->configurationFromCMake(); const CMakeConfig &cm = cmakeBuildConfiguration()->configurationFromCMake();
const CMakeConfig &initialConfig = const CMakeConfig &initialConfig =
CMakeConfigItem::itemsFromArguments(cmakeBuildConfiguration()->initialCMakeArguments()); CMakeConfig::fromArguments(cmakeBuildConfiguration()->initialCMakeArguments());
CMakeConfig config; CMakeConfig config;
@@ -1275,7 +1275,7 @@ void CMakeBuildSystem::updateInitialCMakeExpandableVars()
}); });
if (it != cm.cend()) { if (it != cm.cend()) {
const QByteArray initialValue = CMakeConfigItem::expandedValueOf(kit(), var, initialConfig).toUtf8(); const QByteArray initialValue = initialConfig.expandedValueOf(kit(), var).toUtf8();
const FilePath initialPath = FilePath::fromString(QString::fromUtf8(initialValue)); const FilePath initialPath = FilePath::fromString(QString::fromUtf8(initialValue));
const FilePath path = FilePath::fromString(QString::fromUtf8(it->value)); const FilePath path = FilePath::fromString(QString::fromUtf8(it->value));
@@ -1299,20 +1299,23 @@ void CMakeBuildSystem::updateInitialCMakeExpandableVars()
}); });
if (it != cm.cend()) { if (it != cm.cend()) {
const QByteArray initialValue = CMakeConfigItem::expandedValueOf(kit(), var, initialConfig).toUtf8(); const QByteArrayList initialValueList = initialConfig.expandedValueOf(kit(), var).toUtf8().split(';');
const FilePath initialPath = FilePath::fromString(QString::fromUtf8(initialValue));
const bool pathIsContained for (const auto &initialValue: initialValueList) {
= Utils::contains(it->value.split(';'), [samePath, initialPath](const QByteArray &p) { const FilePath initialPath = FilePath::fromString(QString::fromUtf8(initialValue));
return samePath(FilePath::fromString(QString::fromUtf8(p)), initialPath);
});
if (!initialValue.isEmpty() && !pathIsContained) {
CMakeConfigItem item(*it);
item.value = initialValue;
item.value.append(";");
item.value.append(it->value);
config << item; const bool pathIsContained
= Utils::contains(it->value.split(';'), [samePath, initialPath](const QByteArray &p) {
return samePath(FilePath::fromString(QString::fromUtf8(p)), initialPath);
});
if (!initialValue.isEmpty() && !pathIsContained) {
CMakeConfigItem item(*it);
item.value = initialValue;
item.value.append(";");
item.value.append(it->value);
config << item;
}
} }
} }
} }

View File

@@ -55,29 +55,28 @@ CMakeConfigItem::CMakeConfigItem(const QByteArray &k, const QByteArray &v) :
key(k), value(v) key(k), value(v)
{ } { }
QByteArray CMakeConfigItem::valueOf(const QByteArray &key, const QList<CMakeConfigItem> &input) QByteArray CMakeConfig::valueOf(const QByteArray &key) const
{ {
for (auto it = input.constBegin(); it != input.constEnd(); ++it) { for (auto it = constBegin(); it != constEnd(); ++it) {
if (it->key == key) if (it->key == key)
return it->value; return it->value;
} }
return QByteArray(); return QByteArray();
} }
QString CMakeConfigItem::stringValueOf(const QByteArray &key, const QList<CMakeConfigItem> &input) QString CMakeConfig::stringValueOf(const QByteArray &key) const
{ {
return QString::fromUtf8(valueOf(key, input)); return QString::fromUtf8(valueOf(key));
} }
FilePath CMakeConfigItem::filePathValueOf(const QByteArray &key, const QList<CMakeConfigItem> &input) FilePath CMakeConfig::filePathValueOf(const QByteArray &key) const
{ {
return FilePath::fromUtf8(valueOf(key, input)); return FilePath::fromUtf8(valueOf(key));
} }
QString CMakeConfigItem::expandedValueOf(const ProjectExplorer::Kit *k, const QByteArray &key, QString CMakeConfig::expandedValueOf(const ProjectExplorer::Kit *k, const QByteArray &key) const
const QList<CMakeConfigItem> &input)
{ {
for (auto it = input.constBegin(); it != input.constEnd(); ++it) { for (auto it = constBegin(); it != constEnd(); ++it) {
if (it->key == key) if (it->key == key)
return it->expandedValue(k); return it->expandedValue(k);
} }
@@ -312,7 +311,7 @@ static CMakeConfigItem unsetItemFromString(const QString &input)
return item; return item;
} }
QList<CMakeConfigItem> CMakeConfigItem::itemsFromArguments(const QStringList &list) CMakeConfig CMakeConfig::fromArguments(const QStringList &list)
{ {
CMakeConfig result; CMakeConfig result;
bool inSet = false; bool inSet = false;
@@ -348,7 +347,7 @@ QList<CMakeConfigItem> CMakeConfigItem::itemsFromArguments(const QStringList &li
return result; return result;
} }
QList<CMakeConfigItem> CMakeConfigItem::itemsFromFile(const Utils::FilePath &cacheFile, QString *errorMessage) CMakeConfig CMakeConfig::fromFile(const Utils::FilePath &cacheFile, QString *errorMessage)
{ {
CMakeConfig result; CMakeConfig result;
QFile cache(cacheFile.toString()); QFile cache(cacheFile.toString());
@@ -473,6 +472,11 @@ bool CMakeConfigItem::operator==(const CMakeConfigItem &o) const
return o.key == key && o.value == value && o.isUnset == isUnset; return o.key == key && o.value == value && o.isUnset == isUnset;
} }
uint qHash(const CMakeConfigItem &it)
{
return ::qHash(it.key) ^ ::qHash(it.value) ^ ::qHash(it.isUnset);
}
#if WITH_TESTS #if WITH_TESTS
} // namespace CMakeProjectManager } // namespace CMakeProjectManager

View File

@@ -43,18 +43,14 @@ class Kit;
namespace CMakeProjectManager { namespace CMakeProjectManager {
class CMAKE_EXPORT CMakeConfigItem { class CMAKE_EXPORT CMakeConfigItem
{
public: public:
enum Type { FILEPATH, PATH, BOOL, STRING, INTERNAL, STATIC, UNINITIALIZED }; enum Type { FILEPATH, PATH, BOOL, STRING, INTERNAL, STATIC, UNINITIALIZED };
CMakeConfigItem(); CMakeConfigItem();
CMakeConfigItem(const QByteArray &k, Type t, const QByteArray &d, const QByteArray &v, const QStringList &s = {}); CMakeConfigItem(const QByteArray &k, Type t, const QByteArray &d, const QByteArray &v, const QStringList &s = {});
CMakeConfigItem(const QByteArray &k, const QByteArray &v); CMakeConfigItem(const QByteArray &k, const QByteArray &v);
static QByteArray valueOf(const QByteArray &key, const QList<CMakeConfigItem> &input);
static QString stringValueOf(const QByteArray &key, const QList<CMakeConfigItem> &input);
static Utils::FilePath filePathValueOf(const QByteArray &key, const QList<CMakeConfigItem> &input);
static QString expandedValueOf(const ProjectExplorer::Kit *k, const QByteArray &key,
const QList<CMakeConfigItem> &input);
static QStringList cmakeSplitValue(const QString &in, bool keepEmpty = false); static QStringList cmakeSplitValue(const QString &in, bool keepEmpty = false);
static Type typeStringToType(const QByteArray &typeString); static Type typeStringToType(const QByteArray &typeString);
static QString typeToTypeString(const Type t); static QString typeToTypeString(const Type t);
@@ -66,8 +62,6 @@ public:
static bool less(const CMakeConfigItem &a, const CMakeConfigItem &b); static bool less(const CMakeConfigItem &a, const CMakeConfigItem &b);
static CMakeConfigItem fromString(const QString &s); static CMakeConfigItem fromString(const QString &s);
static QList<CMakeConfigItem> itemsFromArguments(const QStringList &list);
static QList<CMakeConfigItem> itemsFromFile(const Utils::FilePath &input, QString *errorMessage);
QString toString(const Utils::MacroExpander *expander = nullptr) const; QString toString(const Utils::MacroExpander *expander = nullptr) const;
QString toArgument(const Utils::MacroExpander *expander = nullptr) const; QString toArgument(const Utils::MacroExpander *expander = nullptr) const;
QString toCMakeSetLine(const Utils::MacroExpander *expander = nullptr) const; QString toCMakeSetLine(const Utils::MacroExpander *expander = nullptr) const;
@@ -83,6 +77,25 @@ public:
QByteArray documentation; QByteArray documentation;
QStringList values; QStringList values;
}; };
using CMakeConfig = QList<CMakeConfigItem>;
uint qHash(const CMakeConfigItem &it); // needed for MSVC
class CMAKE_EXPORT CMakeConfig : public QList<CMakeConfigItem>
{
public:
CMakeConfig() = default;
CMakeConfig(const QList<CMakeConfigItem> &items) : QList<CMakeConfigItem>(items) {}
CMakeConfig(std::initializer_list<CMakeConfigItem> items) : QList<CMakeConfigItem>(items) {}
const QList<CMakeConfigItem> &toList() const { return *this; }
static CMakeConfig fromArguments(const QStringList &list);
static CMakeConfig fromFile(const Utils::FilePath &input, QString *errorMessage);
QByteArray valueOf(const QByteArray &key) const;
QString stringValueOf(const QByteArray &key) const;
Utils::FilePath filePathValueOf(const QByteArray &key) const;
QString expandedValueOf(const ProjectExplorer::Kit *k, const QByteArray &key) const;
};
} // namespace CMakeProjectManager } // namespace CMakeProjectManager

View File

@@ -996,15 +996,15 @@ void CMakeConfigurationKitAspect::setConfiguration(Kit *k, const CMakeConfig &co
{ {
if (!k) if (!k)
return; return;
const QStringList tmp = Utils::transform(config, [](const CMakeConfigItem &i) { return i.toString(); }); const QStringList tmp = Utils::transform(config.toList(),
[](const CMakeConfigItem &i) { return i.toString(); });
k->setValue(CONFIGURATION_ID, tmp); k->setValue(CONFIGURATION_ID, tmp);
} }
QStringList CMakeConfigurationKitAspect::toStringList(const Kit *k) QStringList CMakeConfigurationKitAspect::toStringList(const Kit *k)
{ {
QStringList current QStringList current = Utils::transform(CMakeConfigurationKitAspect::configuration(k).toList(),
= Utils::transform(CMakeConfigurationKitAspect::configuration(k), [](const CMakeConfigItem &i) { return i.toString(); });
[](const CMakeConfigItem &i) { return i.toString(); });
current = Utils::filtered(current, [](const QString &s) { return !s.isEmpty(); }); current = Utils::filtered(current, [](const QString &s) { return !s.isEmpty(); });
Utils::sort(current); Utils::sort(current);
return current; return current;
@@ -1023,7 +1023,7 @@ void CMakeConfigurationKitAspect::fromStringList(Kit *k, const QStringList &in)
QStringList CMakeConfigurationKitAspect::toArgumentsList(const Kit *k) QStringList CMakeConfigurationKitAspect::toArgumentsList(const Kit *k)
{ {
return Utils::transform(CMakeConfigurationKitAspect::configuration(k), return Utils::transform(CMakeConfigurationKitAspect::configuration(k).toList(),
[](const CMakeConfigItem &i) { return i.toArgument(nullptr); }); [](const CMakeConfigItem &i) { return i.toArgument(nullptr); });
} }
@@ -1046,8 +1046,8 @@ QVariant CMakeConfigurationKitAspect::defaultValue(const Kit *k) const
{ {
// FIXME: Convert preload scripts // FIXME: Convert preload scripts
CMakeConfig config = defaultConfiguration(k); CMakeConfig config = defaultConfiguration(k);
const QStringList tmp const QStringList tmp = Utils::transform(config.toList(),
= Utils::transform(config, [](const CMakeConfigItem &i) { return i.toString(); }); [](const CMakeConfigItem &i) { return i.toString(); });
return tmp; return tmp;
} }

View File

@@ -135,20 +135,16 @@ QStringList CMakeProjectImporter::importCandidates()
static FilePath qmakeFromCMakeCache(const CMakeConfig &config) static FilePath qmakeFromCMakeCache(const CMakeConfig &config)
{ {
// Qt4 way to define things (more convenient for us, so try this first;-) // Qt4 way to define things (more convenient for us, so try this first;-)
FilePath qmake const FilePath qmake = config.filePathValueOf("QT_QMAKE_EXECUTABLE");
= FilePath::fromUtf8(CMakeConfigItem::valueOf(QByteArray("QT_QMAKE_EXECUTABLE"), config));
qCDebug(cmInputLog) << "QT_QMAKE_EXECUTABLE=" << qmake.toUserOutput(); qCDebug(cmInputLog) << "QT_QMAKE_EXECUTABLE=" << qmake.toUserOutput();
if (!qmake.isEmpty()) if (!qmake.isEmpty())
return qmake; return qmake;
// Check Qt5 settings: oh, the horror! // Check Qt5 settings: oh, the horror!
const FilePath qtCMakeDir = [config] { const FilePath qtCMakeDir = [config] {
FilePath tmp = FilePath::fromUtf8( FilePath tmp = config.filePathValueOf("Qt5Core_DIR");
CMakeConfigItem::valueOf(QByteArray("Qt5Core_DIR"), config)); if (tmp.isEmpty())
if (tmp.isEmpty()) { tmp = config.filePathValueOf("Qt6Core_DIR");
tmp = FilePath::fromUtf8(
CMakeConfigItem::valueOf(QByteArray("Qt6Core_DIR"), config));
}
return tmp; return tmp;
}(); }();
qCDebug(cmInputLog) << "QtXCore_DIR=" << qtCMakeDir.toUserOutput(); qCDebug(cmInputLog) << "QtXCore_DIR=" << qtCMakeDir.toUserOutput();
@@ -206,11 +202,11 @@ static FilePath qmakeFromCMakeCache(const CMakeConfig &config)
cmake.setEnvironment(env); cmake.setEnvironment(env);
cmake.setTimeOutMessageBoxEnabled(false); cmake.setTimeOutMessageBoxEnabled(false);
QString cmakeGenerator = CMakeConfigItem::stringValueOf(QByteArray("CMAKE_GENERATOR"), config); QString cmakeGenerator = config.stringValueOf(QByteArray("CMAKE_GENERATOR"));
FilePath cmakeExecutable = CMakeConfigItem::filePathValueOf(QByteArray("CMAKE_COMMAND"), config); FilePath cmakeExecutable = config.filePathValueOf(QByteArray("CMAKE_COMMAND"));
FilePath cmakeMakeProgram =CMakeConfigItem::filePathValueOf(QByteArray("CMAKE_MAKE_PROGRAM"), config); FilePath cmakeMakeProgram = config.filePathValueOf(QByteArray("CMAKE_MAKE_PROGRAM"));
FilePath toolchainFile = CMakeConfigItem::filePathValueOf(QByteArray("CMAKE_TOOLCHAIN_FILE"), config); FilePath toolchainFile = config.filePathValueOf(QByteArray("CMAKE_TOOLCHAIN_FILE"));
FilePath hostPath = CMakeConfigItem::filePathValueOf(QByteArray("QT_HOST_PATH"), config); FilePath hostPath = config.filePathValueOf(QByteArray("QT_HOST_PATH"));
QStringList args; QStringList args;
args.push_back("-S"); args.push_back("-S");
@@ -270,7 +266,7 @@ static QVector<ToolChainDescription> extractToolChainsFromCache(const CMakeConfi
} }
if (!haveCCxxCompiler) { if (!haveCCxxCompiler) {
const QByteArray generator = CMakeConfigItem::valueOf(QByteArray("CMAKE_GENERATOR"), config); const QByteArray generator = config.valueOf("CMAKE_GENERATOR");
QString cCompilerName; QString cCompilerName;
QString cxxCompilerName; QString cxxCompilerName;
if (generator.contains("Visual Studio")) { if (generator.contains("Visual Studio")) {
@@ -282,8 +278,7 @@ static QVector<ToolChainDescription> extractToolChainsFromCache(const CMakeConfi
} }
if (!cCompilerName.isEmpty() && !cxxCompilerName.isEmpty()) { if (!cCompilerName.isEmpty() && !cxxCompilerName.isEmpty()) {
const FilePath linker = FilePath::fromUtf8( const FilePath linker = config.filePathValueOf("CMAKE_LINKER");
CMakeConfigItem::valueOf(QByteArray("CMAKE_LINKER"), config));
if (!linker.isEmpty()) { if (!linker.isEmpty()) {
const FilePath compilerPath = linker.parentDir(); const FilePath compilerPath = linker.parentDir();
result.append({compilerPath.pathAppended(cCompilerName), result.append({compilerPath.pathAppended(cCompilerName),
@@ -315,13 +310,11 @@ QList<void *> CMakeProjectImporter::examineDirectory(const FilePath &importPath,
return { }; return { };
} }
QByteArrayList buildConfigurationTypes = {CMakeConfigItem::valueOf("CMAKE_BUILD_TYPE", config)}; QByteArrayList buildConfigurationTypes = {config.valueOf("CMAKE_BUILD_TYPE")};
if (buildConfigurationTypes.front().isEmpty()) { if (buildConfigurationTypes.front().isEmpty()) {
QByteArray buildConfigurationTypesString = QByteArray buildConfigurationTypesString = config.valueOf("CMAKE_CONFIGURATION_TYPES");
CMakeConfigItem::valueOf("CMAKE_CONFIGURATION_TYPES", config); if (!buildConfigurationTypesString.isEmpty())
if (!buildConfigurationTypesString.isEmpty()) {
buildConfigurationTypes = buildConfigurationTypesString.split(';'); buildConfigurationTypes = buildConfigurationTypesString.split(';');
}
} }
QList<void *> result; QList<void *> result;
@@ -329,7 +322,7 @@ QList<void *> CMakeProjectImporter::examineDirectory(const FilePath &importPath,
auto data = std::make_unique<DirectoryData>(); auto data = std::make_unique<DirectoryData>();
data->cmakeHomeDirectory = data->cmakeHomeDirectory =
FilePath::fromUserInput(CMakeConfigItem::stringValueOf("CMAKE_HOME_DIRECTORY", config)) FilePath::fromUserInput(config.stringValueOf("CMAKE_HOME_DIRECTORY"))
.canonicalPath(); .canonicalPath();
const FilePath canonicalProjectDirectory = projectDirectory().canonicalPath(); const FilePath canonicalProjectDirectory = projectDirectory().canonicalPath();
if (data->cmakeHomeDirectory != canonicalProjectDirectory) { if (data->cmakeHomeDirectory != canonicalProjectDirectory) {
@@ -344,12 +337,12 @@ QList<void *> CMakeProjectImporter::examineDirectory(const FilePath &importPath,
data->buildDirectory = importPath; data->buildDirectory = importPath;
data->cmakeBuildType = buildType; data->cmakeBuildType = buildType;
data->cmakeBinary = CMakeConfigItem::filePathValueOf("CMAKE_COMMAND", config); data->cmakeBinary = config.filePathValueOf("CMAKE_COMMAND");
data->generator = CMakeConfigItem::stringValueOf("CMAKE_GENERATOR", config); data->generator = config.stringValueOf("CMAKE_GENERATOR");
data->extraGenerator = CMakeConfigItem::stringValueOf("CMAKE_EXTRA_GENERATOR", config); data->extraGenerator = config.stringValueOf("CMAKE_EXTRA_GENERATOR");
data->platform = CMakeConfigItem::stringValueOf("CMAKE_GENERATOR_PLATFORM", config); data->platform = config.stringValueOf("CMAKE_GENERATOR_PLATFORM");
data->toolset = CMakeConfigItem::stringValueOf("CMAKE_GENERATOR_TOOLSET", config); data->toolset = config.stringValueOf("CMAKE_GENERATOR_TOOLSET");
data->sysroot = CMakeConfigItem::filePathValueOf("CMAKE_SYSROOT", config); data->sysroot = config.filePathValueOf("CMAKE_SYSROOT");
// Qt: // Qt:
const FilePath qmake = qmakeFromCMakeCache(config); const FilePath qmake = qmakeFromCMakeCache(config);

View File

@@ -203,7 +203,7 @@ QList<ConfigModel::DataItem> ConfigModel::configurationForCMake() const
void ConfigModel::setConfiguration(const CMakeConfig &config) void ConfigModel::setConfiguration(const CMakeConfig &config)
{ {
setConfiguration(Utils::transform(config, [](const CMakeConfigItem &i) { setConfiguration(Utils::transform(config.toList(), [](const CMakeConfigItem &i) {
return DataItem(i); return DataItem(i);
})); }));
} }

View File

@@ -337,7 +337,7 @@ void FileApiReader::writeConfigurationIntoBuildDirectory(const QStringList &conf
QByteArray contents; QByteArray contents;
contents.append("# This file is managed by Qt Creator, do not edit!\n\n"); contents.append("# This file is managed by Qt Creator, do not edit!\n\n");
contents.append( contents.append(
transform(CMakeConfigItem::itemsFromArguments(configurationArguments), transform(CMakeConfig::fromArguments(configurationArguments).toList(),
[](const CMakeConfigItem &item) { [](const CMakeConfigItem &item) {
return item.toCMakeSetLine(nullptr); return item.toCMakeSetLine(nullptr);
}) })

View File

@@ -69,6 +69,8 @@
#include <QHeaderView> #include <QHeaderView>
#include <QLoggingCategory> #include <QLoggingCategory>
#include <QPushButton> #include <QPushButton>
#include <QRandomGenerator>
#include <QRegularExpression>
#include <QTextBrowser> #include <QTextBrowser>
#include <QToolButton> #include <QToolButton>
#include <QThread> #include <QThread>
@@ -304,9 +306,11 @@ public:
}); });
} }
~DockerDevicePrivate() { delete m_shell; } ~DockerDevicePrivate() { stopCurrentContainer(); }
bool runInContainer(const CommandLine &cmd) const; bool runInContainer(const CommandLine &cmd) const;
bool runInShell(const CommandLine &cmd) const;
QString outputForRunInShell(const CommandLine &cmd) const;
void tryCreateLocalFileAccess(); void tryCreateLocalFileAccess();
@@ -318,6 +322,7 @@ public:
// For local file access // For local file access
QPointer<QtcProcess> m_shell; QPointer<QtcProcess> m_shell;
mutable QMutex m_shellMutex;
QString m_container; QString m_container;
QString m_mergedDir; QString m_mergedDir;
QFileSystemWatcher m_mergedDirWatcher; QFileSystemWatcher m_mergedDirWatcher;
@@ -359,12 +364,15 @@ public:
auto daemonStateLabel = new QLabel(tr("Daemon state:")); auto daemonStateLabel = new QLabel(tr("Daemon state:"));
m_daemonReset = new QToolButton; m_daemonReset = new QToolButton;
m_daemonReset->setIcon(Icons::INFO.icon()); m_daemonReset->setIcon(Icons::INFO.icon());
m_daemonReset->setToolTip(tr("Daemon state not evaluated.")); m_daemonReset->setToolTip(tr("Clear detected daemon state. "
"It will be automatically re-evaluated next time an access is needed."));
m_daemonState = new QLabel(tr("Daemon state not evaluated."));
connect(m_daemonReset, &QToolButton::clicked, this, [this, dockerDevice] { connect(m_daemonReset, &QToolButton::clicked, this, [this, dockerDevice] {
dockerDevice->resetDaemonState(); dockerDevice->resetDaemonState();
m_daemonReset->setIcon(Icons::INFO.icon()); m_daemonReset->setIcon(Icons::INFO.icon());
m_daemonReset->setToolTip(tr("Daemon state not evaluated.")); m_daemonState->setText(tr("Daemon state not evaluated."));
}); });
m_runAsOutsideUser = new QCheckBox(tr("Run as outside user")); m_runAsOutsideUser = new QCheckBox(tr("Run as outside user"));
@@ -403,10 +411,11 @@ public:
if (!dockerDevice->isDaemonRunning()) { if (!dockerDevice->isDaemonRunning()) {
logView->append(tr("Docker daemon appears to be not running.")); logView->append(tr("Docker daemon appears to be not running."));
m_daemonReset->setToolTip(tr("Daemon not running. Push to reset the state.")); m_daemonState->setText(tr("Docker daemon not running."));
m_daemonReset->setIcon(Icons::CRITICAL.icon()); m_daemonReset->setIcon(Icons::CRITICAL.icon());
} else { } else {
m_daemonReset->setToolTip(tr("Docker daemon running.")); logView->append(tr("Docker daemon appears to be running."));
m_daemonState->setText(tr("Docker daemon running."));
m_daemonReset->setIcon(Icons::OK.icon()); m_daemonReset->setIcon(Icons::OK.icon());
} }
@@ -427,7 +436,7 @@ public:
Form { Form {
idLabel, m_idLineEdit, Break(), idLabel, m_idLineEdit, Break(),
repoLabel, m_repoLineEdit, Break(), repoLabel, m_repoLineEdit, Break(),
daemonStateLabel, m_daemonReset, Break(), daemonStateLabel, m_daemonReset, m_daemonState, Break(),
m_runAsOutsideUser, Break(), m_runAsOutsideUser, Break(),
tr("Paths to mount:"), m_pathsLineEdit, Break(), tr("Paths to mount:"), m_pathsLineEdit, Break(),
Column { Column {
@@ -445,6 +454,7 @@ private:
QLineEdit *m_idLineEdit; QLineEdit *m_idLineEdit;
QLineEdit *m_repoLineEdit; QLineEdit *m_repoLineEdit;
QToolButton *m_daemonReset; QToolButton *m_daemonReset;
QLabel *m_daemonState;
QCheckBox *m_runAsOutsideUser; QCheckBox *m_runAsOutsideUser;
QLineEdit *m_pathsLineEdit; QLineEdit *m_pathsLineEdit;
@@ -745,6 +755,20 @@ void DockerDevicePrivate::stopCurrentContainer()
if (m_container.isEmpty() || m_accessible == NoDaemon) if (m_container.isEmpty() || m_accessible == NoDaemon)
return; return;
if (m_shell) {
QMutexLocker l(&m_shellMutex);
m_shell->write("exit\n");
m_shell->waitForFinished(2000);
if (m_shell->state() == QProcess::NotRunning) {
LOG("Clean exit via shell");
m_container.clear();
m_mergedDir.clear();
delete m_shell;
m_shell = nullptr;
return;
}
}
QtcProcess proc; QtcProcess proc;
proc.setCommand({"docker", {"container", "stop", m_container}}); proc.setCommand({"docker", {"container", "stop", m_container}});
@@ -1019,7 +1043,7 @@ bool DockerDevice::isExecutableFile(const FilePath &filePath) const
return res; return res;
} }
const QString path = filePath.path(); const QString path = filePath.path();
return d->runInContainer({"test", {"-x", path}}); return d->runInShell({"test", {"-x", path}});
} }
bool DockerDevice::isReadableFile(const FilePath &filePath) const bool DockerDevice::isReadableFile(const FilePath &filePath) const
@@ -1033,7 +1057,7 @@ bool DockerDevice::isReadableFile(const FilePath &filePath) const
return res; return res;
} }
const QString path = filePath.path(); const QString path = filePath.path();
return d->runInContainer({"test", {"-r", path, "-a", "-f", path}}); return d->runInShell({"test", {"-r", path, "-a", "-f", path}});
} }
bool DockerDevice::isWritableFile(const Utils::FilePath &filePath) const bool DockerDevice::isWritableFile(const Utils::FilePath &filePath) const
@@ -1047,7 +1071,7 @@ bool DockerDevice::isWritableFile(const Utils::FilePath &filePath) const
return res; return res;
} }
const QString path = filePath.path(); const QString path = filePath.path();
return d->runInContainer({"test", {"-w", path, "-a", "-f", path}}); return d->runInShell({"test", {"-w", path, "-a", "-f", path}});
} }
bool DockerDevice::isReadableDirectory(const FilePath &filePath) const bool DockerDevice::isReadableDirectory(const FilePath &filePath) const
@@ -1061,7 +1085,7 @@ bool DockerDevice::isReadableDirectory(const FilePath &filePath) const
return res; return res;
} }
const QString path = filePath.path(); const QString path = filePath.path();
return d->runInContainer({"test", {"-r", path, "-a", "-d", path}}); return d->runInShell({"test", {"-r", path, "-a", "-d", path}});
} }
bool DockerDevice::isWritableDirectory(const FilePath &filePath) const bool DockerDevice::isWritableDirectory(const FilePath &filePath) const
@@ -1075,7 +1099,7 @@ bool DockerDevice::isWritableDirectory(const FilePath &filePath) const
return res; return res;
} }
const QString path = filePath.path(); const QString path = filePath.path();
return d->runInContainer({"test", {"-w", path, "-a", "-d", path}}); return d->runInShell({"test", {"-w", path, "-a", "-d", path}});
} }
bool DockerDevice::isFile(const FilePath &filePath) const bool DockerDevice::isFile(const FilePath &filePath) const
@@ -1089,7 +1113,7 @@ bool DockerDevice::isFile(const FilePath &filePath) const
return res; return res;
} }
const QString path = filePath.path(); const QString path = filePath.path();
return d->runInContainer({"test", {"-f", path}}); return d->runInShell({"test", {"-f", path}});
} }
bool DockerDevice::isDirectory(const FilePath &filePath) const bool DockerDevice::isDirectory(const FilePath &filePath) const
@@ -1103,7 +1127,7 @@ bool DockerDevice::isDirectory(const FilePath &filePath) const
return res; return res;
} }
const QString path = filePath.path(); const QString path = filePath.path();
return d->runInContainer({"test", {"-d", path}}); return d->runInShell({"test", {"-d", path}});
} }
bool DockerDevice::createDirectory(const FilePath &filePath) const bool DockerDevice::createDirectory(const FilePath &filePath) const
@@ -1131,7 +1155,7 @@ bool DockerDevice::exists(const FilePath &filePath) const
return res; return res;
} }
const QString path = filePath.path(); const QString path = filePath.path();
return d->runInContainer({"test", {"-e", path}}); return d->runInShell({"test", {"-e", path}});
} }
bool DockerDevice::ensureExistingFile(const FilePath &filePath) const bool DockerDevice::ensureExistingFile(const FilePath &filePath) const
@@ -1145,7 +1169,7 @@ bool DockerDevice::ensureExistingFile(const FilePath &filePath) const
return res; return res;
} }
const QString path = filePath.path(); const QString path = filePath.path();
return d->runInContainer({"touch", {path}}); return d->runInShell({"touch", {path}});
} }
bool DockerDevice::removeFile(const FilePath &filePath) const bool DockerDevice::removeFile(const FilePath &filePath) const
@@ -1172,9 +1196,15 @@ bool DockerDevice::removeRecursively(const FilePath &filePath) const
LOG("Remove recursively? " << filePath.toUserOutput() << localAccess.toUserOutput() << res); LOG("Remove recursively? " << filePath.toUserOutput() << localAccess.toUserOutput() << res);
return res; return res;
} }
// Open this up only when really needed.
// return d->runInContainer({"rm", "-rf", {filePath.path()}}); const QString path = filePath.cleanPath().path();
return false; // We are expecting this only to be called in a context of build directories or similar.
// Chicken out in some cases that _might_ be user code errors.
QTC_ASSERT(path.startsWith('/'), return false);
const int levelsNeeded = path.startsWith("/home/") ? 4 : 3;
QTC_ASSERT(path.count('/') >= levelsNeeded, return false);
return d->runInContainer({"rm", {"-rf", "--", path}});
} }
bool DockerDevice::copyFile(const FilePath &filePath, const FilePath &target) const bool DockerDevice::copyFile(const FilePath &filePath, const FilePath &target) const
@@ -1240,8 +1270,44 @@ FilePath DockerDevice::symLinkTarget(const FilePath &filePath) const
return {}; return {};
return mapToGlobalPath(target); return mapToGlobalPath(target);
} }
QTC_CHECK(false);
return {}; const QString output = d->outputForRunInShell({"readlink", {"-n", "-e", filePath.path()}});
return output.isEmpty() ? FilePath() : filePath.withNewPath(output);
}
static FilePaths filterEntriesHelper(const FilePath &base,
const QStringList &entries,
const QStringList &nameFilters,
QDir::Filters filters,
QDir::SortFlags sort)
{
const QList<QRegularExpression> nameRegexps = transform(nameFilters, [](const QString &filter) {
QRegularExpression re;
re.setPattern(QRegularExpression::wildcardToRegularExpression(filter));
QTC_CHECK(re.isValid());
return re;
});
const auto nameMatches = [&nameRegexps](const QString &fileName) {
for (const QRegularExpression &re : nameRegexps) {
const QRegularExpressionMatch match = re.match(fileName);
if (match.hasMatch())
return true;
}
return false;
};
// FIXME: Handle sort and filters. For now bark on unsupported options.
QTC_CHECK(filters == QDir::NoFilter);
QTC_CHECK(sort == QDir::NoSort);
FilePaths result;
for (const QString &entry : entries) {
if (!nameMatches(entry))
continue;
result.append(base.pathAppended(entry));
}
return result;
} }
FilePaths DockerDevice::directoryEntries(const FilePath &filePath, FilePaths DockerDevice::directoryEntries(const FilePath &filePath,
@@ -1258,13 +1324,9 @@ FilePaths DockerDevice::directoryEntries(const FilePath &filePath,
}); });
} }
QtcProcess proc; const QString output = d->outputForRunInShell({"ls", {"-1", "-b", "--", filePath.path()}});
proc.setCommand({"ls", {"-1", "-b", "--", filePath.path()}}); QStringList entries = output.split('\n', Qt::SkipEmptyParts);
runProcess(proc); return filterEntriesHelper(filePath, entries, nameFilters, filters, sort);
proc.waitForFinished();
QStringList entries = proc.stdOut().split('\n', Qt::SkipEmptyParts);
return FilePath::filterEntriesHelper(filePath, entries, nameFilters, filters, sort);
} }
QByteArray DockerDevice::fileContents(const FilePath &filePath, qint64 limit, qint64 offset) const QByteArray DockerDevice::fileContents(const FilePath &filePath, qint64 limit, qint64 offset) const
@@ -1291,15 +1353,35 @@ QByteArray DockerDevice::fileContents(const FilePath &filePath, qint64 limit, qi
return output; return output;
} }
bool DockerDevice::writeFileContents(const Utils::FilePath &filePath, const QByteArray &data) const bool DockerDevice::writeFileContents(const FilePath &filePath, const QByteArray &data) const
{ {
QTC_ASSERT(handlesFile(filePath), return {}); QTC_ASSERT(handlesFile(filePath), return {});
tryCreateLocalFileAccess(); tryCreateLocalFileAccess();
if (hasLocalFileAccess()) if (hasLocalFileAccess())
return mapToLocalAccess(filePath).writeFileContents(data); return mapToLocalAccess(filePath).writeFileContents(data);
QTC_CHECK(false); // FIXME: Implement // This following would be the generic Unix solution.
return {}; // But it doesn't pass input. FIXME: Why?
// QtcProcess proc;
// proc.setCommand({"dd", {"of=" + filePath.path()}});
// proc.setWriteData(data);
// runProcess(proc);
// proc.waitForFinished();
TemporaryFile tempFile("dockertransport-XXXXXX");
tempFile.open();
tempFile.write(data);
const QString tempName = tempFile.fileName();
tempFile.close();
CommandLine cmd{"docker", {"cp", tempName, d->m_container + ':' + filePath.path()}};
QtcProcess proc;
proc.setCommand(cmd);
proc.runBlocking();
return proc.exitCode() == 0;
} }
void DockerDevice::runProcess(QtcProcess &process) const void DockerDevice::runProcess(QtcProcess &process) const
@@ -1375,6 +1457,48 @@ bool DockerDevicePrivate::runInContainer(const CommandLine &cmd) const
return exitCode == 0; return exitCode == 0;
} }
bool DockerDevicePrivate::runInShell(const CommandLine &cmd) const
{
if (m_accessible == NoDaemon)
return false;
QTC_ASSERT(m_shell, return false);
QMutexLocker l(&m_shellMutex);
m_shell->readAllStandardOutput(); // clean possible left-overs
m_shell->write(cmd.toUserOutput().toUtf8() + "\necho $?\n");
m_shell->waitForReadyRead();
QByteArray output = m_shell->readAllStandardOutput();
int result = output.toInt();
LOG("Run command in shell:" << cmd.toUserOutput() << "result: " << output << " ==>" << result);
return result == 0;
}
// generate hex value
static QByteArray randomHex()
{
quint32 val = QRandomGenerator::global()->generate();
return QString::number(val, 16).toUtf8();
}
QString DockerDevicePrivate::outputForRunInShell(const CommandLine &cmd) const
{
if (m_accessible == NoDaemon)
return {};
QTC_ASSERT(m_shell, return {});
QMutexLocker l(&m_shellMutex);
m_shell->readAllStandardOutput(); // clean possible left-overs
const QByteArray markerWithNewLine("___QC_DOCKER_" + randomHex() + "_OUTPUT_MARKER___\n");
m_shell->write(cmd.toUserOutput().toUtf8() + "\necho -n \"" + markerWithNewLine + "\"\n");
QByteArray output;
while (!output.endsWith(markerWithNewLine)) {
m_shell->waitForReadyRead();
output.append(m_shell->readAllStandardOutput());
}
LOG("Run command in shell:" << cmd.toUserOutput() << "output size:" << output.size());
if (QTC_GUARD(output.endsWith(markerWithNewLine)))
output.chop(markerWithNewLine.size());
return QString::fromUtf8(output);
}
// Factory // Factory
DockerDeviceFactory::DockerDeviceFactory() DockerDeviceFactory::DockerDeviceFactory()

View File

@@ -525,7 +525,7 @@ DeviceManager::DeviceManager(bool isInstance) : d(std::make_unique<DeviceManager
return device->systemEnvironment(); return device->systemEnvironment();
}; };
FilePath::setDeviceFileHooks(deviceHooks); FileUtils::setDeviceFileHooks(deviceHooks);
DeviceProcessHooks processHooks; DeviceProcessHooks processHooks;

View File

@@ -347,7 +347,7 @@ void ItemLibraryModel::update(ItemLibraryInfo *itemLibraryInfo, Model *model)
importSection = importHash[entry.requiredImport()]; importSection = importHash[entry.requiredImport()];
} }
} else if (catName == "My Quick3D Components") { } else if (catName == ItemLibraryImport::quick3DAssetsTitle()) {
importSection = importHash[ItemLibraryImport::quick3DAssetsTitle()]; importSection = importHash[ItemLibraryImport::quick3DAssetsTitle()];
} else { } else {
if (catName.startsWith("Qt Quick - ")) if (catName.startsWith("Qt Quick - "))

View File

@@ -79,6 +79,7 @@ extend_qtc_executable(sdktool
DEFINES QTCREATOR_UTILS_STATIC_LIB DEFINES QTCREATOR_UTILS_STATIC_LIB
SOURCES SOURCES
environment.cpp environment.h environment.cpp environment.h
filepath.cpp filepath.h
fileutils.cpp fileutils.h fileutils.cpp fileutils.h
hostosinfo.cpp hostosinfo.h hostosinfo.cpp hostosinfo.h
namevaluedictionary.cpp namevaluedictionary.h namevaluedictionary.cpp namevaluedictionary.h

View File

@@ -32,6 +32,7 @@ SOURCES += \
rmtoolchainoperation.cpp \ rmtoolchainoperation.cpp \
settings.cpp \ settings.cpp \
$$UTILS/environment.cpp \ $$UTILS/environment.cpp \
$$UTILS/filepath.cpp \
$$UTILS/fileutils.cpp \ $$UTILS/fileutils.cpp \
$$UTILS/hostosinfo.cpp \ $$UTILS/hostosinfo.cpp \
$$UTILS/namevaluedictionary.cpp \ $$UTILS/namevaluedictionary.cpp \
@@ -65,6 +66,7 @@ HEADERS += \
rmtoolchainoperation.h \ rmtoolchainoperation.h \
settings.h \ settings.h \
$$UTILS/environment.h \ $$UTILS/environment.h \
$$UTILS/filepath.h \
$$UTILS/fileutils.h \ $$UTILS/fileutils.h \
$$UTILS/hostosinfo.h \ $$UTILS/hostosinfo.h \
$$UTILS/namevaluedictionary.h \ $$UTILS/namevaluedictionary.h \

View File

@@ -70,6 +70,7 @@ QtcTool {
files: [ files: [
"commandline.cpp", "commandline.h", "commandline.cpp", "commandline.h",
"environment.cpp", "environment.h", "environment.cpp", "environment.h",
"filepath.cpp", "filepath.h",
"fileutils.cpp", "fileutils.h", "fileutils.cpp", "fileutils.h",
"hostosinfo.cpp", "hostosinfo.h", "hostosinfo.cpp", "hostosinfo.h",
"namevaluedictionary.cpp", "namevaluedictionary.h", "namevaluedictionary.cpp", "namevaluedictionary.h",

View File

@@ -19,6 +19,7 @@ HEADERS += \
SOURCES += \ SOURCES += \
$$UTILSDIR/commandline.cpp \ $$UTILSDIR/commandline.cpp \
$$UTILSDIR/environment.cpp \ $$UTILSDIR/environment.cpp \
$$UTILSDIR/filepath.cpp \
$$UTILSDIR/fileutils.cpp \ $$UTILSDIR/fileutils.cpp \
$$UTILSDIR/hostosinfo.cpp \ $$UTILSDIR/hostosinfo.cpp \
$$UTILSDIR/launcherinterface.cpp \ $$UTILSDIR/launcherinterface.cpp \
@@ -34,6 +35,7 @@ HEADERS += \
HEADERS += \ HEADERS += \
$$UTILSDIR/commandline.h \ $$UTILSDIR/commandline.h \
$$UTILSDIR/environment.h \ $$UTILSDIR/environment.h \
$$UTILSDIR/filepath.h \
$$UTILSDIR/fileutils.h \ $$UTILSDIR/fileutils.h \
$$UTILSDIR/hostosinfo.h \ $$UTILSDIR/hostosinfo.h \
$$UTILSDIR/launcherinterface.h \ $$UTILSDIR/launcherinterface.h \