forked from qt-creator/qt-creator
Merge remote-tracking branch 'origin/5.0'
Change-Id: I074571dac56b26a8a1449c29aef53b9052d8e304
This commit is contained in:
@@ -167,6 +167,26 @@ void registerNodeInstanceMetaObject(QObject *object, QQmlEngine *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
|
||||
QObject *createPrimitive(const QString &typeName, int majorNumber, int minorNumber, QQmlContext *context)
|
||||
{
|
||||
@@ -357,12 +377,15 @@ void doComponentCompleteRecursive(QObject *object, NodeInstanceServer *nodeInsta
|
||||
doComponentCompleteRecursive(child, nodeInstanceServer);
|
||||
}
|
||||
|
||||
if (item) {
|
||||
static_cast<QQmlParserStatus*>(item)->componentComplete();
|
||||
} else {
|
||||
QQmlParserStatus *qmlParserStatus = dynamic_cast< QQmlParserStatus*>(object);
|
||||
if (qmlParserStatus)
|
||||
qmlParserStatus->componentComplete();
|
||||
if (!isQuickStyleItem(item)) {
|
||||
qDebug() << Q_FUNC_INFO << item;
|
||||
if (item) {
|
||||
static_cast<QQmlParserStatus *>(item)->componentComplete();
|
||||
} else {
|
||||
QQmlParserStatus *qmlParserStatus = dynamic_cast<QQmlParserStatus *>(object);
|
||||
if (qmlParserStatus)
|
||||
qmlParserStatus->componentComplete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -413,7 +413,7 @@ SecondColumnLayout {
|
||||
id: transparentIndicator
|
||||
icon: StudioTheme.Constants.transparent
|
||||
pixelSize: StudioTheme.Values.myIconFontSize * 1.4
|
||||
tooltip: qsTr("Transparent TODO")
|
||||
tooltip: qsTr("Transparent")
|
||||
onClicked: {
|
||||
colorPicker.alpha = 0
|
||||
colorPicker.updateColor()
|
||||
@@ -575,22 +575,29 @@ SecondColumnLayout {
|
||||
onRightMouseButtonClicked: contextMenu.popup(colorPicker)
|
||||
|
||||
onColorInvalidated: {
|
||||
if (colorPicker.saturation > 0.0 && colorPicker.lightness > 0.0) {
|
||||
hueSpinBox.value = colorPicker.hue
|
||||
switch (colorPicker.mode) {
|
||||
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
|
||||
width: implicitWidth
|
||||
actionIndicatorVisible: false
|
||||
model: ["RGBA", "HSLA"]
|
||||
onActivated: {
|
||||
switch (colorMode.currentText) {
|
||||
case "RGBA":
|
||||
rgbaRow.visible = true
|
||||
hslaRow.visible = false
|
||||
break
|
||||
case "HSLA":
|
||||
rgbaRow.visible = false
|
||||
hslaRow.visible = true
|
||||
break
|
||||
default:
|
||||
console.log("Unknown color mode selected.")
|
||||
rgbaRow.visible = true
|
||||
hslaRow.visible = false
|
||||
}
|
||||
}
|
||||
textRole: "text"
|
||||
valueRole: "value"
|
||||
model: [
|
||||
{ value: ColorPicker.Mode.HSVA, text: "HSVA" },
|
||||
{ value: ColorPicker.Mode.RGBA, text: "RGBA" },
|
||||
{ value: ColorPicker.Mode.HSLA, text: "HSLA" }
|
||||
]
|
||||
|
||||
onActivated: colorPicker.mode = colorMode.currentValue
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: rgbaRow
|
||||
|
||||
visible: colorPicker.mode === ColorPicker.Mode.RGBA
|
||||
Layout.fillWidth: true
|
||||
spacing: StudioTheme.Values.controlGap
|
||||
|
||||
@@ -847,7 +847,7 @@ SecondColumnLayout {
|
||||
}
|
||||
|
||||
DoubleSpinBox {
|
||||
id: rgbaAlphaSpinBox
|
||||
id: rgbAlphaSpinBox
|
||||
width: StudioTheme.Values.colorEditorPopupSpinBoxWidth
|
||||
|
||||
stepSize: 1
|
||||
@@ -856,7 +856,7 @@ SecondColumnLayout {
|
||||
decimals: 0
|
||||
|
||||
onValueModified: {
|
||||
var tmp = rgbaAlphaSpinBox.value / 255.0
|
||||
var tmp = rgbAlphaSpinBox.value / 255.0
|
||||
if (colorPicker.alpha !== tmp && !colorPicker.block) {
|
||||
colorPicker.alpha = tmp
|
||||
colorPicker.updateColor()
|
||||
@@ -868,49 +868,109 @@ SecondColumnLayout {
|
||||
RowLayout {
|
||||
id: hslaRow
|
||||
|
||||
visible: false
|
||||
visible: colorPicker.mode === ColorPicker.Mode.HSLA
|
||||
Layout.fillWidth: true
|
||||
spacing: StudioTheme.Values.controlGap
|
||||
|
||||
DoubleSpinBox {
|
||||
id: hueSpinBox
|
||||
id: hslHueSpinBox
|
||||
width: StudioTheme.Values.colorEditorPopupSpinBoxWidth
|
||||
onValueModified: {
|
||||
if (colorPicker.hue !== hueSpinBox.value && !colorPicker.block) {
|
||||
colorPicker.hue = hueSpinBox.value
|
||||
if (colorPicker.hue !== hslHueSpinBox.value
|
||||
&& !colorPicker.block) {
|
||||
colorPicker.hue = hslHueSpinBox.value
|
||||
colorPicker.updateColor()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DoubleSpinBox {
|
||||
id: saturationSpinBox
|
||||
id: hslSaturationSpinBox
|
||||
width: StudioTheme.Values.colorEditorPopupSpinBoxWidth
|
||||
onValueModified: {
|
||||
if (colorPicker.saturation !== saturationSpinBox.value && !colorPicker.block) {
|
||||
colorPicker.saturation = saturationSpinBox.value
|
||||
if (colorPicker.saturationHSL !== hslSaturationSpinBox.value
|
||||
&& !colorPicker.block) {
|
||||
colorPicker.saturationHSL = hslSaturationSpinBox.value
|
||||
colorPicker.updateColor()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DoubleSpinBox {
|
||||
id: lightnessSpinBox
|
||||
id: hslLightnessSpinBox
|
||||
width: StudioTheme.Values.colorEditorPopupSpinBoxWidth
|
||||
onValueModified: {
|
||||
if (colorPicker.lightness !== lightnessSpinBox.value && !colorPicker.block) {
|
||||
colorPicker.lightness = lightnessSpinBox.value
|
||||
if (colorPicker.lightness !== hslLightnessSpinBox.value
|
||||
&& !colorPicker.block) {
|
||||
colorPicker.lightness = hslLightnessSpinBox.value
|
||||
colorPicker.updateColor()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DoubleSpinBox {
|
||||
id: hslaAlphaSpinBox
|
||||
id: hslAlphaSpinBox
|
||||
width: StudioTheme.Values.colorEditorPopupSpinBoxWidth
|
||||
onValueModified: {
|
||||
if (colorPicker.alpha !== hslaAlphaSpinBox.value && !colorPicker.block) {
|
||||
colorPicker.alpha = hslaAlphaSpinBox.value
|
||||
if (colorPicker.alpha !== hslAlphaSpinBox.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()
|
||||
}
|
||||
}
|
||||
|
@@ -29,15 +29,26 @@ import StudioTheme 1.0 as StudioTheme
|
||||
Column {
|
||||
id: root
|
||||
|
||||
enum Mode {
|
||||
HSVA,
|
||||
RGBA,
|
||||
HSLA
|
||||
}
|
||||
|
||||
property int mode: ColorPicker.Mode.HSVA
|
||||
property color color
|
||||
property real alpha: 1
|
||||
|
||||
property real hue: 0
|
||||
property real saturation: 0
|
||||
property real saturationHSL: 0
|
||||
property real saturationHSV: 0
|
||||
property real lightness: 0
|
||||
property real value: 0
|
||||
|
||||
property real alpha: 1
|
||||
|
||||
property bool achromatic: false
|
||||
|
||||
property int sliderMargins: 6
|
||||
|
||||
property bool block: false
|
||||
|
||||
signal updateColor
|
||||
@@ -46,30 +57,84 @@ Column {
|
||||
|
||||
spacing: 10
|
||||
|
||||
onAlphaChanged: invalidateColor()
|
||||
onSaturationChanged: invalidateColor()
|
||||
onLightnessChanged: invalidateColor()
|
||||
onHueChanged: invalidateColor()
|
||||
onColorChanged: {
|
||||
var myAlpha = root.color.a
|
||||
rgbToHsl(root.color)
|
||||
root.alpha = myAlpha
|
||||
onModeChanged: {
|
||||
switch (root.mode) {
|
||||
case ColorPicker.Mode.RGBA:
|
||||
root.color = Qt.rgba(root.color.r, root.color.g, root.color.b, root.alpha)
|
||||
break
|
||||
case ColorPicker.Mode.HSLA:
|
||||
root.color = Qt.hsla(root.hue, root.saturationHSL, root.lightness, root.alpha)
|
||||
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() {
|
||||
if (root.block)
|
||||
return
|
||||
|
||||
root.block = true
|
||||
|
||||
root.color = Qt.hsla(root.hue,
|
||||
root.saturation,
|
||||
root.lightness,
|
||||
root.alpha)
|
||||
if (root.color.hsvSaturation > 0.0
|
||||
&& root.color.hsvValue > 0.0
|
||||
&& root.color.hsvHue !== -1.0)
|
||||
root.hue = root.color.hsvHue
|
||||
|
||||
if (root.saturation > 0.0 && root.lightness > 0.0)
|
||||
hueSlider.value = root.hue
|
||||
if (root.color.hslSaturation > 0.0
|
||||
&& 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)
|
||||
|
||||
root.colorInvalidated()
|
||||
@@ -77,39 +142,51 @@ Column {
|
||||
root.block = false
|
||||
}
|
||||
|
||||
function rgbToHsl(color) {
|
||||
var r = color.r
|
||||
var g = color.g
|
||||
var b = color.b
|
||||
function drawHSVA(ctx) {
|
||||
for (var row = 0; row < gradientOverlay.height; row++) {
|
||||
var gradient = ctx.createLinearGradient(0, 0, gradientOverlay.width, 0)
|
||||
var v = Math.abs(row - gradientOverlay.height) / gradientOverlay.height
|
||||
|
||||
var max = Math.max(r, g, b), min = Math.min(r, g, b)
|
||||
var h, s, l = (max + min) / 2
|
||||
gradient.addColorStop(0, Qt.hsva(root.hue, 0, v, 1))
|
||||
gradient.addColorStop(1, Qt.hsva(root.hue, 1, v, 1))
|
||||
|
||||
if (max === min) {
|
||||
h = 0
|
||||
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
|
||||
ctx.fillStyle = gradient
|
||||
ctx.fillRect(0, row, gradientOverlay.width, 1)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
root.hue = h
|
||||
ctx.fillStyle = gradient
|
||||
ctx.fillRect(0, 0, gradientOverlay.width, gradientOverlay.height)
|
||||
|
||||
root.saturation = s
|
||||
root.lightness = l
|
||||
gradient = ctx.createLinearGradient(0, 0, 0, gradientOverlay.height)
|
||||
gradient.addColorStop(0.000, Qt.rgba(0, 0, 0, 0))
|
||||
gradient.addColorStop(1.000, Qt.rgba(1, 1, 1, 1))
|
||||
|
||||
root.block = false
|
||||
invalidateColor()
|
||||
ctx.fillStyle = gradient
|
||||
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 {
|
||||
@@ -133,26 +210,30 @@ Column {
|
||||
Canvas {
|
||||
id: gradientOverlay
|
||||
|
||||
property real hue: root.hue
|
||||
|
||||
anchors.fill: parent
|
||||
opacity: root.alpha
|
||||
opacity: root.color.a
|
||||
|
||||
Connections {
|
||||
target: root
|
||||
function onHueChanged() { gradientOverlay.requestPaint() }
|
||||
}
|
||||
|
||||
onHueChanged: requestPaint()
|
||||
onPaint: {
|
||||
var ctx = gradientOverlay.getContext('2d')
|
||||
ctx.save()
|
||||
ctx.clearRect(0, 0, gradientOverlay.width, gradientOverlay.height)
|
||||
|
||||
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(gradientOverlay.hue, 0, l, 1))
|
||||
gradient.addColorStop(1, Qt.hsla(gradientOverlay.hue, 1, l, 1))
|
||||
|
||||
ctx.fillStyle = gradient
|
||||
ctx.fillRect(0, row, gradientOverlay.width, 1)
|
||||
switch (root.mode) {
|
||||
case ColorPicker.Mode.RGBA:
|
||||
root.drawRGBA(ctx)
|
||||
break
|
||||
case ColorPicker.Mode.HSLA:
|
||||
root.drawHSLA(ctx)
|
||||
break
|
||||
case ColorPicker.Mode.HSVA:
|
||||
default:
|
||||
root.drawHSVA(ctx)
|
||||
break
|
||||
}
|
||||
|
||||
ctx.restore()
|
||||
@@ -162,25 +243,41 @@ Column {
|
||||
Canvas {
|
||||
id: pickerCross
|
||||
|
||||
property real cavnasSaturation: root.saturation
|
||||
property real canvasLightness: root.lightness
|
||||
property color strokeStyle: "lightGray"
|
||||
|
||||
opacity: 0.8
|
||||
anchors.fill: parent
|
||||
antialiasing: true
|
||||
|
||||
onCavnasSaturationChanged: requestPaint();
|
||||
onCanvasLightnessChanged: requestPaint();
|
||||
Connections {
|
||||
target: root
|
||||
function onColorInvalidated() { pickerCross.requestPaint() }
|
||||
function onColorChanged() { pickerCross.requestPaint() }
|
||||
function onModeChanged() { pickerCross.requestPaint() }
|
||||
}
|
||||
|
||||
onPaint: {
|
||||
var ctx = pickerCross.getContext('2d')
|
||||
|
||||
ctx.save()
|
||||
|
||||
ctx.clearRect(0, 0, pickerCross.width, pickerCross.height)
|
||||
|
||||
var yy = pickerCross.height -root.lightness * pickerCross.height
|
||||
var xx = root.saturation * pickerCross.width
|
||||
var yy, xx = 0
|
||||
|
||||
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.lineWidth = 1
|
||||
@@ -200,24 +297,37 @@ Column {
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mapMouseArea
|
||||
id: mouseArea
|
||||
|
||||
anchors.fill: parent
|
||||
preventStealing: true
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
|
||||
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 yy = Math.max(0, Math.min(mouse.y, parent.height))
|
||||
|
||||
root.lightness = 1.0 - yy / parent.height
|
||||
root.saturation = xx / parent.width
|
||||
switch (root.mode) {
|
||||
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) {
|
||||
if (mouse.button === Qt.LeftButton)
|
||||
positionChanged(mouse)
|
||||
mouseArea.positionChanged(mouse)
|
||||
}
|
||||
onReleased: function(mouse) {
|
||||
if (mouse.button === Qt.LeftButton)
|
||||
@@ -233,10 +343,23 @@ Column {
|
||||
|
||||
HueSlider {
|
||||
id: hueSlider
|
||||
visible: root.mode !== ColorPicker.Mode.RGBA
|
||||
width: parent.width
|
||||
onValueChanged: {
|
||||
if (root.hue !== value)
|
||||
root.hue = value
|
||||
if (root.hue !== hueSlider.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()
|
||||
}
|
||||
@@ -246,8 +369,8 @@ Column {
|
||||
width: parent.width
|
||||
color: Qt.rgba(root.color.r, root.color.g, root.color.b, 1)
|
||||
onValueChanged: {
|
||||
if (root.alpha !== value)
|
||||
root.alpha = (1.0 - value)
|
||||
if (root.alpha !== opacitySlider.value)
|
||||
root.alpha = (1.0 - opacitySlider.value)
|
||||
}
|
||||
onClicked: root.updateColor()
|
||||
}
|
||||
|
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -45,6 +45,7 @@ Label 2.0 Label.qml
|
||||
LineEdit 2.0 LineEdit.qml
|
||||
LinkIndicator2D 2.0 LinkIndicator2D.qml
|
||||
ListViewComboBox 2.0 ListViewComboBox.qml
|
||||
LuminanceSlider 2.0 LuminanceSlider.qml
|
||||
MarginSection 2.0 MarginSection.qml
|
||||
MultiIconLabel 2.0 MultiIconLabel.qml
|
||||
OpacitySlider 2.0 OpacitySlider.qml
|
||||
|
@@ -52,6 +52,7 @@ add_qtc_library(Utils
|
||||
filecrumblabel.cpp filecrumblabel.h
|
||||
fileinprojectfinder.cpp fileinprojectfinder.h
|
||||
filenamevalidatinglineedit.cpp filenamevalidatinglineedit.h
|
||||
filepath.cpp filepath.h
|
||||
filesearch.cpp filesearch.h
|
||||
filesystemwatcher.cpp filesystemwatcher.h
|
||||
fileutils.cpp fileutils.h
|
||||
|
1295
src/libs/utils/filepath.cpp
Normal file
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
193
src/libs/utils/filepath.h
Normal 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
@@ -27,6 +27,7 @@
|
||||
|
||||
#include "utils_global.h"
|
||||
|
||||
#include "filepath.h"
|
||||
#include "hostosinfo.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
@@ -40,33 +41,17 @@
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
namespace Utils {
|
||||
class Environment;
|
||||
class FilePath;
|
||||
} // Utils
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QDataStream;
|
||||
class QDateTime;
|
||||
class QDir;
|
||||
class QFile;
|
||||
class QFileInfo;
|
||||
class QTemporaryFile;
|
||||
class QTextStream;
|
||||
class QWidget;
|
||||
|
||||
QTCREATOR_UTILS_EXPORT QDebug operator<<(QDebug dbg, const Utils::FilePath &c);
|
||||
|
||||
// for withNtfsPermissions
|
||||
#ifdef Q_OS_WIN
|
||||
extern Q_CORE_EXPORT int qt_ntfs_permission_lookup;
|
||||
#endif
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
// tst_fileutils becomes a friend of Utils::FilePath for testing private method
|
||||
class tst_fileutils;
|
||||
|
||||
namespace Utils {
|
||||
|
||||
class DeviceFileHooks
|
||||
@@ -99,152 +84,6 @@ public:
|
||||
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 {
|
||||
public:
|
||||
#ifdef QT_GUI_LIB
|
||||
@@ -287,6 +126,8 @@ public:
|
||||
static QByteArray fileId(const FilePath &fileName);
|
||||
static FilePath homePath();
|
||||
static bool renameFile(const FilePath &srcFilePath, const FilePath &tgtFilePath);
|
||||
|
||||
static void setDeviceFileHooks(const DeviceFileHooks &hooks);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
@@ -432,6 +273,8 @@ private:
|
||||
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); }
|
||||
|
||||
} // namespace Utils
|
||||
@@ -445,4 +288,3 @@ template<> struct QTCREATOR_UTILS_EXPORT hash<Utils::FilePath>
|
||||
};
|
||||
} // namespace std
|
||||
|
||||
Q_DECLARE_METATYPE(Utils::FilePath)
|
||||
|
@@ -554,7 +554,13 @@ void QtcProcess::start()
|
||||
{
|
||||
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()) {
|
||||
QTC_ASSERT(s_deviceHooks.startProcessHook, return);
|
||||
@@ -1219,6 +1225,7 @@ void QtcProcess::setExitCodeInterpreter(const ExitCodeInterpreter &interpreter)
|
||||
void QtcProcess::setWriteData(const QByteArray &writeData)
|
||||
{
|
||||
d->m_writeData = writeData;
|
||||
setKeepWriteChannelOpen();
|
||||
}
|
||||
|
||||
#ifdef QT_GUI_LIB
|
||||
@@ -1231,11 +1238,9 @@ static bool isGuiThread()
|
||||
void QtcProcess::runBlocking()
|
||||
{
|
||||
// FIXME: Implement properly
|
||||
|
||||
if (d->m_commandLine.executable().needsDevice()) {
|
||||
|
||||
// writeData ?
|
||||
QtcProcess::start();
|
||||
|
||||
waitForFinished();
|
||||
return;
|
||||
};
|
||||
|
@@ -62,6 +62,7 @@ SOURCES += \
|
||||
$$PWD/fancylineedit.cpp \
|
||||
$$PWD/qtcolorbutton.cpp \
|
||||
$$PWD/savefile.cpp \
|
||||
$$PWD/filepath.cpp \
|
||||
$$PWD/fileutils.cpp \
|
||||
$$PWD/textfileformat.cpp \
|
||||
$$PWD/consoleprocess.cpp \
|
||||
@@ -196,6 +197,7 @@ HEADERS += \
|
||||
$$PWD/qtcolorbutton.h \
|
||||
$$PWD/consoleprocess.h \
|
||||
$$PWD/savefile.h \
|
||||
$$PWD/filepath.h \
|
||||
$$PWD/fileutils.h \
|
||||
$$PWD/textfileformat.h \
|
||||
$$PWD/uncommentselection.h \
|
||||
|
@@ -115,6 +115,8 @@ Project {
|
||||
"fileinprojectfinder.h",
|
||||
"filenamevalidatinglineedit.cpp",
|
||||
"filenamevalidatinglineedit.h",
|
||||
"filepath.cpp",
|
||||
"filepath.h",
|
||||
"filesearch.cpp",
|
||||
"filesearch.h",
|
||||
"filesystemwatcher.cpp",
|
||||
|
@@ -1066,13 +1066,20 @@ AndroidDeviceInfo AndroidConfigurations::showDeviceDialog(Project *project,
|
||||
if (!serialNumber.isEmpty())
|
||||
break;
|
||||
}
|
||||
|
||||
const AndroidDeviceInfo defaultDevice = AndroidDeviceDialog::defaultDeviceInfo(serialNumber);
|
||||
if (defaultDevice.isValid())
|
||||
return defaultDevice;
|
||||
|
||||
AndroidDeviceDialog dialog(apiLevel, abis, serialNumber, Core::ICore::dialogParent());
|
||||
AndroidDeviceInfo info = dialog.device();
|
||||
AndroidDeviceInfo info = dialog.showAndGetSelectedDevice();
|
||||
if (dialog.saveDeviceSelection() && info.isValid()) {
|
||||
const QString serialNumber = info.type == AndroidDeviceInfo::Hardware ?
|
||||
const QString newSerialNumber = info.type == AndroidDeviceInfo::Hardware ?
|
||||
info.serialNumber : info.avdname;
|
||||
if (!serialNumber.isEmpty())
|
||||
AndroidConfigurations::setDefaultDevice(project, AndroidManager::devicePreferredAbi(info.cpuAbi, abis), serialNumber);
|
||||
if (!newSerialNumber.isEmpty()) {
|
||||
const QString preferredAbi = AndroidManager::devicePreferredAbi(info.cpuAbi, abis);
|
||||
AndroidConfigurations::setDefaultDevice(project, preferredAbi, newSerialNumber);
|
||||
}
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
@@ -44,6 +44,8 @@ using namespace Android::Internal;
|
||||
namespace Android {
|
||||
namespace Internal {
|
||||
|
||||
QVector<AndroidDeviceInfo> AndroidDeviceDialog::m_connectedDevices = {};
|
||||
|
||||
// yeah, writing tree models is fun!
|
||||
class AndroidDeviceModelNode
|
||||
{
|
||||
@@ -481,26 +483,30 @@ AndroidDeviceDialog::~AndroidDeviceDialog()
|
||||
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();
|
||||
|
||||
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)
|
||||
return m_model->device(m_ui->deviceView->currentIndex());
|
||||
return AndroidDeviceInfo();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
bool AndroidDeviceDialog::saveDeviceSelection() const
|
||||
@@ -508,11 +514,16 @@ bool AndroidDeviceDialog::saveDeviceSelection() const
|
||||
return m_ui->defaultDeviceCheckBox->isChecked();
|
||||
}
|
||||
|
||||
void AndroidDeviceDialog::updateConnectedDevicesList()
|
||||
{
|
||||
m_connectedDevices = AndroidConfig::connectedDevices(AndroidConfigurations::currentConfig()
|
||||
.adbToolPath());
|
||||
}
|
||||
|
||||
void AndroidDeviceDialog::refreshDeviceList()
|
||||
{
|
||||
m_ui->refreshDevicesButton->setEnabled(false);
|
||||
m_progressIndicator->show();
|
||||
m_connectedDevices = AndroidConfig::connectedDevices(AndroidConfigurations::currentConfig().adbToolPath());
|
||||
m_futureWatcherRefreshDevices.setFuture(m_avdManager->avdList());
|
||||
}
|
||||
|
||||
|
@@ -56,7 +56,8 @@ public:
|
||||
const QString &serialNumber, QWidget *parent = nullptr);
|
||||
~AndroidDeviceDialog() override;
|
||||
|
||||
AndroidDeviceInfo device();
|
||||
AndroidDeviceInfo showAndGetSelectedDevice();
|
||||
static AndroidDeviceInfo defaultDeviceInfo(const QString &serialNumber);
|
||||
|
||||
bool saveDeviceSelection() const;
|
||||
|
||||
@@ -68,6 +69,7 @@ private:
|
||||
void devicesRefreshed();
|
||||
void enableOkayButton();
|
||||
void defaultDeviceClear();
|
||||
static void updateConnectedDevicesList();
|
||||
|
||||
AndroidDeviceModel *m_model;
|
||||
Ui::AndroidDeviceDialog *m_ui;
|
||||
@@ -76,8 +78,8 @@ private:
|
||||
QStringList m_abis;
|
||||
QString m_avdNameFromAdd;
|
||||
QString m_defaultDevice;
|
||||
static QVector<AndroidDeviceInfo> m_connectedDevices;
|
||||
std::unique_ptr<AndroidAvdManager> m_avdManager;
|
||||
QVector<AndroidDeviceInfo> m_connectedDevices;
|
||||
QFutureWatcher<CreateAvdInfo> m_futureWatcherAddDevice;
|
||||
QFutureWatcher<AndroidDeviceInfoList> m_futureWatcherRefreshDevices;
|
||||
};
|
||||
|
@@ -515,7 +515,7 @@ void CMakeBuildSettingsWidget::batchEditConfiguration()
|
||||
[expander](const QString &s) {
|
||||
return expander->expand(s);
|
||||
});
|
||||
const CMakeConfig config = CMakeConfigItem::itemsFromArguments(expandedLines);
|
||||
const CMakeConfig config = CMakeConfig::fromArguments(expandedLines);
|
||||
|
||||
m_configModel->setBatchEditConfiguration(config);
|
||||
});
|
||||
@@ -1048,7 +1048,7 @@ bool CMakeBuildConfiguration::fromMap(const QVariantMap &map)
|
||||
}();
|
||||
if (initialCMakeArguments().isEmpty()) {
|
||||
QStringList initialArgs = defaultInitialCMakeArguments(kit(), buildTypeName)
|
||||
+ Utils::transform(conf, [this](const CMakeConfigItem &i) {
|
||||
+ Utils::transform(conf.toList(), [this](const CMakeConfigItem &i) {
|
||||
return i.toArgument(macroExpander());
|
||||
});
|
||||
|
||||
@@ -1110,7 +1110,8 @@ CMakeConfig CMakeBuildConfiguration::configurationChanges() 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
|
||||
@@ -1296,9 +1297,9 @@ BuildInfo CMakeBuildConfigurationFactory::createBuildInfo(BuildType buildType)
|
||||
|
||||
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()) {
|
||||
QByteArray cmakeCfgTypes = CMakeConfigItem::valueOf("CMAKE_CONFIGURATION_TYPES", m_configurationFromCMake);
|
||||
QByteArray cmakeCfgTypes = m_configurationFromCMake.valueOf("CMAKE_CONFIGURATION_TYPES");
|
||||
if (!cmakeCfgTypes.isEmpty())
|
||||
cmakeBuildTypeName = cmakeBuildType().toUtf8();
|
||||
}
|
||||
@@ -1352,14 +1353,14 @@ QString CMakeBuildConfiguration::cmakeBuildType() const
|
||||
QString errorMessage;
|
||||
config = CMakeBuildSystem::parseCMakeCacheDotTxt(cmakeCacheTxt, &errorMessage);
|
||||
} else {
|
||||
config = CMakeConfigItem::itemsFromArguments(initialCMakeArguments());
|
||||
config = CMakeConfig::fromArguments(initialCMakeArguments());
|
||||
}
|
||||
} else if (!hasCMakeCache) {
|
||||
config = CMakeConfigItem::itemsFromArguments(initialCMakeArguments());
|
||||
config = CMakeConfig::fromArguments(initialCMakeArguments());
|
||||
}
|
||||
|
||||
if (!config.isEmpty() && !isMultiConfig()) {
|
||||
cmakeBuildType = CMakeConfigItem::stringValueOf("CMAKE_BUILD_TYPE", config);
|
||||
cmakeBuildType = config.stringValueOf("CMAKE_BUILD_TYPE");
|
||||
const_cast<CMakeBuildConfiguration*>(this)->setCMakeBuildType(cmakeBuildType);
|
||||
}
|
||||
|
||||
|
@@ -838,7 +838,7 @@ void CMakeBuildSystem::wireUpConnections()
|
||||
QString errorMessage;
|
||||
const CMakeConfig config = CMakeBuildSystem::parseCMakeCacheDotTxt(cmakeCacheTxt, &errorMessage);
|
||||
if (!config.isEmpty() && errorMessage.isEmpty()) {
|
||||
QString cmakeBuildTypeName = CMakeConfigItem::stringValueOf("CMAKE_BUILD_TYPE", config);
|
||||
QString cmakeBuildTypeName = config.stringValueOf("CMAKE_BUILD_TYPE");
|
||||
cmakeBuildConfiguration()->setCMakeBuildType(cmakeBuildTypeName, true);
|
||||
}
|
||||
}
|
||||
@@ -1057,7 +1057,7 @@ CMakeConfig CMakeBuildSystem::parseCMakeCacheDotTxt(const Utils::FilePath &cache
|
||||
*errorMessage = tr("CMakeCache.txt file not found.");
|
||||
return {};
|
||||
}
|
||||
CMakeConfig result = CMakeConfigItem::itemsFromFile(cacheFile, errorMessage);
|
||||
CMakeConfig result = CMakeConfig::fromFile(cacheFile, errorMessage);
|
||||
if (!errorMessage->isEmpty())
|
||||
return {};
|
||||
return result;
|
||||
@@ -1210,7 +1210,7 @@ void CMakeBuildSystem::updateQmlJSCodeModel(const QStringList &extraHeaderPaths,
|
||||
};
|
||||
|
||||
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());
|
||||
|
||||
for (const QString &extraHeaderPath : extraHeaderPaths)
|
||||
@@ -1244,7 +1244,7 @@ void CMakeBuildSystem::updateInitialCMakeExpandableVars()
|
||||
{
|
||||
const CMakeConfig &cm = cmakeBuildConfiguration()->configurationFromCMake();
|
||||
const CMakeConfig &initialConfig =
|
||||
CMakeConfigItem::itemsFromArguments(cmakeBuildConfiguration()->initialCMakeArguments());
|
||||
CMakeConfig::fromArguments(cmakeBuildConfiguration()->initialCMakeArguments());
|
||||
|
||||
CMakeConfig config;
|
||||
|
||||
@@ -1275,7 +1275,7 @@ void CMakeBuildSystem::updateInitialCMakeExpandableVars()
|
||||
});
|
||||
|
||||
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 path = FilePath::fromString(QString::fromUtf8(it->value));
|
||||
|
||||
@@ -1299,20 +1299,23 @@ void CMakeBuildSystem::updateInitialCMakeExpandableVars()
|
||||
});
|
||||
|
||||
if (it != cm.cend()) {
|
||||
const QByteArray initialValue = CMakeConfigItem::expandedValueOf(kit(), var, initialConfig).toUtf8();
|
||||
const FilePath initialPath = FilePath::fromString(QString::fromUtf8(initialValue));
|
||||
const QByteArrayList initialValueList = initialConfig.expandedValueOf(kit(), var).toUtf8().split(';');
|
||||
|
||||
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);
|
||||
for (const auto &initialValue: initialValueList) {
|
||||
const FilePath initialPath = FilePath::fromString(QString::fromUtf8(initialValue));
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -55,29 +55,28 @@ CMakeConfigItem::CMakeConfigItem(const QByteArray &k, const QByteArray &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)
|
||||
return it->value;
|
||||
}
|
||||
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,
|
||||
const QList<CMakeConfigItem> &input)
|
||||
QString CMakeConfig::expandedValueOf(const ProjectExplorer::Kit *k, const QByteArray &key) const
|
||||
{
|
||||
for (auto it = input.constBegin(); it != input.constEnd(); ++it) {
|
||||
for (auto it = constBegin(); it != constEnd(); ++it) {
|
||||
if (it->key == key)
|
||||
return it->expandedValue(k);
|
||||
}
|
||||
@@ -312,7 +311,7 @@ static CMakeConfigItem unsetItemFromString(const QString &input)
|
||||
return item;
|
||||
}
|
||||
|
||||
QList<CMakeConfigItem> CMakeConfigItem::itemsFromArguments(const QStringList &list)
|
||||
CMakeConfig CMakeConfig::fromArguments(const QStringList &list)
|
||||
{
|
||||
CMakeConfig result;
|
||||
bool inSet = false;
|
||||
@@ -348,7 +347,7 @@ QList<CMakeConfigItem> CMakeConfigItem::itemsFromArguments(const QStringList &li
|
||||
return result;
|
||||
}
|
||||
|
||||
QList<CMakeConfigItem> CMakeConfigItem::itemsFromFile(const Utils::FilePath &cacheFile, QString *errorMessage)
|
||||
CMakeConfig CMakeConfig::fromFile(const Utils::FilePath &cacheFile, QString *errorMessage)
|
||||
{
|
||||
CMakeConfig result;
|
||||
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;
|
||||
}
|
||||
|
||||
uint qHash(const CMakeConfigItem &it)
|
||||
{
|
||||
return ::qHash(it.key) ^ ::qHash(it.value) ^ ::qHash(it.isUnset);
|
||||
}
|
||||
|
||||
#if WITH_TESTS
|
||||
|
||||
} // namespace CMakeProjectManager
|
||||
|
@@ -43,18 +43,14 @@ class Kit;
|
||||
|
||||
namespace CMakeProjectManager {
|
||||
|
||||
class CMAKE_EXPORT CMakeConfigItem {
|
||||
class CMAKE_EXPORT CMakeConfigItem
|
||||
{
|
||||
public:
|
||||
enum Type { FILEPATH, PATH, BOOL, STRING, INTERNAL, STATIC, UNINITIALIZED };
|
||||
CMakeConfigItem();
|
||||
CMakeConfigItem(const QByteArray &k, Type t, const QByteArray &d, const QByteArray &v, const QStringList &s = {});
|
||||
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 Type typeStringToType(const QByteArray &typeString);
|
||||
static QString typeToTypeString(const Type t);
|
||||
@@ -66,8 +62,6 @@ public:
|
||||
|
||||
static bool less(const CMakeConfigItem &a, const CMakeConfigItem &b);
|
||||
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 toArgument(const Utils::MacroExpander *expander = nullptr) const;
|
||||
QString toCMakeSetLine(const Utils::MacroExpander *expander = nullptr) const;
|
||||
@@ -83,6 +77,25 @@ public:
|
||||
QByteArray documentation;
|
||||
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
|
||||
|
@@ -996,15 +996,15 @@ void CMakeConfigurationKitAspect::setConfiguration(Kit *k, const CMakeConfig &co
|
||||
{
|
||||
if (!k)
|
||||
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);
|
||||
}
|
||||
|
||||
QStringList CMakeConfigurationKitAspect::toStringList(const Kit *k)
|
||||
{
|
||||
QStringList current
|
||||
= Utils::transform(CMakeConfigurationKitAspect::configuration(k),
|
||||
[](const CMakeConfigItem &i) { return i.toString(); });
|
||||
QStringList current = Utils::transform(CMakeConfigurationKitAspect::configuration(k).toList(),
|
||||
[](const CMakeConfigItem &i) { return i.toString(); });
|
||||
current = Utils::filtered(current, [](const QString &s) { return !s.isEmpty(); });
|
||||
Utils::sort(current);
|
||||
return current;
|
||||
@@ -1023,7 +1023,7 @@ void CMakeConfigurationKitAspect::fromStringList(Kit *k, const QStringList &in)
|
||||
|
||||
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); });
|
||||
}
|
||||
|
||||
@@ -1046,8 +1046,8 @@ QVariant CMakeConfigurationKitAspect::defaultValue(const Kit *k) const
|
||||
{
|
||||
// FIXME: Convert preload scripts
|
||||
CMakeConfig config = defaultConfiguration(k);
|
||||
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(); });
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
@@ -135,20 +135,16 @@ QStringList CMakeProjectImporter::importCandidates()
|
||||
static FilePath qmakeFromCMakeCache(const CMakeConfig &config)
|
||||
{
|
||||
// Qt4 way to define things (more convenient for us, so try this first;-)
|
||||
FilePath qmake
|
||||
= FilePath::fromUtf8(CMakeConfigItem::valueOf(QByteArray("QT_QMAKE_EXECUTABLE"), config));
|
||||
const FilePath qmake = config.filePathValueOf("QT_QMAKE_EXECUTABLE");
|
||||
qCDebug(cmInputLog) << "QT_QMAKE_EXECUTABLE=" << qmake.toUserOutput();
|
||||
if (!qmake.isEmpty())
|
||||
return qmake;
|
||||
|
||||
// Check Qt5 settings: oh, the horror!
|
||||
const FilePath qtCMakeDir = [config] {
|
||||
FilePath tmp = FilePath::fromUtf8(
|
||||
CMakeConfigItem::valueOf(QByteArray("Qt5Core_DIR"), config));
|
||||
if (tmp.isEmpty()) {
|
||||
tmp = FilePath::fromUtf8(
|
||||
CMakeConfigItem::valueOf(QByteArray("Qt6Core_DIR"), config));
|
||||
}
|
||||
FilePath tmp = config.filePathValueOf("Qt5Core_DIR");
|
||||
if (tmp.isEmpty())
|
||||
tmp = config.filePathValueOf("Qt6Core_DIR");
|
||||
return tmp;
|
||||
}();
|
||||
qCDebug(cmInputLog) << "QtXCore_DIR=" << qtCMakeDir.toUserOutput();
|
||||
@@ -206,11 +202,11 @@ static FilePath qmakeFromCMakeCache(const CMakeConfig &config)
|
||||
cmake.setEnvironment(env);
|
||||
cmake.setTimeOutMessageBoxEnabled(false);
|
||||
|
||||
QString cmakeGenerator = CMakeConfigItem::stringValueOf(QByteArray("CMAKE_GENERATOR"), config);
|
||||
FilePath cmakeExecutable = CMakeConfigItem::filePathValueOf(QByteArray("CMAKE_COMMAND"), config);
|
||||
FilePath cmakeMakeProgram =CMakeConfigItem::filePathValueOf(QByteArray("CMAKE_MAKE_PROGRAM"), config);
|
||||
FilePath toolchainFile = CMakeConfigItem::filePathValueOf(QByteArray("CMAKE_TOOLCHAIN_FILE"), config);
|
||||
FilePath hostPath = CMakeConfigItem::filePathValueOf(QByteArray("QT_HOST_PATH"), config);
|
||||
QString cmakeGenerator = config.stringValueOf(QByteArray("CMAKE_GENERATOR"));
|
||||
FilePath cmakeExecutable = config.filePathValueOf(QByteArray("CMAKE_COMMAND"));
|
||||
FilePath cmakeMakeProgram = config.filePathValueOf(QByteArray("CMAKE_MAKE_PROGRAM"));
|
||||
FilePath toolchainFile = config.filePathValueOf(QByteArray("CMAKE_TOOLCHAIN_FILE"));
|
||||
FilePath hostPath = config.filePathValueOf(QByteArray("QT_HOST_PATH"));
|
||||
|
||||
QStringList args;
|
||||
args.push_back("-S");
|
||||
@@ -270,7 +266,7 @@ static QVector<ToolChainDescription> extractToolChainsFromCache(const CMakeConfi
|
||||
}
|
||||
|
||||
if (!haveCCxxCompiler) {
|
||||
const QByteArray generator = CMakeConfigItem::valueOf(QByteArray("CMAKE_GENERATOR"), config);
|
||||
const QByteArray generator = config.valueOf("CMAKE_GENERATOR");
|
||||
QString cCompilerName;
|
||||
QString cxxCompilerName;
|
||||
if (generator.contains("Visual Studio")) {
|
||||
@@ -282,8 +278,7 @@ static QVector<ToolChainDescription> extractToolChainsFromCache(const CMakeConfi
|
||||
}
|
||||
|
||||
if (!cCompilerName.isEmpty() && !cxxCompilerName.isEmpty()) {
|
||||
const FilePath linker = FilePath::fromUtf8(
|
||||
CMakeConfigItem::valueOf(QByteArray("CMAKE_LINKER"), config));
|
||||
const FilePath linker = config.filePathValueOf("CMAKE_LINKER");
|
||||
if (!linker.isEmpty()) {
|
||||
const FilePath compilerPath = linker.parentDir();
|
||||
result.append({compilerPath.pathAppended(cCompilerName),
|
||||
@@ -315,13 +310,11 @@ QList<void *> CMakeProjectImporter::examineDirectory(const FilePath &importPath,
|
||||
return { };
|
||||
}
|
||||
|
||||
QByteArrayList buildConfigurationTypes = {CMakeConfigItem::valueOf("CMAKE_BUILD_TYPE", config)};
|
||||
QByteArrayList buildConfigurationTypes = {config.valueOf("CMAKE_BUILD_TYPE")};
|
||||
if (buildConfigurationTypes.front().isEmpty()) {
|
||||
QByteArray buildConfigurationTypesString =
|
||||
CMakeConfigItem::valueOf("CMAKE_CONFIGURATION_TYPES", config);
|
||||
if (!buildConfigurationTypesString.isEmpty()) {
|
||||
QByteArray buildConfigurationTypesString = config.valueOf("CMAKE_CONFIGURATION_TYPES");
|
||||
if (!buildConfigurationTypesString.isEmpty())
|
||||
buildConfigurationTypes = buildConfigurationTypesString.split(';');
|
||||
}
|
||||
}
|
||||
|
||||
QList<void *> result;
|
||||
@@ -329,7 +322,7 @@ QList<void *> CMakeProjectImporter::examineDirectory(const FilePath &importPath,
|
||||
auto data = std::make_unique<DirectoryData>();
|
||||
|
||||
data->cmakeHomeDirectory =
|
||||
FilePath::fromUserInput(CMakeConfigItem::stringValueOf("CMAKE_HOME_DIRECTORY", config))
|
||||
FilePath::fromUserInput(config.stringValueOf("CMAKE_HOME_DIRECTORY"))
|
||||
.canonicalPath();
|
||||
const FilePath canonicalProjectDirectory = projectDirectory().canonicalPath();
|
||||
if (data->cmakeHomeDirectory != canonicalProjectDirectory) {
|
||||
@@ -344,12 +337,12 @@ QList<void *> CMakeProjectImporter::examineDirectory(const FilePath &importPath,
|
||||
data->buildDirectory = importPath;
|
||||
data->cmakeBuildType = buildType;
|
||||
|
||||
data->cmakeBinary = CMakeConfigItem::filePathValueOf("CMAKE_COMMAND", config);
|
||||
data->generator = CMakeConfigItem::stringValueOf("CMAKE_GENERATOR", config);
|
||||
data->extraGenerator = CMakeConfigItem::stringValueOf("CMAKE_EXTRA_GENERATOR", config);
|
||||
data->platform = CMakeConfigItem::stringValueOf("CMAKE_GENERATOR_PLATFORM", config);
|
||||
data->toolset = CMakeConfigItem::stringValueOf("CMAKE_GENERATOR_TOOLSET", config);
|
||||
data->sysroot = CMakeConfigItem::filePathValueOf("CMAKE_SYSROOT", config);
|
||||
data->cmakeBinary = config.filePathValueOf("CMAKE_COMMAND");
|
||||
data->generator = config.stringValueOf("CMAKE_GENERATOR");
|
||||
data->extraGenerator = config.stringValueOf("CMAKE_EXTRA_GENERATOR");
|
||||
data->platform = config.stringValueOf("CMAKE_GENERATOR_PLATFORM");
|
||||
data->toolset = config.stringValueOf("CMAKE_GENERATOR_TOOLSET");
|
||||
data->sysroot = config.filePathValueOf("CMAKE_SYSROOT");
|
||||
|
||||
// Qt:
|
||||
const FilePath qmake = qmakeFromCMakeCache(config);
|
||||
|
@@ -203,7 +203,7 @@ QList<ConfigModel::DataItem> ConfigModel::configurationForCMake() const
|
||||
|
||||
void ConfigModel::setConfiguration(const CMakeConfig &config)
|
||||
{
|
||||
setConfiguration(Utils::transform(config, [](const CMakeConfigItem &i) {
|
||||
setConfiguration(Utils::transform(config.toList(), [](const CMakeConfigItem &i) {
|
||||
return DataItem(i);
|
||||
}));
|
||||
}
|
||||
|
@@ -337,7 +337,7 @@ void FileApiReader::writeConfigurationIntoBuildDirectory(const QStringList &conf
|
||||
QByteArray contents;
|
||||
contents.append("# This file is managed by Qt Creator, do not edit!\n\n");
|
||||
contents.append(
|
||||
transform(CMakeConfigItem::itemsFromArguments(configurationArguments),
|
||||
transform(CMakeConfig::fromArguments(configurationArguments).toList(),
|
||||
[](const CMakeConfigItem &item) {
|
||||
return item.toCMakeSetLine(nullptr);
|
||||
})
|
||||
|
@@ -69,6 +69,8 @@
|
||||
#include <QHeaderView>
|
||||
#include <QLoggingCategory>
|
||||
#include <QPushButton>
|
||||
#include <QRandomGenerator>
|
||||
#include <QRegularExpression>
|
||||
#include <QTextBrowser>
|
||||
#include <QToolButton>
|
||||
#include <QThread>
|
||||
@@ -304,9 +306,11 @@ public:
|
||||
});
|
||||
}
|
||||
|
||||
~DockerDevicePrivate() { delete m_shell; }
|
||||
~DockerDevicePrivate() { stopCurrentContainer(); }
|
||||
|
||||
bool runInContainer(const CommandLine &cmd) const;
|
||||
bool runInShell(const CommandLine &cmd) const;
|
||||
QString outputForRunInShell(const CommandLine &cmd) const;
|
||||
|
||||
void tryCreateLocalFileAccess();
|
||||
|
||||
@@ -318,6 +322,7 @@ public:
|
||||
|
||||
// For local file access
|
||||
QPointer<QtcProcess> m_shell;
|
||||
mutable QMutex m_shellMutex;
|
||||
QString m_container;
|
||||
QString m_mergedDir;
|
||||
QFileSystemWatcher m_mergedDirWatcher;
|
||||
@@ -359,12 +364,15 @@ public:
|
||||
auto daemonStateLabel = new QLabel(tr("Daemon state:"));
|
||||
m_daemonReset = new QToolButton;
|
||||
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] {
|
||||
dockerDevice->resetDaemonState();
|
||||
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"));
|
||||
@@ -403,10 +411,11 @@ public:
|
||||
|
||||
if (!dockerDevice->isDaemonRunning()) {
|
||||
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());
|
||||
} 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());
|
||||
|
||||
}
|
||||
@@ -427,7 +436,7 @@ public:
|
||||
Form {
|
||||
idLabel, m_idLineEdit, Break(),
|
||||
repoLabel, m_repoLineEdit, Break(),
|
||||
daemonStateLabel, m_daemonReset, Break(),
|
||||
daemonStateLabel, m_daemonReset, m_daemonState, Break(),
|
||||
m_runAsOutsideUser, Break(),
|
||||
tr("Paths to mount:"), m_pathsLineEdit, Break(),
|
||||
Column {
|
||||
@@ -445,6 +454,7 @@ private:
|
||||
QLineEdit *m_idLineEdit;
|
||||
QLineEdit *m_repoLineEdit;
|
||||
QToolButton *m_daemonReset;
|
||||
QLabel *m_daemonState;
|
||||
QCheckBox *m_runAsOutsideUser;
|
||||
QLineEdit *m_pathsLineEdit;
|
||||
|
||||
@@ -745,6 +755,20 @@ void DockerDevicePrivate::stopCurrentContainer()
|
||||
if (m_container.isEmpty() || m_accessible == NoDaemon)
|
||||
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;
|
||||
proc.setCommand({"docker", {"container", "stop", m_container}});
|
||||
|
||||
@@ -1019,7 +1043,7 @@ bool DockerDevice::isExecutableFile(const FilePath &filePath) const
|
||||
return res;
|
||||
}
|
||||
const QString path = filePath.path();
|
||||
return d->runInContainer({"test", {"-x", path}});
|
||||
return d->runInShell({"test", {"-x", path}});
|
||||
}
|
||||
|
||||
bool DockerDevice::isReadableFile(const FilePath &filePath) const
|
||||
@@ -1033,7 +1057,7 @@ bool DockerDevice::isReadableFile(const FilePath &filePath) const
|
||||
return res;
|
||||
}
|
||||
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
|
||||
@@ -1047,7 +1071,7 @@ bool DockerDevice::isWritableFile(const Utils::FilePath &filePath) const
|
||||
return res;
|
||||
}
|
||||
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
|
||||
@@ -1061,7 +1085,7 @@ bool DockerDevice::isReadableDirectory(const FilePath &filePath) const
|
||||
return res;
|
||||
}
|
||||
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
|
||||
@@ -1075,7 +1099,7 @@ bool DockerDevice::isWritableDirectory(const FilePath &filePath) const
|
||||
return res;
|
||||
}
|
||||
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
|
||||
@@ -1089,7 +1113,7 @@ bool DockerDevice::isFile(const FilePath &filePath) const
|
||||
return res;
|
||||
}
|
||||
const QString path = filePath.path();
|
||||
return d->runInContainer({"test", {"-f", path}});
|
||||
return d->runInShell({"test", {"-f", path}});
|
||||
}
|
||||
|
||||
bool DockerDevice::isDirectory(const FilePath &filePath) const
|
||||
@@ -1103,7 +1127,7 @@ bool DockerDevice::isDirectory(const FilePath &filePath) const
|
||||
return res;
|
||||
}
|
||||
const QString path = filePath.path();
|
||||
return d->runInContainer({"test", {"-d", path}});
|
||||
return d->runInShell({"test", {"-d", path}});
|
||||
}
|
||||
|
||||
bool DockerDevice::createDirectory(const FilePath &filePath) const
|
||||
@@ -1131,7 +1155,7 @@ bool DockerDevice::exists(const FilePath &filePath) const
|
||||
return res;
|
||||
}
|
||||
const QString path = filePath.path();
|
||||
return d->runInContainer({"test", {"-e", path}});
|
||||
return d->runInShell({"test", {"-e", path}});
|
||||
}
|
||||
|
||||
bool DockerDevice::ensureExistingFile(const FilePath &filePath) const
|
||||
@@ -1145,7 +1169,7 @@ bool DockerDevice::ensureExistingFile(const FilePath &filePath) const
|
||||
return res;
|
||||
}
|
||||
const QString path = filePath.path();
|
||||
return d->runInContainer({"touch", {path}});
|
||||
return d->runInShell({"touch", {path}});
|
||||
}
|
||||
|
||||
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);
|
||||
return res;
|
||||
}
|
||||
// Open this up only when really needed.
|
||||
// return d->runInContainer({"rm", "-rf", {filePath.path()}});
|
||||
return false;
|
||||
|
||||
const QString path = filePath.cleanPath().path();
|
||||
// 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
|
||||
@@ -1240,8 +1270,44 @@ FilePath DockerDevice::symLinkTarget(const FilePath &filePath) const
|
||||
return {};
|
||||
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,
|
||||
@@ -1258,13 +1324,9 @@ FilePaths DockerDevice::directoryEntries(const FilePath &filePath,
|
||||
});
|
||||
}
|
||||
|
||||
QtcProcess proc;
|
||||
proc.setCommand({"ls", {"-1", "-b", "--", filePath.path()}});
|
||||
runProcess(proc);
|
||||
proc.waitForFinished();
|
||||
|
||||
QStringList entries = proc.stdOut().split('\n', Qt::SkipEmptyParts);
|
||||
return FilePath::filterEntriesHelper(filePath, entries, nameFilters, filters, sort);
|
||||
const QString output = d->outputForRunInShell({"ls", {"-1", "-b", "--", filePath.path()}});
|
||||
QStringList entries = output.split('\n', Qt::SkipEmptyParts);
|
||||
return filterEntriesHelper(filePath, entries, nameFilters, filters, sort);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 {});
|
||||
tryCreateLocalFileAccess();
|
||||
if (hasLocalFileAccess())
|
||||
return mapToLocalAccess(filePath).writeFileContents(data);
|
||||
|
||||
QTC_CHECK(false); // FIXME: Implement
|
||||
return {};
|
||||
// This following would be the generic Unix solution.
|
||||
// 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
|
||||
@@ -1375,6 +1457,48 @@ bool DockerDevicePrivate::runInContainer(const CommandLine &cmd) const
|
||||
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
|
||||
|
||||
DockerDeviceFactory::DockerDeviceFactory()
|
||||
|
@@ -525,7 +525,7 @@ DeviceManager::DeviceManager(bool isInstance) : d(std::make_unique<DeviceManager
|
||||
return device->systemEnvironment();
|
||||
};
|
||||
|
||||
FilePath::setDeviceFileHooks(deviceHooks);
|
||||
FileUtils::setDeviceFileHooks(deviceHooks);
|
||||
|
||||
DeviceProcessHooks processHooks;
|
||||
|
||||
|
@@ -347,7 +347,7 @@ void ItemLibraryModel::update(ItemLibraryInfo *itemLibraryInfo, Model *model)
|
||||
importSection = importHash[entry.requiredImport()];
|
||||
|
||||
}
|
||||
} else if (catName == "My Quick3D Components") {
|
||||
} else if (catName == ItemLibraryImport::quick3DAssetsTitle()) {
|
||||
importSection = importHash[ItemLibraryImport::quick3DAssetsTitle()];
|
||||
} else {
|
||||
if (catName.startsWith("Qt Quick - "))
|
||||
|
@@ -79,6 +79,7 @@ extend_qtc_executable(sdktool
|
||||
DEFINES QTCREATOR_UTILS_STATIC_LIB
|
||||
SOURCES
|
||||
environment.cpp environment.h
|
||||
filepath.cpp filepath.h
|
||||
fileutils.cpp fileutils.h
|
||||
hostosinfo.cpp hostosinfo.h
|
||||
namevaluedictionary.cpp namevaluedictionary.h
|
||||
|
@@ -32,6 +32,7 @@ SOURCES += \
|
||||
rmtoolchainoperation.cpp \
|
||||
settings.cpp \
|
||||
$$UTILS/environment.cpp \
|
||||
$$UTILS/filepath.cpp \
|
||||
$$UTILS/fileutils.cpp \
|
||||
$$UTILS/hostosinfo.cpp \
|
||||
$$UTILS/namevaluedictionary.cpp \
|
||||
@@ -65,6 +66,7 @@ HEADERS += \
|
||||
rmtoolchainoperation.h \
|
||||
settings.h \
|
||||
$$UTILS/environment.h \
|
||||
$$UTILS/filepath.h \
|
||||
$$UTILS/fileutils.h \
|
||||
$$UTILS/hostosinfo.h \
|
||||
$$UTILS/namevaluedictionary.h \
|
||||
|
@@ -70,6 +70,7 @@ QtcTool {
|
||||
files: [
|
||||
"commandline.cpp", "commandline.h",
|
||||
"environment.cpp", "environment.h",
|
||||
"filepath.cpp", "filepath.h",
|
||||
"fileutils.cpp", "fileutils.h",
|
||||
"hostosinfo.cpp", "hostosinfo.h",
|
||||
"namevaluedictionary.cpp", "namevaluedictionary.h",
|
||||
|
@@ -19,6 +19,7 @@ HEADERS += \
|
||||
SOURCES += \
|
||||
$$UTILSDIR/commandline.cpp \
|
||||
$$UTILSDIR/environment.cpp \
|
||||
$$UTILSDIR/filepath.cpp \
|
||||
$$UTILSDIR/fileutils.cpp \
|
||||
$$UTILSDIR/hostosinfo.cpp \
|
||||
$$UTILSDIR/launcherinterface.cpp \
|
||||
@@ -34,6 +35,7 @@ HEADERS += \
|
||||
HEADERS += \
|
||||
$$UTILSDIR/commandline.h \
|
||||
$$UTILSDIR/environment.h \
|
||||
$$UTILSDIR/filepath.h \
|
||||
$$UTILSDIR/fileutils.h \
|
||||
$$UTILSDIR/hostosinfo.h \
|
||||
$$UTILSDIR/launcherinterface.h \
|
||||
|
Reference in New Issue
Block a user