Merge remote-tracking branch 'origin/qds-1.59'

Change-Id: I8a5d7d98b4d75379fe3953fe00bdb939d1722676
This commit is contained in:
Tim Jenssen
2020-04-28 16:18:24 +02:00
97 changed files with 4303 additions and 315 deletions

View File

@@ -121,7 +121,7 @@ View3D {
pick(mouse); pick(mouse);
if (pickObj) { if (pickObj) {
axisHelperView.editCameraCtrl.focusObject(axisHelperView.selectedNode, axisHelperView.editCameraCtrl.focusObject(axisHelperView.selectedNode,
pickObj.cameraRotation, false); pickObj.cameraRotation, false, false);
} else { } else {
mouse.accepted = false; mouse.accepted = false;
} }

View File

@@ -87,14 +87,15 @@ Item {
} }
function focusObject(targetObject, rotation, updateZoom) function focusObject(targetObject, rotation, updateZoom, closeUp)
{ {
if (!camera) if (!camera)
return; return;
camera.eulerRotation = rotation; camera.eulerRotation = rotation;
var newLookAtAndZoom = _generalHelper.focusObjectToCamera( var newLookAtAndZoom = _generalHelper.focusObjectToCamera(
camera, _defaultCameraLookAtDistance, targetObject, view3d, _zoomFactor, updateZoom); camera, _defaultCameraLookAtDistance, targetObject, view3d, _zoomFactor,
updateZoom, closeUp);
_lookAtPoint = newLookAtAndZoom.toVector3d(); _lookAtPoint = newLookAtAndZoom.toVector3d();
_zoomFactor = newLookAtAndZoom.w; _zoomFactor = newLookAtAndZoom.w;
storeCameraState(0); storeCameraState(0);

View File

@@ -146,7 +146,7 @@ Item {
if (editView) { if (editView) {
var targetNode = selectionBoxes.length > 0 var targetNode = selectionBoxes.length > 0
? selectionBoxes[0].model : null; ? selectionBoxes[0].model : null;
cameraControl.focusObject(targetNode, editView.camera.eulerRotation, true); cameraControl.focusObject(targetNode, editView.camera.eulerRotation, true, false);
} }
} }

View File

@@ -42,7 +42,7 @@ Item {
function fitAndHideBox() : bool function fitAndHideBox() : bool
{ {
cameraControl.focusObject(selectionBox.model, viewCamera.eulerRotation, true); cameraControl.focusObject(selectionBox.model, viewCamera.eulerRotation, true, true);
if (cameraControl._zoomFactor < 0.1) { if (cameraControl._zoomFactor < 0.1) {
view3D.importScene.scale = view3D.importScene.scale.times(10); view3D.importScene.scale = view3D.importScene.scale.times(10);
return false; return false;

View File

@@ -148,7 +148,7 @@ float GeneralHelper::zoomCamera(QQuick3DCamera *camera, float distance, float de
// Return value contains new lookAt point (xyz) and zoom factor (w) // Return value contains new lookAt point (xyz) and zoom factor (w)
QVector4D GeneralHelper::focusObjectToCamera(QQuick3DCamera *camera, float defaultLookAtDistance, QVector4D GeneralHelper::focusObjectToCamera(QQuick3DCamera *camera, float defaultLookAtDistance,
QQuick3DNode *targetObject, QQuick3DViewport *viewPort, QQuick3DNode *targetObject, QQuick3DViewport *viewPort,
float oldZoom, bool updateZoom) float oldZoom, bool updateZoom, bool closeUp)
{ {
if (!camera) if (!camera)
return QVector4D(0.f, 0.f, 0.f, 1.f); return QVector4D(0.f, 0.f, 0.f, 1.f);
@@ -200,7 +200,9 @@ QVector4D GeneralHelper::focusObjectToCamera(QQuick3DCamera *camera, float defau
camera->setPosition(lookAt + newLookVector); camera->setPosition(lookAt + newLookVector);
float newZoomFactor = updateZoom ? qBound(.01f, float(maxExtent / 900.), 100.f) : oldZoom; qreal divisor = closeUp ? 900. : 725.;
float newZoomFactor = updateZoom ? qBound(.01f, float(maxExtent / divisor), 100.f) : oldZoom;
float cameraZoomFactor = zoomCamera(camera, 0, defaultLookAtDistance, lookAt, newZoomFactor, false); float cameraZoomFactor = zoomCamera(camera, 0, defaultLookAtDistance, lookAt, newZoomFactor, false);
return QVector4D(lookAt, cameraZoomFactor); return QVector4D(lookAt, cameraZoomFactor);

View File

@@ -66,8 +66,9 @@ public:
float defaultLookAtDistance, const QVector3D &lookAt, float defaultLookAtDistance, const QVector3D &lookAt,
float zoomFactor, bool relative); float zoomFactor, bool relative);
Q_INVOKABLE QVector4D focusObjectToCamera(QQuick3DCamera *camera, float defaultLookAtDistance, Q_INVOKABLE QVector4D focusObjectToCamera(QQuick3DCamera *camera, float defaultLookAtDistance,
QQuick3DNode *targetObject, QQuick3DViewport *viewPort, QQuick3DNode *targetObject, QQuick3DViewport *viewPort,
float oldZoom, bool updateZoom = true); float oldZoom, bool updateZoom = true,
bool closeUp = false);
Q_INVOKABLE void delayedPropertySet(QObject *obj, int delay, const QString &property, Q_INVOKABLE void delayedPropertySet(QObject *obj, int delay, const QString &property,
const QVariant& value); const QVariant& value);
Q_INVOKABLE QQuick3DNode *resolvePick(QQuick3DNode *pickNode); Q_INVOKABLE QQuick3DNode *resolvePick(QQuick3DNode *pickNode);

View File

@@ -47,6 +47,8 @@ Item {
width: itemLibraryIconWidth // to be set in Qml context width: itemLibraryIconWidth // to be set in Qml context
height: itemLibraryIconHeight // to be set in Qml context height: itemLibraryIconHeight // to be set in Qml context
source: itemLibraryIconPath // to be set by model source: itemLibraryIconPath // to be set by model
cache: false // Allow thumbnail to be dynamically updated
} }
Text { Text {

View File

@@ -100,14 +100,17 @@ Section {
} }
Label { Label {
text: "State" text: qsTr("State")
} }
SecondColumnLayout { SecondColumnLayout {
LineEdit {
ComboBox {
Layout.fillWidth: true
backendValue: backendValues.state backendValue: backendValues.state
showTranslateCheckBox: false model: allStateNames
enabled: anchorBackend.hasParent || isBaseState valueType: ComboBox.String
} }
ExpandingSpacer { ExpandingSpacer {
} }
} }
@@ -158,5 +161,56 @@ Section {
} }
} }
Label {
text: qsTr("Focus")
tooltip: qsTr("Holds whether the item has focus within the enclosing FocusScope.")
disabledState: !backendValues.focus.isAvailable
}
SecondColumnLayout {
CheckBox {
backendValue: backendValues.focus
text: backendValues.focus.valueToString
enabled: backendValues.focus.isAvailable
implicitWidth: 180
}
ExpandingSpacer {
}
}
Label {
text: qsTr("Active focus on tab")
tooltip: qsTr("Holds whether the item wants to be in the tab focus chain.")
disabledState: !backendValues.activeFocusOnTab.isAvailable
}
SecondColumnLayout {
CheckBox {
backendValue: backendValues.activeFocusOnTab
text: backendValues.activeFocusOnTab.valueToString
enabled: backendValues.activeFocusOnTab.isAvailable
implicitWidth: 180
}
ExpandingSpacer {
}
}
Label {
text: qsTr("Baseline offset")
tooltip: qsTr("Specifies the position of the item's baseline in local coordinates.")
disabledState: !backendValues.baselineOffset.isAvailable
}
SecondColumnLayout {
SpinBox {
sliderIndicatorVisible: true
backendValue: backendValues.baselineOffset
hasSlider: true
decimals: 0
minimumValue: -1000
maximumValue: 1000
Layout.preferredWidth: 140
enabled: backendValues.baselineOffset.isAvailable
}
ExpandingSpacer {
}
}
} }
} }

View File

@@ -0,0 +1,95 @@
/****************************************************************************
**
** Copyright (C) 2016 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.1
import HelperWidgets 2.0
import QtQuick.Layouts 1.0
Column {
anchors.left: parent.left
anchors.right: parent.right
ImageSpecifics {
}
Section {
anchors.left: parent.left
anchors.right: parent.right
caption: qsTr("Animated Image")
SectionLayout {
Label {
text: qsTr("Speed")
disabledState: !backendValues.speed.isAvailable
}
SecondColumnLayout {
SpinBox {
sliderIndicatorVisible: true
backendValue: backendValues.speed
hasSlider: true
decimals: 2
minimumValue: 0
maximumValue: 100
Layout.preferredWidth: 140
enabled: backendValues.speed.isAvailable
}
ExpandingSpacer {
}
}
Label {
text: qsTr("Paused")
tooltip: qsTr("Holds whether the animated image is paused.")
disabledState: !backendValues.paused.isAvailable
}
SecondColumnLayout {
CheckBox {
enabled: backendValues.paused.isAvailable
text: backendValues.paused.valueToString
backendValue: backendValues.paused
implicitWidth: 180
}
ExpandingSpacer {}
}
Label {
text: qsTr("Playing")
tooltip: qsTr("Holds whether the animated image is playing.")
disabledState: !backendValues.playing.isAvailable
}
SecondColumnLayout {
CheckBox {
enabled: backendValues.playing.isAvailable
text: backendValues.playing.valueToString
backendValue: backendValues.playing
implicitWidth: 180
}
ExpandingSpacer {}
}
}
}
}

View File

@@ -124,7 +124,7 @@ Column {
} }
Label { Label {
text: qsTr("Horizontal Fill mode") text: qsTr("Horizontal Tile mode")
} }
SecondColumnLayout { SecondColumnLayout {
@@ -138,7 +138,7 @@ Column {
} }
Label { Label {
text: qsTr("Vertical Fill mode") text: qsTr("Vertical Tile mode")
} }
SecondColumnLayout { SecondColumnLayout {
@@ -186,6 +186,70 @@ Column {
} }
} }
Label {
text: qsTr("Mirror")
tooltip: qsTr("Specifies whether the image should be horizontally inverted.")
disabledState: !backendValues.mirror.isAvailable
}
SecondColumnLayout {
CheckBox {
enabled: backendValues.mirror.isAvailable
text: backendValues.mirror.valueToString
backendValue: backendValues.mirror
implicitWidth: 180
}
ExpandingSpacer {}
}
Label {
text: qsTr("Smooth")
tooltip: qsTr("Specifies whether the image is smoothly filtered when scaled or transformed.")
disabledState: !backendValues.smooth.isAvailable
}
SecondColumnLayout {
CheckBox {
enabled: backendValues.smooth.isAvailable
text: backendValues.smooth.valueToString
backendValue: backendValues.smooth
implicitWidth: 180
}
ExpandingSpacer {}
}
Label {
text: qsTr("Cache")
tooltip: qsTr("Specifies whether the image should be cached.")
disabledState: !backendValues.cache.isAvailable
}
SecondColumnLayout {
CheckBox {
enabled: backendValues.cache.isAvailable
text: backendValues.cache.valueToString
backendValue: backendValues.cache
implicitWidth: 180
}
ExpandingSpacer {}
}
Label {
text: qsTr("Asynchronous")
tooltip: qsTr("Specifies that images on the local filesystem should be loaded asynchronously in a separate thread.")
disabledState: !backendValues.asynchronous.isAvailable
}
SecondColumnLayout {
CheckBox {
enabled: backendValues.asynchronous.isAvailable
text: backendValues.asynchronous.valueToString
backendValue: backendValues.asynchronous
implicitWidth: 180
}
ExpandingSpacer {}
}
} }
} }
} }

View File

@@ -95,7 +95,32 @@ Column {
Layout.fillWidth: true Layout.fillWidth: true
scope: "Qt" scope: "Qt"
} }
}
Label {
text: qsTr("Horizontal item alignment")
}
SecondColumnLayout {
ComboBox {
model: ["AlignLeft", "AlignRight" ,"AlignHCenter"]
backendValue: backendValues.horizontalItemAlignment
Layout.fillWidth: true
scope: "Grid"
}
}
Label {
text: qsTr("Vertical item alignment")
}
SecondColumnLayout {
ComboBox {
model: ["AlignTop", "AlignBottom" ,"AlignVCenter"]
backendValue: backendValues.verticalItemAlignment
Layout.fillWidth: true
scope: "Grid"
}
} }
Label { Label {

View File

@@ -58,7 +58,7 @@ Column {
SecondColumnLayout { SecondColumnLayout {
ComboBox { ComboBox {
scope: "Image" scope: "Image"
model: ["Stretch", "PreserveAspectFit", "PreserveAspectCrop", "Tile", "TileVertically", "TileHorizontally"] model: ["Stretch", "PreserveAspectFit", "PreserveAspectCrop", "Tile", "TileVertically", "TileHorizontally", "Pad"]
backendValue: backendValues.fillMode backendValue: backendValues.fillMode
implicitWidth: 180 implicitWidth: 180
Layout.fillWidth: true Layout.fillWidth: true
@@ -105,6 +105,136 @@ Column {
ExpandingSpacer { ExpandingSpacer {
} }
} }
Label {
text: qsTr("Horizontal alignment")
}
SecondColumnLayout {
ComboBox {
scope: "Image"
model: ["AlignLeft", "AlignRight", "AlignHCenter"]
backendValue: backendValues.horizontalAlignment
implicitWidth: 180
Layout.fillWidth: true
}
ExpandingSpacer {
}
}
Label {
text: qsTr("Vertical alignment")
}
SecondColumnLayout {
ComboBox {
scope: "Image"
model: ["AlignTop", "AlignBottom", "AlignVCenter"]
backendValue: backendValues.verticalAlignment
implicitWidth: 180
Layout.fillWidth: true
}
ExpandingSpacer {
}
}
Label {
text: qsTr("Asynchronous")
tooltip: qsTr("Specifies that images on the local filesystem should be loaded asynchronously in a separate thread.")
disabledState: !backendValues.asynchronous.isAvailable
}
SecondColumnLayout {
CheckBox {
enabled: backendValues.asynchronous.isAvailable
text: backendValues.asynchronous.valueToString
backendValue: backendValues.asynchronous
implicitWidth: 180
}
ExpandingSpacer {}
}
Label {
text: qsTr("Auto transform")
tooltip: qsTr("Specifies whether the image should automatically apply image transformation metadata such as EXIF orientation.")
disabledState: !backendValues.autoTransform.isAvailable
}
SecondColumnLayout {
CheckBox {
enabled: backendValues.autoTransform.isAvailable
text: backendValues.autoTransform.valueToString
backendValue: backendValues.autoTransform
implicitWidth: 180
}
ExpandingSpacer {}
}
Label {
text: qsTr("Cache")
tooltip: qsTr("Specifies whether the image should be cached.")
disabledState: !backendValues.cache.isAvailable
}
SecondColumnLayout {
CheckBox {
enabled: backendValues.cache.isAvailable
text: backendValues.cache.valueToString
backendValue: backendValues.cache
implicitWidth: 180
}
ExpandingSpacer {}
}
Label {
text: qsTr("Mipmap")
tooltip: qsTr("Specifies whether the image uses mipmap filtering when scaled or transformed.")
disabledState: !backendValues.mipmap.isAvailable
}
SecondColumnLayout {
CheckBox {
enabled: backendValues.mipmap.isAvailable
text: backendValues.mipmap.valueToString
backendValue: backendValues.mipmap
implicitWidth: 180
}
ExpandingSpacer {}
}
Label {
text: qsTr("Mirror")
tooltip: qsTr("Specifies whether the image should be horizontally inverted.")
disabledState: !backendValues.mirror.isAvailable
}
SecondColumnLayout {
CheckBox {
enabled: backendValues.mirror.isAvailable
text: backendValues.mirror.valueToString
backendValue: backendValues.mirror
implicitWidth: 180
}
ExpandingSpacer {}
}
Label {
text: qsTr("Smooth")
tooltip: qsTr("Specifies whether the image is smoothly filtered when scaled or transformed.")
disabledState: !backendValues.smooth.isAvailable
}
SecondColumnLayout {
CheckBox {
enabled: backendValues.smooth.isAvailable
text: backendValues.smooth.valueToString
backendValue: backendValues.smooth
implicitWidth: 180
}
ExpandingSpacer {}
}
} }
} }
} }

View File

@@ -54,7 +54,7 @@ Column {
} }
Label { Label {
text: qsTr("Hover Enabled") text: qsTr("Hover enabled")
tooltip: qsTr("This property holds whether hover events are handled.") tooltip: qsTr("This property holds whether hover events are handled.")
} }
@@ -68,6 +68,197 @@ Column {
ExpandingSpacer { ExpandingSpacer {
} }
} }
Label {
text: qsTr("Accepted buttons")
tooltip: qsTr("This property holds the mouse buttons that the mouse area reacts to.")
}
SecondColumnLayout {
ComboBox {
backendValue: backendValues.acceptedButtons
model: ["LeftButton", "RightButton", "MiddleButton", "BackButton", "ForwardButton", "AllButtons"]
Layout.fillWidth: true
scope: "Qt"
}
ExpandingSpacer {
}
}
Label {
text: qsTr("Press and hold interval")
tooltip: qsTr("This property overrides the elapsed time in milliseconds before pressAndHold is emitted.")
}
SecondColumnLayout {
SpinBox {
backendValue: backendValues.pressAndHoldInterval
minimumValue: 0
maximumValue: 2000
decimals: 0
}
ExpandingSpacer {
}
}
Label {
text: qsTr("Scroll gesture enabled")
tooltip: qsTr("This property controls whether this MouseArea responds to scroll gestures from non-mouse devices.")
}
SecondColumnLayout {
CheckBox {
Layout.fillWidth: true
backendValue: backendValues.scrollGestureEnabled
text: backendValues.scrollGestureEnabled.valueToString
}
ExpandingSpacer {
}
}
Label {
text: qsTr("Cursor shape")
tooltip: qsTr("This property holds the cursor shape for this mouse area.")
}
SecondColumnLayout {
ComboBox {
backendValue: backendValues.cursorShape
model: ["ArrowCursor", "UpArrowCursor", "CrossCursor", "WaitCursor",
"IBeamCursor", "SizeVerCursor", "SizeHorCursor", "SizeBDiagCursor",
"SizeFDiagCursor", "SizeAllCursor", "BlankCursor", "SplitVCursor",
"SplitHCursor", "PointingHandCursor", "ForbiddenCursor", "WhatsThisCursor",
"BusyCursor", "OpenHandCursor", "ClosedHandCursor", "DragCopyCursor",
"DragMoveCursor", "DragLinkCursor"]
Layout.fillWidth: true
scope: "Qt"
}
ExpandingSpacer {
}
}
Label {
text: qsTr("Prevent stealing")
tooltip: qsTr("This property controls whether the mouse events may be stolen from this MouseArea.")
}
SecondColumnLayout {
CheckBox {
Layout.fillWidth: true
backendValue: backendValues.preventStealing
text: backendValues.preventStealing.valueToString
}
ExpandingSpacer {
}
}
Label {
text: qsTr("Propagate composed events")
tooltip: qsTr("This property controls whether composed mouse events will automatically propagate to other MouseAreas.")
}
SecondColumnLayout {
CheckBox {
Layout.fillWidth: true
backendValue: backendValues.propagateComposedEvents
text: backendValues.propagateComposedEvents.valueToString
}
ExpandingSpacer {
}
}
}
}
Section {
anchors.left: parent.left
anchors.right: parent.right
caption: qsTr("Drag")
SectionLayout {
Label {
text: qsTr("Target")
tooltip: qsTr("Sets the id of the item to drag.")
}
SecondColumnLayout {
ItemFilterComboBox {
typeFilter: "QtQuick.QtObject"
validator: RegExpValidator { regExp: /(^$|^[a-z_]\w*)/ }
backendValue: backendValues.drag_target
Layout.fillWidth: true
}
ExpandingSpacer {
}
}
Label {
text: qsTr("Axis")
tooltip: qsTr("Specifies whether dragging can be done horizontally, vertically, or both.")
}
SecondColumnLayout {
ComboBox {
scope: "Drag"
model: ["XAxis", "YAxis", "XAndYAxis"]
backendValue: backendValues.drag_axis
Layout.fillWidth: true
}
ExpandingSpacer {
}
}
Label {
text: qsTr("Filter children")
tooltip: qsTr("Specifies whether a drag overrides descendant MouseAreas.")
}
SecondColumnLayout {
CheckBox {
Layout.fillWidth: true
backendValue: backendValues.drag_filterChildren
text: backendValues.drag_filterChildren.valueToString
}
ExpandingSpacer {
}
}
Label {
text: qsTr("Threshold")
tooltip: qsTr("Determines the threshold in pixels of when the drag operation should start.")
}
SecondColumnLayout {
SpinBox {
backendValue: backendValues.drag_threshold
minimumValue: 0
maximumValue: 5000
decimals: 0
}
ExpandingSpacer {
}
}
Label {
text: qsTr("Smoothed")
tooltip: qsTr("If set to true, the target will be moved only after the drag operation has started.\n"
+ "If set to false, the target will be moved straight to the current mouse position.")
}
SecondColumnLayout {
CheckBox {
Layout.fillWidth: true
backendValue: backendValues.drag_smoothed
text: backendValues.drag_smoothed.valueToString
}
ExpandingSpacer {
}
}
} }
} }
} }

View File

@@ -113,6 +113,19 @@ Section {
minimumValue: -200 minimumValue: -200
} }
Label {
visible: textInputSection.isTextInput
text: qsTr("Maximum length")
tooltip: qsTr("Sets the maximum permitted length of the text in the TextInput.")
}
SpinBox {
visible: textInputSection.isTextInput
Layout.fillWidth: true
backendValue: backendValues.maximumLength
minimumValue: 0
maximumValue: 32767
}
Label { Label {
text: qsTr("Flags") text: qsTr("Flags")
Layout.alignment: Qt.AlignTop Layout.alignment: Qt.AlignTop

View File

@@ -47,7 +47,7 @@ Section {
SecondColumnLayout { SecondColumnLayout {
ComboBox { ComboBox {
backendValue: backendValues.flickableDirection backendValue: backendValues.flickableDirection
model: ["AutoFlickDirection", "HorizontalFlick", "VerticalFlick", "HorizontalAndVerticalFlick"] model: ["AutoFlickDirection", "AutoFlickIfNeeded", "HorizontalFlick", "VerticalFlick", "HorizontalAndVerticalFlick"]
Layout.fillWidth: true Layout.fillWidth: true
scope: "Flickable" scope: "Flickable"
} }
@@ -63,7 +63,7 @@ Section {
SecondColumnLayout { SecondColumnLayout {
ComboBox { ComboBox {
backendValue: backendValues.boundsBehavior backendValue: backendValues.boundsBehavior
model: ["StopAtBounds", "DragOverBounds", "DragAndOvershootBounds"] model: ["StopAtBounds", "DragOverBounds", "OvershootBounds", "DragAndOvershootBounds"]
Layout.fillWidth: true Layout.fillWidth: true
scope: "Flickable" scope: "Flickable"
} }
@@ -166,6 +166,23 @@ Section {
} }
} }
Label {
text: qsTr("Synchronous drag")
tooltip: qsTr("If set to true, then when the mouse or touchpoint moves far enough to begin dragging\n"
+ "the content, the content will jump, such that the content pixel which was under the\n"
+ "cursor or touchpoint when pressed remains under that point.")
}
SecondColumnLayout {
CheckBox {
Layout.fillWidth: true
backendValue: backendValues.synchronousDrag
text: backendValues.synchronousDrag.valueToString
}
ExpandingSpacer {
}
}
Label { Label {
text: qsTr("Content size") text: qsTr("Content size")
} }
@@ -246,6 +263,45 @@ Section {
} }
} }
Label {
text: qsTr("Origin")
}
SecondColumnLayout {
Label {
text: "X"
width: root.labelWidth
}
SpinBox {
backendValue: backendValues.originX
minimumValue: -8000
maximumValue: 8000
implicitWidth: root.spinBoxWidth
Layout.fillWidth: true
}
Item {
width: 4
height: 4
}
Label {
text: "Y"
width: root.labelWidth
}
SpinBox {
backendValue: backendValues.originY
minimumValue: -8000
maximumValue: 8000
implicitWidth: root.spinBoxWidth
Layout.fillWidth: true
}
ExpandingSpacer {
}
}
Label { Label {
text: qsTr("Margins") text: qsTr("Margins")
} }

View File

@@ -68,9 +68,12 @@ Section {
text: qsTr("Font") text: qsTr("Font")
} }
FontComboBox { FontComboBox {
id: fontComboBox
backendValue: fontSection.fontFamily backendValue: fontSection.fontFamily
Layout.fillWidth: true Layout.fillWidth: true
width: 160 width: 160
property string familyName: backendValue.value
onFamilyNameChanged: print(styleNamesForFamily(familyName))
} }
Label { Label {
@@ -151,6 +154,7 @@ Section {
italic: fontSection.italicStyle italic: fontSection.italicStyle
underline: fontSection.underlineStyle underline: fontSection.underlineStyle
strikeout: fontSection.strikeoutStyle strikeout: fontSection.strikeoutStyle
enabled: !styleComboBox.styleSet
} }
Label { Label {
@@ -175,6 +179,21 @@ Section {
backendValue: getBackendValue("weight") backendValue: getBackendValue("weight")
model: ["Normal", "Light", "ExtraLight", "Thin", "Medium", "DemiBold", "Bold", "ExtraBold", "Black"] model: ["Normal", "Light", "ExtraLight", "Thin", "Medium", "DemiBold", "Bold", "ExtraBold", "Black"]
scope: "Font" scope: "Font"
enabled: !styleComboBox.styleSet
}
Label {
text: qsTr("Style name")
toolTip: qsTr("Sets the font's style.")
}
ComboBox {
id: styleComboBox
property bool styleSet: backendValue.isInModel
Layout.fillWidth: true
backendValue: getBackendValue("styleName")
model: styleNamesForFamily(fontComboBox.familyName)
useString: true
} }
Label { Label {
@@ -257,5 +276,17 @@ Section {
"Latin script,\n it is merely a cosmetic feature. Setting the preferShaping property to false will disable all such features\nwhen they are not required, which will improve performance in most cases.") "Latin script,\n it is merely a cosmetic feature. Setting the preferShaping property to false will disable all such features\nwhen they are not required, which will improve performance in most cases.")
} }
} }
Label {
text: qsTr("Hinting preference")
toolTip: qsTr("Sets the preferred hinting on the text.")
}
ComboBox {
Layout.fillWidth: true
backendValue: getBackendValue("hintingPreference")
model: ["PreferDefaultHinting", "PreferNoHinting", "PreferVerticalHinting", "PreferFullHinting"]
scope: "Font"
}
} }
} }

View File

@@ -61,7 +61,7 @@ Section {
Layout.fillWidth: true Layout.fillWidth: true
backendValue: backendValues.wrapMode backendValue: backendValues.wrapMode
scope: "Text" scope: "Text"
model: ["NoWrap", "WordWrap", "WrapAnywhere", "WrapAtWordBoundaryOrAnywhere"] model: ["NoWrap", "WordWrap", "WrapAnywhere", "Wrap"]
} }
Label { Label {
@@ -77,6 +77,21 @@ Section {
model: ["ElideNone", "ElideLeft", "ElideMiddle", "ElideRight"] model: ["ElideNone", "ElideLeft", "ElideMiddle", "ElideRight"]
} }
Label {
visible: showElide
text: qsTr("Maximum line count")
tooltip: qsTr("Limits the number of lines that the text item will show.")
}
SpinBox {
visible: showElide
Layout.fillWidth: true
backendValue: backendValues.maximumLineCount
minimumValue: 0
maximumValue: 10000
decimals: 0
}
Label { Label {
text: qsTr("Alignment") text: qsTr("Alignment")
} }
@@ -124,6 +139,7 @@ Section {
toolTip: qsTr("Specifies how the font size of the displayed text is determined.") toolTip: qsTr("Specifies how the font size of the displayed text is determined.")
} }
ComboBox { ComboBox {
id: fontSizeMode
visible: showFontSizeMode visible: showFontSizeMode
scope: "Text" scope: "Text"
model: ["FixedSize", "HorizontalFit", "VerticalFit", "Fit"] model: ["FixedSize", "HorizontalFit", "VerticalFit", "Fit"]
@@ -131,6 +147,48 @@ Section {
Layout.fillWidth: true Layout.fillWidth: true
} }
Label {
visible: showFontSizeMode
text: qsTr("Minimum size")
}
SecondColumnLayout {
visible: showFontSizeMode
SpinBox {
enabled: fontSizeMode.currentIndex !== 0
minimumValue: 0
maximumValue: 500
decimals: 0
backendValue: backendValues.minimumPixelSize
Layout.fillWidth: true
Layout.minimumWidth: 60
}
Label {
text: qsTr("Pixel")
tooltip: qsTr("Specifies the minimum font pixel size of scaled text.")
width: 42
}
Item {
width: 4
height: 4
}
SpinBox {
enabled: fontSizeMode.currentIndex !== 0
minimumValue: 0
maximumValue: 500
decimals: 0
backendValue: backendValues.minimumPointSize
Layout.fillWidth: true
Layout.minimumWidth: 60
}
Label {
text: qsTr("Point")
tooltip: qsTr("Specifies the minimum font point size of scaled text.")
width: 42
}
}
Label { Label {
visible: showLineHeight visible: showLineHeight
@@ -148,5 +206,17 @@ Section {
stepSize: 0.1 stepSize: 0.1
} }
Label {
visible: showLineHeight
text: qsTr("Line height mode")
toolTip: qsTr("Determines how the line height is specified.")
}
ComboBox {
visible: showLineHeight
scope: "Text"
model: ["ProportionalHeight", "FixedHeight"]
backendValue: backendValues.lineHeightMode
Layout.fillWidth: true
}
} }
} }

View File

@@ -26,98 +26,4 @@
pragma Singleton pragma Singleton
import QtQuick 2.10 import QtQuick 2.10
QtObject { InternalConstants {}
readonly property int width: 1920
readonly property int height: 1080
readonly property FontLoader mySystemFont: FontLoader {
name: "Arial"
}
readonly property FontLoader controlIcons: FontLoader {
source: "icons.ttf"
}
readonly property string actionIcon: "\u0021"
readonly property string actionIconBinding: "\u0022"
readonly property string addColumnAfter: "\u0023"
readonly property string addColumnBefore: "\u0024"
readonly property string addFile: "\u0025"
readonly property string addRowAfter: "\u0026"
readonly property string addRowBefore: "\u0027"
readonly property string addTable: "\u0028"
readonly property string alignBottom: "\u0029"
readonly property string alignCenterHorizontal: "\u002A"
readonly property string alignCenterVertical: "\u002B"
readonly property string alignLeft: "\u002C"
readonly property string alignRight: "\u002D"
readonly property string alignTo: "\u002E"
readonly property string alignTop: "\u002F"
readonly property string anchorBaseline: "\u0030"
readonly property string anchorBottom: "\u0031"
readonly property string anchorFill: "\u0032"
readonly property string anchorLeft: "\u0033"
readonly property string anchorRight: "\u0034"
readonly property string anchorTop: "\u0035"
readonly property string annotationBubble: "\u0036"
readonly property string annotationDecal: "\u0037"
readonly property string centerHorizontal: "\u0038"
readonly property string centerVertical: "\u0039"
readonly property string closeCross: "\u003A"
readonly property string deleteColumn: "\u003B"
readonly property string deleteRow: "\u003C"
readonly property string deleteTable: "\u003D"
readonly property string distributeBottom: "\u003E"
readonly property string distributeCenterHorizontal: "\u003F"
readonly property string distributeCenterVertical: "\u0040"
readonly property string distributeLeft: "\u0041"
readonly property string distributeOriginBottomRight: "\u0042"
readonly property string distributeOriginCenter: "\u0043"
readonly property string distributeOriginNone: "\u0044"
readonly property string distributeOriginTopLeft: "\u0045"
readonly property string distributeRight: "\u0046"
readonly property string distributeSpacingHorizontal: "\u0047"
readonly property string distributeSpacingVertical: "\u0048"
readonly property string distributeTop: "\u0049"
readonly property string edit: "\u004A"
readonly property string fontStyleBold: "\u004B"
readonly property string fontStyleItalic: "\u004C"
readonly property string fontStyleStrikethrough: "\u004D"
readonly property string fontStyleUnderline: "\u004E"
readonly property string mergeCells: "\u004F"
readonly property string redo: "\u0050"
readonly property string splitColumns: "\u0051"
readonly property string splitRows: "\u0052"
readonly property string testIcon: "\u0053"
readonly property string textAlignBottom: "\u0054"
readonly property string textAlignCenter: "\u0055"
readonly property string textAlignLeft: "\u0056"
readonly property string textAlignMiddle: "\u0057"
readonly property string textAlignRight: "\u0058"
readonly property string textAlignTop: "\u0059"
readonly property string textBulletList: "\u005A"
readonly property string textFullJustification: "\u005B"
readonly property string textNumberedList: "\u005C"
readonly property string tickIcon: "\u005D"
readonly property string triState: "\u005E"
readonly property string undo: "\u005F"
readonly property string upDownIcon: "\u0060"
readonly property string upDownSquare2: "\u0061"
readonly property font iconFont: Qt.font({
"family": controlIcons.name,
"pixelSize": 12
})
readonly property font font: Qt.font({
"family": mySystemFont.name,
"pointSize": Qt.application.font.pixelSize
})
readonly property font largeFont: Qt.font({
"family": mySystemFont.name,
"pointSize": Qt.application.font.pixelSize * 1.6
})
readonly property color backgroundColor: "#c2c2c2"
readonly property bool showActionIndicatorBackground: false
}

View File

@@ -0,0 +1,131 @@
/****************************************************************************
**
** Copyright (C) 2020 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.10
QtObject {
readonly property int width: 1920
readonly property int height: 1080
readonly property FontLoader mySystemFont: FontLoader {
name: "Arial"
}
readonly property FontLoader controlIcons: FontLoader {
source: "icons.ttf"
}
objectName: "internalConstantsObject"
readonly property string actionIcon: "\u0021"
readonly property string actionIconBinding: "\u0022"
readonly property string addColumnAfter: "\u0023"
readonly property string addColumnBefore: "\u0024"
readonly property string addFile: "\u0025"
readonly property string addRowAfter: "\u0026"
readonly property string addRowBefore: "\u0027"
readonly property string addTable: "\u0028"
readonly property string adsClose: "\u0029"
readonly property string adsDetach: "\u002A"
readonly property string adsDropDown: "\u002B"
readonly property string alignBottom: "\u002C"
readonly property string alignCenterHorizontal: "\u002D"
readonly property string alignCenterVertical: "\u002E"
readonly property string alignLeft: "\u002F"
readonly property string alignRight: "\u0030"
readonly property string alignTo: "\u0031"
readonly property string alignTop: "\u0032"
readonly property string anchorBaseline: "\u0033"
readonly property string anchorBottom: "\u0034"
readonly property string anchorFill: "\u0035"
readonly property string anchorLeft: "\u0036"
readonly property string anchorRight: "\u0037"
readonly property string anchorTop: "\u0038"
readonly property string annotationBubble: "\u0039"
readonly property string annotationDecal: "\u003A"
readonly property string centerHorizontal: "\u003B"
readonly property string centerVertical: "\u003C"
readonly property string closeCross: "\u003D"
readonly property string decisionNode: "\u003E"
readonly property string deleteColumn: "\u003F"
readonly property string deleteRow: "\u0040"
readonly property string deleteTable: "\u0041"
readonly property string detach: "\u0042"
readonly property string distributeBottom: "\u0043"
readonly property string distributeCenterHorizontal: "\u0044"
readonly property string distributeCenterVertical: "\u0045"
readonly property string distributeLeft: "\u0046"
readonly property string distributeOriginBottomRight: "\u0047"
readonly property string distributeOriginCenter: "\u0048"
readonly property string distributeOriginNone: "\u0049"
readonly property string distributeOriginTopLeft: "\u004A"
readonly property string distributeRight: "\u004B"
readonly property string distributeSpacingHorizontal: "\u004C"
readonly property string distributeSpacingVertical: "\u004D"
readonly property string distributeTop: "\u004E"
readonly property string edit: "\u004F"
readonly property string fontStyleBold: "\u0050"
readonly property string fontStyleItalic: "\u0051"
readonly property string fontStyleStrikethrough: "\u0052"
readonly property string fontStyleUnderline: "\u0053"
readonly property string mergeCells: "\u0054"
readonly property string redo: "\u0055"
readonly property string splitColumns: "\u0056"
readonly property string splitRows: "\u0057"
readonly property string startNode: "\u0058"
readonly property string testIcon: "\u0059"
readonly property string textAlignBottom: "\u005A"
readonly property string textAlignCenter: "\u005B"
readonly property string textAlignLeft: "\u005C"
readonly property string textAlignMiddle: "\u005D"
readonly property string textAlignRight: "\u005E"
readonly property string textAlignTop: "\u005F"
readonly property string textBulletList: "\u0060"
readonly property string textFullJustification: "\u0061"
readonly property string textNumberedList: "\u0062"
readonly property string tickIcon: "\u0063"
readonly property string triState: "\u0064"
readonly property string undo: "\u0065"
readonly property string upDownIcon: "\u0066"
readonly property string upDownSquare2: "\u0067"
readonly property string wildcard: "\u0068"
readonly property font iconFont: Qt.font({
"family": controlIcons.name,
"pixelSize": 12
})
readonly property font font: Qt.font({
"family": mySystemFont.name,
"pointSize": Qt.application.font.pixelSize
})
readonly property font largeFont: Qt.font({
"family": mySystemFont.name,
"pointSize": Qt.application.font.pixelSize * 1.6
})
readonly property color backgroundColor: "#c2c2c2"
readonly property bool showActionIndicatorBackground: false
}

View File

@@ -1,2 +1,4 @@
singleton Values 1.0 Values.qml singleton Values 1.0 Values.qml
singleton Constants 1.0 Constants.qml singleton Constants 1.0 Constants.qml
InternalConstants 1.0 InternalConstants.qml

View File

@@ -107,10 +107,11 @@ enum eDragState {
* The different icons used in the UI * The different icons used in the UI
*/ */
enum eIcon { enum eIcon {
TabCloseIcon, //!< TabCloseIcon TabCloseIcon, //!< TabCloseIcon
DockAreaMenuIcon, //!< DockAreaMenuIcon DockAreaMenuIcon, //!< DockAreaMenuIcon
DockAreaUndockIcon, //!< DockAreaUndockIcon DockAreaUndockIcon, //!< DockAreaUndockIcon
DockAreaCloseIcon, //!< DockAreaCloseIcon DockAreaCloseIcon, //!< DockAreaCloseIcon
FloatingWidgetCloseIcon, //!< FloatingWidgetCloseIcon
IconCount, //!< just a delimiter for range checks IconCount, //!< just a delimiter for range checks
}; };

View File

@@ -132,6 +132,7 @@ namespace ADS
void DockAreaTitleBarPrivate::createButtons() void DockAreaTitleBarPrivate::createButtons()
{ {
const QSize iconSize(14, 14);
QSizePolicy sizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding); QSizePolicy sizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
// Tabs menu button // Tabs menu button
m_tabsMenuButton = new TitleBarButton(testConfigFlag(DockManager::DockAreaHasTabsMenuButton)); m_tabsMenuButton = new TitleBarButton(testConfigFlag(DockManager::DockAreaHasTabsMenuButton));
@@ -149,6 +150,7 @@ namespace ADS
m_tabsMenuButton->setMenu(tabsMenu); m_tabsMenuButton->setMenu(tabsMenu);
internal::setToolTip(m_tabsMenuButton, QObject::tr("List All Tabs")); internal::setToolTip(m_tabsMenuButton, QObject::tr("List All Tabs"));
m_tabsMenuButton->setSizePolicy(sizePolicy); m_tabsMenuButton->setSizePolicy(sizePolicy);
m_tabsMenuButton->setIconSize(iconSize);
m_layout->addWidget(m_tabsMenuButton, 0); m_layout->addWidget(m_tabsMenuButton, 0);
QObject::connect(m_tabsMenuButton->menu(), QObject::connect(m_tabsMenuButton->menu(),
&QMenu::triggered, &QMenu::triggered,
@@ -164,6 +166,7 @@ namespace ADS
QStyle::SP_TitleBarNormalButton, QStyle::SP_TitleBarNormalButton,
ADS::DockAreaUndockIcon); ADS::DockAreaUndockIcon);
m_undockButton->setSizePolicy(sizePolicy); m_undockButton->setSizePolicy(sizePolicy);
m_undockButton->setIconSize(iconSize);
m_layout->addWidget(m_undockButton, 0); m_layout->addWidget(m_undockButton, 0);
QObject::connect(m_undockButton, QObject::connect(m_undockButton,
&QToolButton::clicked, &QToolButton::clicked,
@@ -183,7 +186,7 @@ namespace ADS
internal::setToolTip(m_closeButton, QObject::tr("Close Group")); internal::setToolTip(m_closeButton, QObject::tr("Close Group"));
} }
m_closeButton->setSizePolicy(sizePolicy); m_closeButton->setSizePolicy(sizePolicy);
m_closeButton->setIconSize(QSize(16, 16)); m_closeButton->setIconSize(iconSize);
m_layout->addWidget(m_closeButton, 0); m_layout->addWidget(m_closeButton, 0);
QObject::connect(m_closeButton, QObject::connect(m_closeButton,
&QToolButton::clicked, &QToolButton::clicked,

View File

@@ -168,12 +168,18 @@ namespace ADS
m_titleLabel->setText(m_dockWidget->windowTitle()); m_titleLabel->setText(m_dockWidget->windowTitle());
m_titleLabel->setObjectName("dockWidgetTabLabel"); m_titleLabel->setObjectName("dockWidgetTabLabel");
m_titleLabel->setAlignment(Qt::AlignCenter); m_titleLabel->setAlignment(Qt::AlignCenter);
QObject::connect(m_titleLabel, &ElidingLabel::elidedChanged, q, &DockWidgetTab::elidedChanged); QObject::connect(m_titleLabel,
&ElidingLabel::elidedChanged,
q,
&DockWidgetTab::elidedChanged);
m_closeButton = createCloseButton(); m_closeButton = createCloseButton();
m_closeButton->setObjectName("tabCloseButton"); m_closeButton->setObjectName("tabCloseButton");
internal::setButtonIcon(m_closeButton, QStyle::SP_TitleBarCloseButton, TabCloseIcon); internal::setButtonIcon(m_closeButton,
QStyle::SP_TitleBarCloseButton,
TabCloseIcon);
m_closeButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); m_closeButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
m_closeButton->setIconSize(QSize(14, 14));
q->onDockWidgetFeaturesChanged(); q->onDockWidgetFeaturesChanged();
internal::setToolTip(m_closeButton, QObject::tr("Close Tab")); internal::setToolTip(m_closeButton, QObject::tr("Close Tab"));
QObject::connect(m_closeButton, QObject::connect(m_closeButton,
@@ -189,11 +195,11 @@ namespace ADS
boxLayout->setContentsMargins(2 * spacing, 0, 0, 0); boxLayout->setContentsMargins(2 * spacing, 0, 0, 0);
boxLayout->setSpacing(0); boxLayout->setSpacing(0);
q->setLayout(boxLayout); q->setLayout(boxLayout);
boxLayout->addWidget(m_titleLabel, 1); boxLayout->addWidget(m_titleLabel, 1, Qt::AlignVCenter);
boxLayout->addSpacing(spacing); boxLayout->addSpacing(spacing);
boxLayout->addWidget(m_closeButton); boxLayout->addWidget(m_closeButton, 0, Qt::AlignVCenter);
boxLayout->addSpacing(qRound(spacing * 4.0 / 3.0)); boxLayout->addSpacing(qRound(spacing * 4.0 / 3.0));
boxLayout->setAlignment(Qt::AlignCenter); boxLayout->setAlignment(Qt::AlignCenter | Qt::AlignVCenter);
m_titleLabel->setVisible(true); m_titleLabel->setVisible(true);
} }

View File

@@ -51,7 +51,7 @@ namespace ADS {
*/ */
IconProviderPrivate(IconProvider *parent); IconProviderPrivate(IconProvider *parent);
}; };
// struct LedArrayPanelPrivate // struct IconProviderPrivate
IconProviderPrivate::IconProviderPrivate(IconProvider *parent) IconProviderPrivate::IconProviderPrivate(IconProvider *parent)
: q(parent) : q(parent)

View File

@@ -41,7 +41,7 @@
namespace ADS { namespace ADS {
using TabLabelType = ElidingLabel; using TabLabelType = ElidingLabel;
using tCloseButton = QPushButton; using CloseButtonType = QPushButton;
/** /**
* @brief Private data class of public interface CFloatingWidgetTitleBar * @brief Private data class of public interface CFloatingWidgetTitleBar
@@ -52,7 +52,7 @@ public:
FloatingWidgetTitleBar *q; ///< public interface class FloatingWidgetTitleBar *q; ///< public interface class
QLabel *m_iconLabel = nullptr; QLabel *m_iconLabel = nullptr;
TabLabelType *m_titleLabel = nullptr; TabLabelType *m_titleLabel = nullptr;
tCloseButton *m_closeButton = nullptr; CloseButtonType *m_closeButton = nullptr;
FloatingDockContainer *m_floatingWidget = nullptr; FloatingDockContainer *m_floatingWidget = nullptr;
eDragState m_dragState = DraggingInactive; eDragState m_dragState = DraggingInactive;
@@ -74,22 +74,20 @@ void FloatingWidgetTitleBarPrivate::createLayout()
m_titleLabel->setObjectName("floatingTitleLabel"); m_titleLabel->setObjectName("floatingTitleLabel");
m_titleLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); m_titleLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
m_closeButton = new tCloseButton(); m_closeButton = new CloseButtonType();
m_closeButton->setObjectName("floatingTitleCloseButton"); m_closeButton->setObjectName("floatingTitleCloseButton");
m_closeButton->setFlat(true); m_closeButton->setFlat(true);
internal::setButtonIcon(m_closeButton,
// The standard icons do does not look good on high DPI screens QStyle::SP_TitleBarCloseButton,
QIcon closeIcon; ADS::FloatingWidgetCloseIcon);
QPixmap normalPixmap = q->style()->standardPixmap(QStyle::SP_TitleBarCloseButton,
nullptr,
m_closeButton);
closeIcon.addPixmap(normalPixmap, QIcon::Normal);
closeIcon.addPixmap(internal::createTransparentPixmap(normalPixmap, 0.25), QIcon::Disabled);
m_closeButton->setIcon(q->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
m_closeButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); m_closeButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
m_closeButton->setIconSize(QSize(14, 14));
m_closeButton->setVisible(true); m_closeButton->setVisible(true);
m_closeButton->setFocusPolicy(Qt::NoFocus); m_closeButton->setFocusPolicy(Qt::NoFocus);
q->connect(m_closeButton, &QPushButton::clicked, q, &FloatingWidgetTitleBar::closeRequested); QObject::connect(m_closeButton,
&QPushButton::clicked,
q,
&FloatingWidgetTitleBar::closeRequested);
QFontMetrics fontMetrics(m_titleLabel->font()); QFontMetrics fontMetrics(m_titleLabel->font());
int spacing = qRound(fontMetrics.height() / 4.0); int spacing = qRound(fontMetrics.height() / 4.0);

View File

@@ -22,6 +22,7 @@ add_qtc_library(Sqlite
sqlitetable.h sqlitetable.h
sqlitetransaction.h sqlitetransaction.h
sqlitewritestatement.cpp sqlitewritestatement.h sqlitewritestatement.cpp sqlitewritestatement.h
sqlitevalue.h
sqlstatementbuilder.cpp sqlstatementbuilder.h sqlstatementbuilder.cpp sqlstatementbuilder.h
sqlstatementbuilderexception.h sqlstatementbuilderexception.h
utf8string.cpp utf8string.h utf8string.cpp utf8string.h

View File

@@ -32,6 +32,7 @@ HEADERS += \
$$PWD/sqlitereadstatement.h \ $$PWD/sqlitereadstatement.h \
$$PWD/sqlitereadwritestatement.h \ $$PWD/sqlitereadwritestatement.h \
$$PWD/sqlitetransaction.h \ $$PWD/sqlitetransaction.h \
$$PWD/sqlitevalue.h \
$$PWD/sqlitewritestatement.h \ $$PWD/sqlitewritestatement.h \
$$PWD/sqlstatementbuilder.h \ $$PWD/sqlstatementbuilder.h \
$$PWD/sqlstatementbuilderexception.h \ $$PWD/sqlstatementbuilderexception.h \

View File

@@ -190,6 +190,21 @@ void BaseStatement::bind(int index, Utils::SmallStringView text)
checkForBindingError(resultCode); checkForBindingError(resultCode);
} }
void BaseStatement::bind(int index, const Value &value)
{
switch (value.type()) {
case ValueType::Integer:
bind(index, value.toInteger());
break;
case ValueType::Float:
bind(index, value.toFloat());
break;
case ValueType::String:
bind(index, value.toStringView());
break;
}
}
template <typename Type> template <typename Type>
void BaseStatement::bind(Utils::SmallStringView name, Type value) void BaseStatement::bind(Utils::SmallStringView name, Type value)
{ {
@@ -498,12 +513,34 @@ StringType BaseStatement::fetchValue(int column) const
return convertToTextForColumn<StringType>(m_compiledStatement.get(), column); return convertToTextForColumn<StringType>(m_compiledStatement.get(), column);
} }
template SQLITE_EXPORT Utils::SmallStringView BaseStatement::fetchValue<Utils::SmallStringView>(
int column) const;
template SQLITE_EXPORT Utils::SmallString BaseStatement::fetchValue<Utils::SmallString>(
int column) const;
template SQLITE_EXPORT Utils::PathString BaseStatement::fetchValue<Utils::PathString>(
int column) const;
Utils::SmallStringView BaseStatement::fetchSmallStringViewValue(int column) const Utils::SmallStringView BaseStatement::fetchSmallStringViewValue(int column) const
{ {
return fetchValue<Utils::SmallStringView>(column); return fetchValue<Utils::SmallStringView>(column);
} }
template SQLITE_EXPORT Utils::SmallStringView BaseStatement::fetchValue<Utils::SmallStringView>(int column) const; ValueView BaseStatement::fetchValueView(int column) const
template SQLITE_EXPORT Utils::SmallString BaseStatement::fetchValue<Utils::SmallString>(int column) const; {
template SQLITE_EXPORT Utils::PathString BaseStatement::fetchValue<Utils::PathString>(int column) const; int dataType = sqlite3_column_type(m_compiledStatement.get(), column);
switch (dataType) {
case SQLITE_INTEGER:
return ValueView::create(fetchLongLongValue(column));
case SQLITE_FLOAT:
return ValueView::create(fetchDoubleValue(column));
case SQLITE3_TEXT:
return ValueView::create(fetchValue<Utils::SmallStringView>(column));
case SQLITE_BLOB:
case SQLITE_NULL:
break;
}
return ValueView::create(0LL);
}
} // namespace Sqlite } // namespace Sqlite

View File

@@ -28,6 +28,7 @@
#include "sqliteglobal.h" #include "sqliteglobal.h"
#include "sqliteexception.h" #include "sqliteexception.h"
#include "sqlitevalue.h"
#include <utils/smallstringvector.h> #include <utils/smallstringvector.h>
@@ -67,6 +68,7 @@ public:
long long fetchLongLongValue(int column) const; long long fetchLongLongValue(int column) const;
double fetchDoubleValue(int column) const; double fetchDoubleValue(int column) const;
Utils::SmallStringView fetchSmallStringViewValue(int column) const; Utils::SmallStringView fetchSmallStringViewValue(int column) const;
ValueView fetchValueView(int column) const;
template<typename Type> template<typename Type>
Type fetchValue(int column) const; Type fetchValue(int column) const;
int columnCount() const; int columnCount() const;
@@ -76,11 +78,9 @@ public:
void bind(int index, long long fetchValue); void bind(int index, long long fetchValue);
void bind(int index, double fetchValue); void bind(int index, double fetchValue);
void bind(int index, Utils::SmallStringView fetchValue); void bind(int index, Utils::SmallStringView fetchValue);
void bind(int index, const Value &fetchValue);
void bind(int index, uint value) void bind(int index, uint value) { bind(index, static_cast<long long>(value)); }
{
bind(index, static_cast<long long>(value));
}
void bind(int index, long value) void bind(int index, long value)
{ {
@@ -345,34 +345,16 @@ private:
struct ValueGetter struct ValueGetter
{ {
ValueGetter(StatementImplementation &statement, int column) ValueGetter(StatementImplementation &statement, int column)
: statement(statement), : statement(statement)
column(column) , column(column)
{} {}
operator int() operator int() { return statement.fetchIntValue(column); }
{ operator long() { return statement.fetchLongValue(column); }
return statement.fetchIntValue(column); operator long long() { return statement.fetchLongLongValue(column); }
} operator double() { return statement.fetchDoubleValue(column); }
operator Utils::SmallStringView() { return statement.fetchSmallStringViewValue(column); }
operator long() operator ValueView() { return statement.fetchValueView(column); }
{
return statement.fetchLongValue(column);
}
operator long long()
{
return statement.fetchLongLongValue(column);
}
operator double()
{
return statement.fetchDoubleValue(column);
}
operator Utils::SmallStringView()
{
return statement.fetchSmallStringViewValue(column);
}
StatementImplementation &statement; StatementImplementation &statement;
int column; int column;

View File

@@ -264,4 +264,12 @@ public:
} }
}; };
class CannotConvert : public Exception
{
public:
CannotConvert(const char *whatErrorHasHappen)
: Exception(whatErrorHasHappen)
{}
};
} // namespace Sqlite } // namespace Sqlite

View File

@@ -0,0 +1,300 @@
/****************************************************************************
**
** Copyright (C) 2020 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.
**
****************************************************************************/
#include "sqliteexception.h"
#include <utils/smallstring.h>
#include <utils/variant.h>
#include <QVariant>
#pragma once
namespace Sqlite {
enum class ValueType : unsigned char { Integer, Float, String };
template<typename StringType>
class ValueBase
{
public:
using VariantType = Utils::variant<long long, double, StringType>;
explicit ValueBase(VariantType &&value)
: value(value)
{}
explicit ValueBase(const char *value)
: value(Utils::SmallStringView{value})
{}
explicit ValueBase(long long value)
: value(value)
{}
explicit ValueBase(int value)
: value(static_cast<long long>(value))
{}
explicit ValueBase(uint value)
: value(static_cast<long long>(value))
{}
explicit ValueBase(double value)
: value(value)
{}
explicit ValueBase(Utils::SmallStringView value)
: value(value)
{}
long long toInteger() const { return Utils::get<int(ValueType::Integer)>(value); }
double toFloat() const { return Utils::get<int(ValueType::Float)>(value); }
Utils::SmallStringView toStringView() const
{
return Utils::get<int(ValueType::String)>(value);
}
explicit operator QVariant() const
{
switch (type()) {
case ValueType::Integer:
return QVariant(toInteger());
case ValueType::Float:
return QVariant(toFloat());
case ValueType::String:
return QVariant(QString(toStringView()));
}
return {};
}
friend bool operator==(const ValueBase &first, long long second)
{
auto maybeInteger = Utils::get_if<int(ValueType::Integer)>(&first.value);
return maybeInteger && *maybeInteger == second;
}
friend bool operator==(long long first, const ValueBase &second) { return second == first; }
friend bool operator==(const ValueBase &first, double second)
{
auto maybeInteger = Utils::get_if<int(ValueType::Float)>(&first.value);
return maybeInteger && *maybeInteger == second;
}
friend bool operator==(const ValueBase &first, int second)
{
return first == static_cast<long long>(second);
}
friend bool operator==(int first, const ValueBase &second) { return second == first; }
friend bool operator==(const ValueBase &first, uint second)
{
return first == static_cast<long long>(second);
}
friend bool operator==(uint first, const ValueBase &second) { return second == first; }
friend bool operator==(double first, const ValueBase &second) { return second == first; }
friend bool operator==(const ValueBase &first, Utils::SmallStringView second)
{
auto maybeInteger = Utils::get_if<int(ValueType::String)>(&first.value);
return maybeInteger && *maybeInteger == second;
}
friend bool operator==(Utils::SmallStringView first, const ValueBase &second)
{
return second == first;
}
friend bool operator==(const ValueBase &first, const QString &second)
{
auto maybeInteger = Utils::get_if<int(ValueType::String)>(&first.value);
return maybeInteger
&& second == QLatin1String{maybeInteger->data(), int(maybeInteger->size())};
}
friend bool operator==(const QString &first, const ValueBase &second)
{
return second == first;
}
friend bool operator==(const ValueBase &first, const char *second)
{
return first == Utils::SmallStringView{second};
}
friend bool operator==(const char *first, const ValueBase &second) { return second == first; }
friend bool operator==(const ValueBase &first, const ValueBase &second)
{
return first.value == second.value;
}
friend bool operator!=(const ValueBase &first, const ValueBase &second)
{
return !(first.value == second.value);
}
ValueType type() const
{
switch (value.index()) {
case 0:
return ValueType::Integer;
case 1:
return ValueType::Float;
case 2:
return ValueType::String;
}
return {};
}
public:
VariantType value;
};
class ValueView : public ValueBase<Utils::SmallStringView>
{
public:
explicit ValueView(ValueBase &&base)
: ValueBase(std::move(base))
{}
template<typename Type>
static ValueView create(Type &&value)
{
return ValueView{ValueBase{value}};
}
};
class Value : public ValueBase<Utils::SmallString>
{
using Base = ValueBase<Utils::SmallString>;
public:
using Base::Base;
explicit Value(ValueView view)
: ValueBase(convert(view))
{}
explicit Value(const QVariant &value)
: ValueBase(convert(value))
{}
explicit Value(Utils::SmallString &&value)
: ValueBase(VariantType{std::move(value)})
{}
explicit Value(const Utils::SmallString &value)
: ValueBase(Utils::SmallStringView(value))
{}
explicit Value(const QString &value)
: ValueBase(VariantType{Utils::SmallString(value)})
{}
friend bool operator!=(const Value &first, const Value &second)
{
return !(first.value == second.value);
}
template<typename Type>
friend bool operator!=(const Value &first, const Type &second)
{
return !(first == second);
}
template<typename Type>
friend bool operator!=(const Type &first, const Value &second)
{
return !(first == second);
}
friend bool operator==(const Value &first, const ValueView &second)
{
if (first.type() != second.type())
return false;
switch (first.type()) {
case ValueType::Integer:
return first.toInteger() == second.toInteger();
case ValueType::Float:
return first.toFloat() == second.toFloat();
case ValueType::String:
return first.toStringView() == second.toStringView();
}
return false;
}
friend bool operator==(const ValueView &first, const Value &second) { return second == first; }
private:
static Base::VariantType convert(const QVariant &value)
{
switch (value.type()) {
case QVariant::Int:
return VariantType{static_cast<long long>(value.toInt())};
case QVariant::LongLong:
return VariantType{value.toLongLong()};
case QVariant::UInt:
return VariantType{static_cast<long long>(value.toUInt())};
case QVariant::Double:
return VariantType{value.toFloat()};
case QVariant::String:
return VariantType{value.toString()};
default:
throw CannotConvert("Cannot convert this QVariant to a ValueBase");
}
}
static Base::VariantType convert(ValueView view)
{
switch (view.type()) {
case ValueType::Integer:
return VariantType{view.toInteger()};
case ValueType::Float:
return VariantType{view.toFloat()};
case ValueType::String:
return VariantType{view.toStringView()};
default:
throw CannotConvert("Cannot convert this QVariant to a ValueBase");
}
}
};
using Values = std::vector<Value>;
} // namespace Sqlite

View File

@@ -28,6 +28,8 @@
#include "theme/theme.h" #include "theme/theme.h"
#include "hostosinfo.h" #include "hostosinfo.h"
#include <utils/qtcassert.h>
#include <QPixmapCache> #include <QPixmapCache>
#include <QPainter> #include <QPainter>
#include <QApplication> #include <QApplication>
@@ -35,6 +37,7 @@
#include <QCommonStyle> #include <QCommonStyle>
#include <QStyleOption> #include <QStyleOption>
#include <QWindow> #include <QWindow>
#include <QFontDatabase>
#include <qmath.h> #include <qmath.h>
// Clamps float color values within (0, 255) // Clamps float color values within (0, 255)
@@ -542,6 +545,48 @@ QLinearGradient StyleHelper::statusBarGradient(const QRect &statusBarRect)
return grad; return grad;
} }
QIcon StyleHelper::getIconFromIconFont(const QString &fontName, const QString &iconSymbol, int fontSize, int iconSize, QColor color)
{
QFontDatabase a;
QTC_ASSERT(a.hasFamily(fontName), {});
if (a.hasFamily(fontName)) {
QIcon icon;
QSize size(iconSize, iconSize);
const int maxDpr = qRound(qApp->devicePixelRatio());
for (int dpr = 1; dpr <= maxDpr; dpr++) {
QPixmap pixmap(size * dpr);
pixmap.setDevicePixelRatio(dpr);
pixmap.fill(Qt::transparent);
QFont font(fontName);
font.setPixelSize(fontSize * dpr);
QPainter painter(&pixmap);
painter.save();
painter.setPen(color);
painter.setFont(font);
painter.drawText(QRectF(QPoint(0, 0), size), iconSymbol);
painter.restore();
icon.addPixmap(pixmap);
}
return icon;
}
return {};
}
QIcon StyleHelper::getIconFromIconFont(const QString &fontName, const QString &iconSymbol, int fontSize, int iconSize)
{
QColor penColor = QApplication::palette("QWidget").color(QPalette::Normal, QPalette::ButtonText);
return getIconFromIconFont(fontName, iconSymbol, fontSize, iconSize, penColor);
}
QString StyleHelper::dpiSpecificImageFile(const QString &fileName) QString StyleHelper::dpiSpecificImageFile(const QString &fileName)
{ {
// See QIcon::addFile() // See QIcon::addFile()

View File

@@ -93,6 +93,9 @@ public:
static void tintImage(QImage &img, const QColor &tintColor); static void tintImage(QImage &img, const QColor &tintColor);
static QLinearGradient statusBarGradient(const QRect &statusBarRect); static QLinearGradient statusBarGradient(const QRect &statusBarRect);
static QIcon getIconFromIconFont(const QString &fontName, const QString &iconSymbol, int fontSize, int iconSize, QColor color);
static QIcon getIconFromIconFont(const QString &fontName, const QString &iconSymbol, int fontSize, int iconSize);
static QString dpiSpecificImageFile(const QString &fileName); static QString dpiSpecificImageFile(const QString &fileName);
static QString imageFileWithResolution(const QString &fileName, int dpr); static QString imageFileWithResolution(const QString &fileName, int dpr);
static QList<int> availableImageResolutions(const QString &fileName); static QList<int> availableImageResolutions(const QString &fileName);

View File

@@ -247,6 +247,7 @@ extend_qtc_plugin(QmlDesigner
snapper.cpp snapper.h snapper.cpp snapper.h
snappinglinecreator.cpp snappinglinecreator.h snappinglinecreator.cpp snappinglinecreator.h
toolbox.cpp toolbox.h toolbox.cpp toolbox.h
transitiontool.cpp transitiontool.h
) )
extend_qtc_plugin(QmlDesigner extend_qtc_plugin(QmlDesigner
@@ -558,6 +559,7 @@ extend_qtc_plugin(QmlDesigner
annotationeditordialog.cpp annotationeditordialog.h annotationeditordialog.ui annotationeditordialog.cpp annotationeditordialog.h annotationeditordialog.ui
annotationeditor.cpp annotationeditor.h annotationeditor.cpp annotationeditor.h
annotationtool.cpp annotationtool.h annotationtool.cpp annotationtool.h
globalannotationeditor.cpp globalannotationeditor.h
) )
extend_qtc_plugin(QmlDesigner extend_qtc_plugin(QmlDesigner
@@ -591,6 +593,13 @@ extend_qtc_plugin(QmlDesigner
texttool/texttool.cpp texttool/texttool.h texttool/texttool.cpp texttool/texttool.h
) )
extend_qtc_plugin(QmlDesigner
SOURCES_PREFIX components/richtexteditor
SOURCES
hyperlinkdialog.cpp hyperlinkdialog.h hyperlinkdialog.ui
richtexteditor.cpp richtexteditor.h hyperlinkdialog.ui
)
extend_qtc_plugin(QmlDesigner extend_qtc_plugin(QmlDesigner
SOURCES_PREFIX components/timelineeditor SOURCES_PREFIX components/timelineeditor
SOURCES SOURCES

View File

@@ -26,6 +26,8 @@
#include "annotationcommenttab.h" #include "annotationcommenttab.h"
#include "ui_annotationcommenttab.h" #include "ui_annotationcommenttab.h"
#include "richtexteditor/richtexteditor.h"
namespace QmlDesigner { namespace QmlDesigner {
AnnotationCommentTab::AnnotationCommentTab(QWidget *parent) : AnnotationCommentTab::AnnotationCommentTab(QWidget *parent) :
@@ -34,6 +36,9 @@ AnnotationCommentTab::AnnotationCommentTab(QWidget *parent) :
{ {
ui->setupUi(this); ui->setupUi(this);
m_editor = new RichTextEditor;
ui->formLayout->setWidget(3, QFormLayout::FieldRole, m_editor);
connect(ui->titleEdit, &QLineEdit::textEdited, connect(ui->titleEdit, &QLineEdit::textEdited,
this, &AnnotationCommentTab::commentTitleChanged); this, &AnnotationCommentTab::commentTitleChanged);
} }
@@ -49,7 +54,7 @@ Comment AnnotationCommentTab::currentComment() const
result.setTitle(ui->titleEdit->text().trimmed()); result.setTitle(ui->titleEdit->text().trimmed());
result.setAuthor(ui->authorEdit->text().trimmed()); result.setAuthor(ui->authorEdit->text().trimmed());
result.setText(ui->textEdit->toPlainText().trimmed()); result.setText(m_editor->richText().trimmed());
if (m_comment.sameContent(result)) if (m_comment.sameContent(result))
result.setTimestamp(m_comment.timestamp()); result.setTimestamp(m_comment.timestamp());
@@ -74,7 +79,7 @@ void AnnotationCommentTab::resetUI()
{ {
ui->titleEdit->setText(m_comment.title()); ui->titleEdit->setText(m_comment.title());
ui->authorEdit->setText(m_comment.author()); ui->authorEdit->setText(m_comment.author());
ui->textEdit->setText(m_comment.text()); m_editor->setRichText(m_comment.text());
if (m_comment.timestamp() > 0) if (m_comment.timestamp() > 0)
ui->timeLabel->setText(m_comment.timestampStr()); ui->timeLabel->setText(m_comment.timestampStr());

View File

@@ -35,6 +35,8 @@ namespace Ui {
class AnnotationCommentTab; class AnnotationCommentTab;
} }
class RichTextEditor;
class AnnotationCommentTab : public QWidget class AnnotationCommentTab : public QWidget
{ {
Q_OBJECT Q_OBJECT
@@ -59,6 +61,7 @@ private slots:
private: private:
Ui::AnnotationCommentTab *ui; Ui::AnnotationCommentTab *ui;
RichTextEditor *m_editor;
Comment m_comment; Comment m_comment;
}; };

View File

@@ -33,13 +33,6 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="1">
<widget class="QTextEdit" name="textEdit">
<property name="tabChangesFocus">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0"> <item row="2" column="0">
<widget class="QLabel" name="authorLabel"> <widget class="QLabel" name="authorLabel">
<property name="text"> <property name="text">
@@ -64,7 +57,6 @@
<tabstops> <tabstops>
<tabstop>titleEdit</tabstop> <tabstop>titleEdit</tabstop>
<tabstop>authorEdit</tabstop> <tabstop>authorEdit</tabstop>
<tabstop>textEdit</tabstop>
</tabstops> </tabstops>
<resources/> <resources/>
<connections/> <connections/>

View File

@@ -2,11 +2,13 @@ HEADERS += $$PWD/annotationtool.h
HEADERS += $$PWD/annotationcommenttab.h HEADERS += $$PWD/annotationcommenttab.h
HEADERS += $$PWD/annotationeditordialog.h HEADERS += $$PWD/annotationeditordialog.h
HEADERS += $$PWD/annotationeditor.h HEADERS += $$PWD/annotationeditor.h
HEADERS += $$PWD/globalannotationeditor.h
SOURCES += $$PWD/annotationtool.cpp SOURCES += $$PWD/annotationtool.cpp
SOURCES += $$PWD/annotationcommenttab.cpp SOURCES += $$PWD/annotationcommenttab.cpp
SOURCES += $$PWD/annotationeditordialog.cpp SOURCES += $$PWD/annotationeditordialog.cpp
SOURCES += $$PWD/annotationeditor.cpp SOURCES += $$PWD/annotationeditor.cpp
SOURCES += $$PWD/globalannotationeditor.cpp
FORMS += $$PWD/annotationcommenttab.ui FORMS += $$PWD/annotationcommenttab.ui
FORMS += $$PWD/annotationeditordialog.ui FORMS += $$PWD/annotationeditordialog.ui

View File

@@ -40,16 +40,16 @@
namespace QmlDesigner { namespace QmlDesigner {
AnnotationEditorDialog::AnnotationEditorDialog(QWidget *parent, const QString &targetId, const QString &customId, const Annotation &annotation) AnnotationEditorDialog::AnnotationEditorDialog(QWidget *parent, const QString &targetId, const QString &customId, const Annotation &annotation, EditorMode mode)
: QDialog(parent) : QDialog(parent)
, ui(new Ui::AnnotationEditorDialog) , ui(new Ui::AnnotationEditorDialog)
, m_customId(customId) , m_customId(customId)
, m_annotation(annotation) , m_annotation(annotation)
, m_editorMode(mode)
{ {
ui->setupUi(this); ui->setupUi(this);
setWindowFlag(Qt::Tool, true); setWindowFlag(Qt::Tool, true);
setWindowTitle(titleString);
setModal(true); setModal(true);
connect(this, &QDialog::accepted, this, &AnnotationEditorDialog::acceptedClicked); connect(this, &QDialog::accepted, this, &AnnotationEditorDialog::acceptedClicked);
@@ -98,6 +98,7 @@ AnnotationEditorDialog::AnnotationEditorDialog(QWidget *parent, const QString &t
ui->tabWidget->setCornerWidget(commentCornerWidget, Qt::TopRightCorner); ui->tabWidget->setCornerWidget(commentCornerWidget, Qt::TopRightCorner);
ui->targetIdEdit->setText(targetId); ui->targetIdEdit->setText(targetId);
changeEditorMode(m_editorMode);
fillFields(); fillFields();
} }
@@ -128,6 +129,39 @@ QString AnnotationEditorDialog::customId() const
return m_customId; return m_customId;
} }
void AnnotationEditorDialog::changeEditorMode(AnnotationEditorDialog::EditorMode mode)
{
switch (mode) {
case ItemAnnotation: {
ui->customIdEdit->setVisible(true);
ui->customIdLabel->setVisible(true);
ui->targetIdEdit->setVisible(true);
ui->targetIdLabel->setVisible(true);
setWindowTitle(annotationEditorTitle);
break;
}
case GlobalAnnotation: {
ui->customIdEdit->clear();
ui->targetIdEdit->clear();
ui->customIdEdit->setVisible(false);
ui->customIdLabel->setVisible(false);
ui->targetIdEdit->setVisible(false);
ui->targetIdLabel->setVisible(false);
setWindowTitle(globalEditorTitle);
break;
}
}
m_editorMode = mode;
}
AnnotationEditorDialog::EditorMode AnnotationEditorDialog::editorMode() const
{
return m_editorMode;
}
void AnnotationEditorDialog::acceptedClicked() void AnnotationEditorDialog::acceptedClicked()
{ {
m_customId = ui->customIdEdit->text(); m_customId = ui->customIdEdit->text();

View File

@@ -40,7 +40,10 @@ class AnnotationEditorDialog : public QDialog
Q_OBJECT Q_OBJECT
public: public:
explicit AnnotationEditorDialog(QWidget *parent, const QString &targetId, const QString &customId, const Annotation &annotation); enum EditorMode { ItemAnnotation, GlobalAnnotation };
explicit AnnotationEditorDialog(QWidget *parent, const QString &targetId, const QString &customId, const Annotation &annotation,
EditorMode mode = EditorMode::ItemAnnotation);
~AnnotationEditorDialog(); ~AnnotationEditorDialog();
void setAnnotation(const Annotation &annotation); void setAnnotation(const Annotation &annotation);
@@ -49,6 +52,9 @@ public:
void setCustomId(const QString &customId); void setCustomId(const QString &customId);
QString customId() const; QString customId() const;
void changeEditorMode(EditorMode mode);
EditorMode editorMode() const;
signals: signals:
void accepted(); void accepted();
@@ -68,12 +74,15 @@ private:
void deleteAllTabs(); void deleteAllTabs();
private: private:
const QString titleString = {tr("Annotation Editor")}; const QString annotationEditorTitle = {tr("Annotation Editor")};
const QString globalEditorTitle = {tr("Global Annotation Editor")};
const QString defaultTabName = {tr("Annotation")}; const QString defaultTabName = {tr("Annotation")};
Ui::AnnotationEditorDialog *ui; Ui::AnnotationEditorDialog *ui;
QString m_customId; QString m_customId;
Annotation m_annotation; Annotation m_annotation;
EditorMode m_editorMode;
}; };
} //namespace QmlDesigner } //namespace QmlDesigner

View File

@@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>700</width> <width>1100</width>
<height>487</height> <height>600</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">

View File

@@ -0,0 +1,148 @@
/****************************************************************************
**
** Copyright (C) 2020 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.
**
****************************************************************************/
#include "globalannotationeditor.h"
#include "annotationeditordialog.h"
#include "annotation.h"
#include "qmlmodelnodeproxy.h"
#include <coreplugin/icore.h>
#include <QObject>
#include <QToolBar>
#include <QAction>
#include <QMessageBox>
namespace QmlDesigner {
GlobalAnnotationEditor::GlobalAnnotationEditor(QObject *)
{
}
GlobalAnnotationEditor::~GlobalAnnotationEditor()
{
hideWidget();
}
void GlobalAnnotationEditor::showWidget()
{
m_dialog = new AnnotationEditorDialog(Core::ICore::dialogParent(),
modelNode().validId(),
"",
modelNode().globalAnnotation(),
AnnotationEditorDialog::EditorMode::GlobalAnnotation);
QObject::connect(m_dialog, &AnnotationEditorDialog::accepted,
this, &GlobalAnnotationEditor::acceptedClicked);
QObject::connect(m_dialog, &AnnotationEditorDialog::rejected,
this, &GlobalAnnotationEditor::cancelClicked);
m_dialog->setAttribute(Qt::WA_DeleteOnClose);
m_dialog->show();
m_dialog->raise();
}
void GlobalAnnotationEditor::showWidget(int x, int y)
{
showWidget();
m_dialog->move(x, y);
}
void GlobalAnnotationEditor::hideWidget()
{
if (m_dialog)
m_dialog->close();
m_dialog = nullptr;
}
void GlobalAnnotationEditor::setModelNode(const ModelNode &modelNode)
{
m_modelNode = modelNode;
}
ModelNode GlobalAnnotationEditor::modelNode() const
{
return m_modelNode;
}
bool GlobalAnnotationEditor::hasAnnotation() const
{
if (m_modelNode.isValid())
return m_modelNode.hasGlobalAnnotation();
return false;
}
void GlobalAnnotationEditor::removeFullAnnotation()
{
if (!m_modelNode.isValid())
return;
QString dialogTitle = tr("Global Annotation");
QMessageBox *deleteDialog = new QMessageBox(Core::ICore::dialogParent());
deleteDialog->setWindowTitle(dialogTitle);
deleteDialog->setText(tr("Delete this annotation?"));
deleteDialog->setStandardButtons(QMessageBox::Yes | QMessageBox::No);
deleteDialog->setDefaultButton(QMessageBox::Yes);
int result = deleteDialog->exec();
if (deleteDialog) deleteDialog->deleteLater();
if (result == QMessageBox::Yes) {
m_modelNode.removeGlobalAnnotation();
}
emit annotationChanged();
}
void GlobalAnnotationEditor::acceptedClicked()
{
if (m_dialog) {
Annotation annotation = m_dialog->annotation();
if (annotation.comments().isEmpty())
m_modelNode.removeGlobalAnnotation();
else
m_modelNode.setGlobalAnnotation(annotation);
}
hideWidget();
emit accepted();
emit annotationChanged();
}
void GlobalAnnotationEditor::cancelClicked()
{
hideWidget();
emit canceled();
emit annotationChanged();
}
} //namespace QmlDesigner

View File

@@ -0,0 +1,75 @@
/****************************************************************************
**
** Copyright (C) 2020 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 <QObject>
#include <QtQml>
#include <QPointer>
#include "annotationeditordialog.h"
#include "annotation.h"
#include "modelnode.h"
namespace QmlDesigner {
class GlobalAnnotationEditor : public QObject
{
Q_OBJECT
public:
explicit GlobalAnnotationEditor(QObject *parent = nullptr);
~GlobalAnnotationEditor();
Q_INVOKABLE void showWidget();
Q_INVOKABLE void showWidget(int x, int y);
Q_INVOKABLE void hideWidget();
void setModelNode(const ModelNode &modelNode);
ModelNode modelNode() const;
Q_INVOKABLE bool hasAnnotation() const;
Q_INVOKABLE void removeFullAnnotation();
signals:
void accepted();
void canceled();
void modelNodeBackendChanged();
void annotationChanged();
private slots:
void acceptedClicked();
void cancelClicked();
private:
QPointer<AnnotationEditorDialog> m_dialog;
ModelNode m_modelNode;
};
} //namespace QmlDesigner

View File

@@ -41,6 +41,7 @@ const char anchorsCategory[] = "Anchors";
const char positionCategory[] = "Position"; const char positionCategory[] = "Position";
const char layoutCategory[] = "Layout"; const char layoutCategory[] = "Layout";
const char flowCategory[] = "Flow"; const char flowCategory[] = "Flow";
const char flowEffectCategory[] = "FlowEffect";
const char flowConnectionCategory[] = "FlowConnection"; const char flowConnectionCategory[] = "FlowConnection";
const char stackedContainerCategory[] = "StackedContainer"; const char stackedContainerCategory[] = "StackedContainer";
const char genericToolBarCategory[] = "GenericToolBar"; const char genericToolBarCategory[] = "GenericToolBar";
@@ -57,6 +58,7 @@ const char anchorsFillCommandId[] = "AnchorsFill";
const char anchorsResetCommandId[] = "AnchorsReset"; const char anchorsResetCommandId[] = "AnchorsReset";
const char removePositionerCommandId[] = "RemovePositioner"; const char removePositionerCommandId[] = "RemovePositioner";
const char createFlowActionAreaCommandId[] = "CreateFlowActionArea"; const char createFlowActionAreaCommandId[] = "CreateFlowActionArea";
const char setFlowStartCommandId[] = "SetFlowStart";
const char layoutRowPositionerCommandId[] = "LayoutRowPositioner"; const char layoutRowPositionerCommandId[] = "LayoutRowPositioner";
const char layoutColumnPositionerCommandId[] = "LayoutColumnPositioner"; const char layoutColumnPositionerCommandId[] = "LayoutColumnPositioner";
const char layoutGridPositionerCommandId[] = "LayoutGridPositioner"; const char layoutGridPositionerCommandId[] = "LayoutGridPositioner";
@@ -85,6 +87,7 @@ const char anchorsCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextM
const char positionCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Position"); const char positionCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Position");
const char layoutCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Layout"); const char layoutCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Layout");
const char flowCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Flow"); const char flowCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Flow");
const char flowEffectCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Flow Effects");
const char stackedContainerCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Stacked Container"); const char stackedContainerCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Stacked Container");
const char cutSelectionDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Cut"); const char cutSelectionDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Cut");
@@ -124,6 +127,7 @@ const char layoutGridPositionerDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerCon
const char layoutFlowPositionerDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Position in Flow"); const char layoutFlowPositionerDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Position in Flow");
const char removePositionerDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Remove Positioner"); const char removePositionerDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Remove Positioner");
const char createFlowActionAreaDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Create Flow Action"); const char createFlowActionAreaDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Create Flow Action");
const char setFlowStartDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Set Flow Start");
const char removeLayoutDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Remove Layout"); const char removeLayoutDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Remove Layout");
const char addItemToStackedContainerDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Add Item"); const char addItemToStackedContainerDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Add Item");

View File

@@ -346,6 +346,12 @@ bool isFlowItem(const SelectionContext &context)
&& QmlFlowItemNode::isValidQmlFlowItemNode(context.currentSingleSelectedNode()); && QmlFlowItemNode::isValidQmlFlowItemNode(context.currentSingleSelectedNode());
} }
bool isFlowTarget(const SelectionContext &context)
{
return context.singleNodeIsSelected()
&& QmlFlowTargetNode::isFlowEditorTarget(context.currentSingleSelectedNode());
}
bool isFlowTransitionItem(const SelectionContext &context) bool isFlowTransitionItem(const SelectionContext &context)
{ {
return context.singleNodeIsSelected() return context.singleNodeIsSelected()
@@ -362,9 +368,9 @@ bool isFlowActionItemItem(const SelectionContext &context)
|| QmlVisualNode::isFlowWildcard(selectedNode)); || QmlVisualNode::isFlowWildcard(selectedNode));
} }
bool isFlowItemOrTransition(const SelectionContext &context) bool isFlowTargetOrTransition(const SelectionContext &context)
{ {
return isFlowItem(context) || isFlowTransitionItem(context); return isFlowTarget(context) || isFlowTransitionItem(context);
} }
class FlowActionConnectAction : public ActionGroup class FlowActionConnectAction : public ActionGroup
@@ -853,15 +859,24 @@ void DesignerActionManager::createDefaultDesignerActions()
priorityLayoutCategory, priorityLayoutCategory,
&layoutOptionVisible)); &layoutOptionVisible));
//isFlowTransitionItem
addDesignerAction(new ActionGroup( addDesignerAction(new ActionGroup(
flowCategoryDisplayName, flowCategoryDisplayName,
flowCategory, flowCategory,
priorityFlowCategory, priorityFlowCategory,
&isFlowItemOrTransition, &isFlowTargetOrTransition,
&flowOptionVisible)); &flowOptionVisible));
auto effectMenu = new ActionGroup(
flowEffectCategoryDisplayName,
flowEffectCategory,
priorityFlowCategory,
&isFlowTransitionItem,
&flowOptionVisible);
effectMenu->setCategory(flowCategory);
addDesignerAction(effectMenu);
addDesignerAction(new ModelNodeFormEditorAction( addDesignerAction(new ModelNodeFormEditorAction(
createFlowActionAreaCommandId, createFlowActionAreaCommandId,
createFlowActionAreaDisplayName, createFlowActionAreaDisplayName,
@@ -874,6 +889,17 @@ void DesignerActionManager::createDefaultDesignerActions()
&isFlowItem, &isFlowItem,
&flowOptionVisible)); &flowOptionVisible));
addDesignerAction(new ModelNodeContextMenuAction(
setFlowStartCommandId,
setFlowStartDisplayName,
{},
flowCategory,
priorityFirst,
{},
&setFlowStartItem,
&isFlowItem,
&flowOptionVisible));
addDesignerAction(new FlowActionConnectAction( addDesignerAction(new FlowActionConnectAction(
flowConnectionCategoryDisplayName, flowConnectionCategoryDisplayName,
flowConnectionCategory, flowConnectionCategory,
@@ -1175,7 +1201,7 @@ void DesignerActionManager::addTransitionEffectAction(const TypeName &typeName)
QByteArray(ComponentCoreConstants::flowAssignEffectCommandId) + typeName, QByteArray(ComponentCoreConstants::flowAssignEffectCommandId) + typeName,
QLatin1String(ComponentCoreConstants::flowAssignEffectDisplayName) + typeName, QLatin1String(ComponentCoreConstants::flowAssignEffectDisplayName) + typeName,
{}, {},
ComponentCoreConstants::flowCategory, ComponentCoreConstants::flowEffectCategory,
{}, {},
typeName == "None" ? 100 : 140, typeName == "None" ? 100 : 140,
[typeName](const SelectionContext &context) [typeName](const SelectionContext &context)

View File

@@ -132,16 +132,22 @@ public:
bool isVisible(const SelectionContext &m_selectionState) const override { return m_visibility(m_selectionState); } bool isVisible(const SelectionContext &m_selectionState) const override { return m_visibility(m_selectionState); }
bool isEnabled(const SelectionContext &m_selectionState) const override { return m_enabled(m_selectionState); } bool isEnabled(const SelectionContext &m_selectionState) const override { return m_enabled(m_selectionState); }
QByteArray category() const override { return QByteArray(); } QByteArray category() const override { return m_category; }
QByteArray menuId() const override { return m_menuId; } QByteArray menuId() const override { return m_menuId; }
int priority() const override { return m_priority; } int priority() const override { return m_priority; }
Type type() const override { return ContextMenu; } Type type() const override { return ContextMenu; }
void setCategory(const QByteArray &catageoryId)
{
m_category = catageoryId;
}
private: private:
const QByteArray m_menuId; const QByteArray m_menuId;
const int m_priority; const int m_priority;
SelectionContextPredicate m_enabled; SelectionContextPredicate m_enabled;
SelectionContextPredicate m_visibility; SelectionContextPredicate m_visibility;
QByteArray m_category;
}; };
class SeperatorDesignerAction : public AbstractAction class SeperatorDesignerAction : public AbstractAction

View File

@@ -295,8 +295,10 @@ void resetSize(const SelectionContext &selectionState)
selectionState.view()->executeInTransaction("DesignerActionManager|resetSize",[selectionState](){ selectionState.view()->executeInTransaction("DesignerActionManager|resetSize",[selectionState](){
foreach (ModelNode node, selectionState.selectedModelNodes()) { foreach (ModelNode node, selectionState.selectedModelNodes()) {
QmlItemNode itemNode(node); QmlItemNode itemNode(node);
itemNode.removeProperty("width"); if (itemNode.isValid()) {
itemNode.removeProperty("height"); itemNode.removeProperty("width");
itemNode.removeProperty("height");
}
} }
}); });
} }
@@ -309,8 +311,10 @@ void resetPosition(const SelectionContext &selectionState)
selectionState.view()->executeInTransaction("DesignerActionManager|resetPosition",[selectionState](){ selectionState.view()->executeInTransaction("DesignerActionManager|resetPosition",[selectionState](){
foreach (ModelNode node, selectionState.selectedModelNodes()) { foreach (ModelNode node, selectionState.selectedModelNodes()) {
QmlItemNode itemNode(node); QmlItemNode itemNode(node);
itemNode.removeProperty("x"); if (itemNode.isValid()) {
itemNode.removeProperty("y"); itemNode.removeProperty("x");
itemNode.removeProperty("y");
}
} }
}); });
} }
@@ -332,7 +336,8 @@ void resetZ(const SelectionContext &selectionState)
selectionState.view()->executeInTransaction("DesignerActionManager|resetZ",[selectionState](){ selectionState.view()->executeInTransaction("DesignerActionManager|resetZ",[selectionState](){
foreach (ModelNode node, selectionState.selectedModelNodes()) { foreach (ModelNode node, selectionState.selectedModelNodes()) {
QmlItemNode itemNode(node); QmlItemNode itemNode(node);
itemNode.removeProperty("z"); if (itemNode.isValid())
itemNode.removeProperty("z");
} }
}); });
} }
@@ -1079,7 +1084,24 @@ void addFlowEffect(const SelectionContext &selectionContext, const TypeName &typ
container.nodeProperty("effect").reparentHere(effectNode); container.nodeProperty("effect").reparentHere(effectNode);
view->setSelectedModelNode(effectNode); view->setSelectedModelNode(effectNode);
} }
}); });
}
void setFlowStartItem(const SelectionContext &selectionContext)
{
AbstractView *view = selectionContext.view();
QTC_ASSERT(view && selectionContext.hasSingleSelectedModelNode(), return);
ModelNode node = selectionContext.currentSingleSelectedNode();
QTC_ASSERT(node.isValid(), return);
QTC_ASSERT(node.metaInfo().isValid(), return);
QmlFlowItemNode flowItem(node);
QTC_ASSERT(flowItem.isValid(), return);
QTC_ASSERT(flowItem.flowView().isValid(), return);
view->executeInTransaction("DesignerActionManager:setFlowStartItem",
[&flowItem](){
flowItem.flowView().setStartFlowItem(flowItem);
});
} }
} // namespace Mode } // namespace Mode

View File

@@ -77,6 +77,7 @@ bool addFontToProject(const QStringList &fileNames, const QString &directory);
void createFlowActionArea(const SelectionContext &selectionContext); void createFlowActionArea(const SelectionContext &selectionContext);
void addTransition(const SelectionContext &selectionState); void addTransition(const SelectionContext &selectionState);
void addFlowEffect(const SelectionContext &selectionState, const TypeName &typeName); void addFlowEffect(const SelectionContext &selectionState, const TypeName &typeName);
void setFlowStartItem(const SelectionContext &selectionContext);
} // namespace ModelNodeOperationso } // namespace ModelNodeOperationso
} //QmlDesigner } //QmlDesigner

View File

@@ -28,19 +28,46 @@
#include <qmldesignerplugin.h> #include <qmldesignerplugin.h>
#include <coreplugin/icore.h>
#include <utils/stylehelper.h> #include <utils/stylehelper.h>
#include <QApplication> #include <QApplication>
#include <QRegExp> #include <QRegExp>
#include <QScreen> #include <QScreen>
#include <QPointer> #include <QPointer>
#include <QQmlEngine>
#include <QQmlComponent>
#include <QQmlProperty>
#include <qqml.h> #include <qqml.h>
static Q_LOGGING_CATEGORY(themeLog, "qtc.qmldesigner.theme", QtWarningMsg)
namespace QmlDesigner { namespace QmlDesigner {
Theme::Theme(Utils::Theme *originTheme, QObject *parent) Theme::Theme(Utils::Theme *originTheme, QObject *parent)
: Utils::Theme(originTheme, parent) : Utils::Theme(originTheme, parent)
, m_constants(nullptr)
{ {
QString constantsPath = Core::ICore::resourcePath() +
QStringLiteral("/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml");
QQmlEngine* engine = new QQmlEngine(this);
QQmlComponent component(engine, QUrl::fromLocalFile(constantsPath));
if (component.status() == QQmlComponent::Ready) {
m_constants = component.create();
}
else if (component.status() == QQmlComponent::Error ) {
qCWarning(themeLog) << "Couldn't load" << constantsPath
<< "due to the following error(s):";
for (QQmlError error : component.errors())
qCWarning(themeLog) << error.toString();
}
else {
qCWarning(themeLog) << "Couldn't load" << constantsPath
<< "the status of the QQmlComponent is" << component.status();
}
} }
QColor Theme::evaluateColorAtThemeInstance(const QString &themeColorName) QColor Theme::evaluateColorAtThemeInstance(const QString &themeColorName)
@@ -129,6 +156,25 @@ QPixmap Theme::getPixmap(const QString &id)
return QmlDesignerIconProvider::getPixmap(id); return QmlDesignerIconProvider::getPixmap(id);
} }
QString Theme::getIconUnicode(Theme::Icon i)
{
if (!instance()->m_constants)
return QString();
const QMetaObject *m = instance()->metaObject();
const char *enumName = "Icon";
int enumIndex = m->indexOfEnumerator(enumName);
if (enumIndex == -1) {
qCWarning(themeLog) << "Couldn't find enum" << enumName;
return QString();
}
QMetaEnum e = m->enumerator(enumIndex);
return instance()->m_constants->property(e.valueToKey(i)).toString();
}
QColor Theme::qmlDesignerBackgroundColorDarker() const QColor Theme::qmlDesignerBackgroundColorDarker() const
{ {
return getColor(QmlDesigner_BackgroundColorDarker); return getColor(QmlDesigner_BackgroundColorDarker);

View File

@@ -41,12 +41,91 @@ namespace QmlDesigner {
class QMLDESIGNERCORE_EXPORT Theme : public Utils::Theme class QMLDESIGNERCORE_EXPORT Theme : public Utils::Theme
{ {
Q_OBJECT Q_OBJECT
Q_ENUMS(Icon)
public: public:
enum Icon {
actionIcon,
actionIconBinding,
addColumnAfter,
addColumnBefore,
addFile,
addRowAfter,
addRowBefore,
addTable,
adsClose,
adsDetach,
adsDropDown,
alignBottom,
alignCenterHorizontal,
alignCenterVertical,
alignLeft,
alignRight,
alignTo,
alignTop,
anchorBaseline,
anchorBottom,
anchorFill,
anchorLeft,
anchorRight,
anchorTop,
annotationBubble,
annotationDecal,
centerHorizontal,
centerVertical,
closeCross,
decisionNode,
deleteColumn,
deleteRow,
deleteTable,
detach,
distributeBottom,
distributeCenterHorizontal,
distributeCenterVertical,
distributeLeft,
distributeOriginBottomRight,
distributeOriginCenter,
distributeOriginNone,
distributeOriginTopLeft,
distributeRight,
distributeSpacingHorizontal,
distributeSpacingVertical,
distributeTop,
edit,
fontStyleBold,
fontStyleItalic,
fontStyleStrikethrough,
fontStyleUnderline,
mergeCells,
redo,
splitColumns,
splitRows,
startNode,
testIcon,
textAlignBottom,
textAlignCenter,
textAlignLeft,
textAlignMiddle,
textAlignRight,
textAlignTop,
textBulletList,
textFullJustification,
textNumberedList,
tickIcon,
triState,
undo,
upDownIcon,
upDownSquare2,
wildcard
};
static Theme *instance(); static Theme *instance();
static QString replaceCssColors(const QString &input); static QString replaceCssColors(const QString &input);
static void setupTheme(QQmlEngine *engine); static void setupTheme(QQmlEngine *engine);
static QColor getColor(Color role); static QColor getColor(Color role);
static QPixmap getPixmap(const QString &id); static QPixmap getPixmap(const QString &id);
static QString getIconUnicode(Theme::Icon i);
Q_INVOKABLE QColor qmlDesignerBackgroundColorDarker() const; Q_INVOKABLE QColor qmlDesignerBackgroundColorDarker() const;
Q_INVOKABLE QColor qmlDesignerBackgroundColorDarkAlternate() const; Q_INVOKABLE QColor qmlDesignerBackgroundColorDarkAlternate() const;
@@ -58,9 +137,12 @@ public:
Q_INVOKABLE int smallFontPixelSize() const; Q_INVOKABLE int smallFontPixelSize() const;
Q_INVOKABLE int captionFontPixelSize() const; Q_INVOKABLE int captionFontPixelSize() const;
Q_INVOKABLE bool highPixelDensity() const; Q_INVOKABLE bool highPixelDensity() const;
private: private:
Theme(Utils::Theme *originTheme, QObject *parent); Theme(Utils::Theme *originTheme, QObject *parent);
QColor evaluateColorAtThemeInstance(const QString &themeColorName); QColor evaluateColorAtThemeInstance(const QString &themeColorName);
QObject *m_constants;
}; };
} // namespace QmlDesigner } // namespace QmlDesigner

View File

@@ -179,6 +179,17 @@ void Edit3DView::importsChanged(const QList<Import> &addedImports,
checkImports(); checkImports();
} }
void Edit3DView::customNotification(const AbstractView *view, const QString &identifier,
const QList<ModelNode> &nodeList, const QList<QVariant> &data)
{
Q_UNUSED(view)
Q_UNUSED(nodeList)
Q_UNUSED(data)
if (identifier == "asset_import_update")
resetPuppet();
}
void Edit3DView::sendInputEvent(QInputEvent *e) const void Edit3DView::sendInputEvent(QInputEvent *e) const
{ {
if (nodeInstanceView()) if (nodeInstanceView())
@@ -301,14 +312,16 @@ QVector<Edit3DAction *> Edit3DView::rightActions() const
void Edit3DView::addQuick3DImport() void Edit3DView::addQuick3DImport()
{ {
const QList<Import> imports = model()->possibleImports(); if (model()) {
for (const auto &import : imports) { const QList<Import> imports = model()->possibleImports();
if (import.url() == "QtQuick3D") { for (const auto &import : imports) {
model()->changeImports({import}, {}); if (import.url() == "QtQuick3D") {
model()->changeImports({import}, {});
// Subcomponent manager update needed to make item library entries appear // Subcomponent manager update needed to make item library entries appear
QmlDesignerPlugin::instance()->currentDesignDocument()->updateSubcomponentManager(); QmlDesignerPlugin::instance()->currentDesignDocument()->updateSubcomponentManager();
return; return;
}
} }
} }
Core::AsynchronousMessageBox::warning(tr("Failed to Add Import"), Core::AsynchronousMessageBox::warning(tr("Failed to Add Import"),

View File

@@ -58,6 +58,7 @@ public:
void modelAttached(Model *model) override; void modelAttached(Model *model) override;
void modelAboutToBeDetached(Model *model) override; void modelAboutToBeDetached(Model *model) override;
void importsChanged(const QList<Import> &addedImports, const QList<Import> &removedImports) override; void importsChanged(const QList<Import> &addedImports, const QList<Import> &removedImports) override;
void customNotification(const AbstractView *view, const QString &identifier, const QList<ModelNode> &nodeList, const QList<QVariant> &data) override;
void sendInputEvent(QInputEvent *e) const; void sendInputEvent(QInputEvent *e) const;
void edit3DViewResized(const QSize &size) const; void edit3DViewResized(const QSize &size) const;

View File

@@ -106,12 +106,11 @@ Edit3DWidget::Edit3DWidget(Edit3DView *view) :
// Onboarding label contains instructions for new users how to get 3D content into the project // Onboarding label contains instructions for new users how to get 3D content into the project
m_onboardingLabel = new QLabel(this); m_onboardingLabel = new QLabel(this);
QString labelText = QString labelText =
"No 3D import here yet!<br><br>" tr("Your file does not import Qt Quick 3D.<br><br>"
"To create a 3D View you need to add the QtQuick3D import to your file.<br>" "To create a 3D view, add the QtQuick3D import to your file in the QML Imports tab of the Library view. Or click"
"You can add the import via the QML Imports tab of the Library view, or alternatively click" " <a href=\"#add_import\"><span style=\"text-decoration:none;color:%1\">here</span></a> "
" <a href=\"#add_import\"><span style=\"text-decoration:none;color:%1\">here</span></a> " "here to add it immediately.<br><br>"
"to add it straight away.<br><br>" "To import 3D assets from another tool, click on the \"Add New Assets...\" button in the Assets tab of the Library view.");
"If you want to import 3D assets from another tool, click on the \"Add New Assets...\" button in the Assets tab of the Library view.";
m_onboardingLabel->setText(labelText.arg(Utils::creatorTheme()->color(Utils::Theme::TextColorLink).name())); m_onboardingLabel->setText(labelText.arg(Utils::creatorTheme()->color(Utils::Theme::TextColorLink).name()));
m_onboardingLabel->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); m_onboardingLabel->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
connect(m_onboardingLabel, &QLabel::linkActivated, this, &Edit3DWidget::linkActivated); connect(m_onboardingLabel, &QLabel::linkActivated, this, &Edit3DWidget::linkActivated);

View File

@@ -36,7 +36,8 @@ SOURCES += formeditoritem.cpp \
contentnoteditableindicator.cpp \ contentnoteditableindicator.cpp \
backgroundaction.cpp \ backgroundaction.cpp \
formeditortoolbutton.cpp \ formeditortoolbutton.cpp \
formeditorannotationicon.cpp formeditorannotationicon.cpp \
transitiontool.cpp
HEADERS += formeditorscene.h \ HEADERS += formeditorscene.h \
formeditorwidget.h \ formeditorwidget.h \
@@ -75,6 +76,7 @@ HEADERS += formeditorscene.h \
contentnoteditableindicator.h \ contentnoteditableindicator.h \
backgroundaction.h \ backgroundaction.h \
formeditortoolbutton.h \ formeditortoolbutton.h \
formeditorannotationicon.h formeditorannotationicon.h \
transitiontool.h
RESOURCES += formeditor.qrc RESOURCES += formeditor.qrc

View File

@@ -339,7 +339,7 @@ QGraphicsItem *FormEditorAnnotationIcon::createCommentBubble(QRectF rect, const
authorItem->update(); authorItem->update();
QGraphicsTextItem *textItem = new QGraphicsTextItem(frameItem); QGraphicsTextItem *textItem = new QGraphicsTextItem(frameItem);
textItem->setPlainText(text); textItem->setHtml(text);
textItem->setDefaultTextColor(textColor); textItem->setDefaultTextColor(textColor);
textItem->setTextWidth(rect.width()); textItem->setTextWidth(rect.width());
textItem->setPos(authorItem->x(), authorItem->boundingRect().height() + authorItem->y() + 5); textItem->setPos(authorItem->x(), authorItem->boundingRect().height() + authorItem->y() + 5);

View File

@@ -32,10 +32,13 @@
#include <nodehints.h> #include <nodehints.h>
#include <nodemetainfo.h> #include <nodemetainfo.h>
#include <theme.h>
#include <utils/theme/theme.h> #include <utils/theme/theme.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <QDebug> #include <QDebug>
#include <QFontDatabase>
#include <QPainter> #include <QPainter>
#include <QPainterPath> #include <QPainterPath>
#include <QStyleOptionGraphicsItem> #include <QStyleOptionGraphicsItem>
@@ -47,6 +50,36 @@
namespace QmlDesigner { namespace QmlDesigner {
const int flowBlockSize = 200; const int flowBlockSize = 200;
const int blockRadius = 18;
const int blockAdjust = 40;
const char startNodeIcon[] = "\u0055";
void drawIcon(QPainter *painter,
int x,
int y,
const QString &iconSymbol,
int fontSize, int iconSize,
const QColor &penColor)
{
static QFontDatabase a;
const QString fontName = "qtds_propertyIconFont.ttf";
Q_ASSERT(a.hasFamily(fontName));
if (a.hasFamily(fontName)) {
QFont font(fontName);
font.setPixelSize(fontSize);
painter->save();
painter->setPen(penColor);
painter->setFont(font);
painter->drawText(QRectF(x, y, iconSize, iconSize), iconSymbol);
painter->restore();
}
}
FormEditorScene *FormEditorItem::scene() const { FormEditorScene *FormEditorItem::scene() const {
return qobject_cast<FormEditorScene*>(QGraphicsItem::scene()); return qobject_cast<FormEditorScene*>(QGraphicsItem::scene());
@@ -578,6 +611,7 @@ void FormEditorFlowActionItem::paint(QPainter *painter, const QStyleOptionGraphi
return; return;
painter->save(); painter->save();
painter->setRenderHint(QPainter::Antialiasing);
QPen pen; QPen pen;
pen.setJoinStyle(Qt::MiterJoin); pen.setJoinStyle(Qt::MiterJoin);
@@ -621,10 +655,9 @@ void FormEditorFlowActionItem::paint(QPainter *painter, const QStyleOptionGraphi
fillColor = qmlItemNode().modelNode().auxiliaryData("fillColor").value<QColor>(); fillColor = qmlItemNode().modelNode().auxiliaryData("fillColor").value<QColor>();
if (fillColor.alpha() > 0) if (fillColor.alpha() > 0)
painter->fillRect(boundingRect(), fillColor); painter->setBrush(fillColor);
painter->drawRect(boundingRect());
painter->drawRoundedRect(boundingRect(), blockRadius, blockRadius);
painter->restore(); painter->restore();
} }
@@ -989,6 +1022,7 @@ void FormEditorTransitionItem::paint(QPainter *painter, const QStyleOptionGraphi
return; return;
painter->save(); painter->save();
painter->setRenderHint(QPainter::Antialiasing);
ResolveConnection resolved(qmlItemNode()); ResolveConnection resolved(qmlItemNode());
@@ -1021,8 +1055,8 @@ void FormEditorTransitionItem::paint(QPainter *painter, const QStyleOptionGraphi
toRect.translate(QmlItemNode(resolved.to).flowPosition()); toRect.translate(QmlItemNode(resolved.to).flowPosition());
if (resolved.isStartLine) { if (resolved.isStartLine) {
fromRect = QRectF(0,0,50,50); fromRect = QRectF(0, 0, 96, 96);
fromRect.translate(QmlItemNode(resolved.to).flowPosition() + QPoint(-120, toRect.height() / 2 - 25)); fromRect.translate(QmlItemNode(resolved.to).flowPosition() + QPoint(-180, toRect.height() / 2 - 96 / 2));
} }
toRect.translate(-pos()); toRect.translate(-pos());
@@ -1075,23 +1109,28 @@ void FormEditorTransitionItem::paint(QPainter *painter, const QStyleOptionGraphi
if (qmlItemNode().modelNode().hasAuxiliaryData("breakPoint")) if (qmlItemNode().modelNode().hasAuxiliaryData("breakPoint"))
breakOffset = qmlItemNode().modelNode().auxiliaryData("breakPoint").toInt(); breakOffset = qmlItemNode().modelNode().auxiliaryData("breakPoint").toInt();
if (resolved.isStartLine)
fromRect.translate(0, inOffset);
paintConnection(painter, fromRect, toRect, width, adjustedWidth ,color, dash, outOffset, inOffset, breakOffset); paintConnection(painter, fromRect, toRect, width, adjustedWidth ,color, dash, outOffset, inOffset, breakOffset);
if (resolved.isStartLine) { if (resolved.isStartLine) {
const QString icon = Theme::getIconUnicode(Theme::startNode);
QPen pen; QPen pen;
pen.setCosmetic(true); pen.setCosmetic(true);
pen.setColor(color); pen.setColor(color);
painter->setPen(pen); painter->setPen(pen);
painter->drawRect(fromRect);
if (scaleFactor > 0.4) { const int iconAdjust = 48;
painter->drawLine(fromRect.topRight() + QPoint(20,10), fromRect.bottomRight() + QPoint(20,-10)); const int offset = 96;
painter->drawLine(fromRect.topRight() + QPoint(25,12), fromRect.bottomRight() + QPoint(25,-12)); const int size = fromRect.width();
painter->drawLine(fromRect.topRight() + QPoint(30,15), fromRect.bottomRight() + QPoint(30,-15)); const int iconSize = size - iconAdjust;
painter->drawLine(fromRect.topRight() + QPoint(35,17), fromRect.bottomRight() + QPoint(35,-17)); const int x = fromRect.topRight().x() - offset;
painter->drawLine(fromRect.topRight() + QPoint(40,20), fromRect.bottomRight() + QPoint(40,-20)); const int y = fromRect.topRight().y();
} painter->drawRoundedRect(x, y , size - 10, size, size / 2, iconSize / 2);
drawIcon(painter, x + iconAdjust / 2, y + iconAdjust / 2, icon, iconSize, iconSize, color);
} }
painter->restore(); painter->restore();
@@ -1140,6 +1179,9 @@ void FormEditorFlowDecisionItem::paint(QPainter *painter, const QStyleOptionGrap
painter->save(); painter->save();
painter->setRenderHint(QPainter::Antialiasing);
painter->setRenderHint(QPainter::SmoothPixmapTransform);
QPen pen; QPen pen;
pen.setJoinStyle(Qt::MiterJoin); pen.setJoinStyle(Qt::MiterJoin);
pen.setCosmetic(true); pen.setCosmetic(true);
@@ -1177,20 +1219,37 @@ void FormEditorFlowDecisionItem::paint(QPainter *painter, const QStyleOptionGrap
if (qmlItemNode().modelNode().hasAuxiliaryData("fillColor")) if (qmlItemNode().modelNode().hasAuxiliaryData("fillColor"))
fillColor = qmlItemNode().modelNode().auxiliaryData("fillColor").value<QColor>(); fillColor = qmlItemNode().modelNode().auxiliaryData("fillColor").value<QColor>();
painter->save();
if (m_iconType == DecisionIcon) {
painter->translate(boundingRect().center());
painter->rotate(45);
painter->translate(-boundingRect().center());
}
if (fillColor.alpha() > 0) if (fillColor.alpha() > 0)
painter->fillRect(boundingRect(), fillColor); painter->setBrush(fillColor);
painter->drawLine(boundingRect().left(), boundingRect().center().y(), int radius = blockRadius;
boundingRect().center().x(), boundingRect().top());
painter->drawLine(boundingRect().center().x(), boundingRect().top(), const QRectF adjustedRect = boundingRect().adjusted(blockAdjust,
boundingRect().right(), boundingRect().center().y()); blockAdjust,
-blockAdjust,
-blockAdjust);
painter->drawLine(boundingRect().right(), boundingRect().center().y(), painter->drawRoundedRect(adjustedRect, radius, radius);
boundingRect().center().x(), boundingRect().bottom());
painter->drawLine(boundingRect().center().x(), boundingRect().bottom(), const int iconDecrement = 32;
boundingRect().left(), boundingRect().center().y()); const int iconSize = adjustedRect.width() - iconDecrement;
const int offset = iconDecrement / 2 + blockAdjust;
painter->restore();
const QString icon = (m_iconType ==
WildcardIcon) ? Theme::getIconUnicode(Theme::wildcard)
: Theme::getIconUnicode(Theme::decisionNode);
drawIcon(painter, offset, offset, icon, iconSize, iconSize, flowColor);
painter->restore(); painter->restore();
} }

View File

@@ -207,9 +207,17 @@ public:
bool flowHitTest(const QPointF &point) const override; bool flowHitTest(const QPointF &point) const override;
protected: protected:
FormEditorFlowDecisionItem(const QmlItemNode &qmlItemNode, FormEditorScene* scene) enum IconType {
: FormEditorFlowItem(qmlItemNode, scene) DecisionIcon,
WildcardIcon
};
FormEditorFlowDecisionItem(const QmlItemNode &qmlItemNode,
FormEditorScene* scene,
IconType iconType = DecisionIcon)
: FormEditorFlowItem(qmlItemNode, scene), m_iconType(iconType)
{} {}
IconType m_iconType;
}; };
class FormEditorFlowWildcardItem : FormEditorFlowDecisionItem class FormEditorFlowWildcardItem : FormEditorFlowDecisionItem
@@ -221,8 +229,9 @@ public:
protected: protected:
FormEditorFlowWildcardItem(const QmlItemNode &qmlItemNode, FormEditorScene* scene) FormEditorFlowWildcardItem(const QmlItemNode &qmlItemNode, FormEditorScene* scene)
: FormEditorFlowDecisionItem(qmlItemNode, scene) : FormEditorFlowDecisionItem(qmlItemNode, scene, WildcardIcon)
{} {
}
}; };
inline int FormEditorItem::type() const inline int FormEditorItem::type() const

View File

@@ -0,0 +1,438 @@
/****************************************************************************
**
** Copyright (C) 2020 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.
**
****************************************************************************/
#include "transitiontool.h"
#include <formeditorscene.h>
#include <formeditorview.h>
#include <formeditorwidget.h>
#include <itemutilfunctions.h>
#include <formeditoritem.h>
#include <layeritem.h>
#include <resizehandleitem.h>
#include <bindingproperty.h>
#include <nodeabstractproperty.h>
#include <nodelistproperty.h>
#include <nodemetainfo.h>
#include <qmlitemnode.h>
#include <qmldesignerplugin.h>
#include <abstractaction.h>
#include <designeractionmanager.h>
#include <variantproperty.h>
#include <rewritingexception.h>
#include <rewritertransaction.h>
#include <coreplugin/icore.h>
#include <utils/qtcassert.h>
#include <QApplication>
#include <QGraphicsSceneMouseEvent>
#include <QAction>
#include <QMessageBox>
#include <QPair>
#include <QGraphicsSceneMouseEvent>
namespace QmlDesigner {
static bool isTransitionSource(const ModelNode &node)
{
return QmlFlowTargetNode::isFlowEditorTarget(node);
}
static bool isTransitionTarget(const QmlItemNode &node)
{
return QmlFlowTargetNode::isFlowEditorTarget(node)
&& !node.isFlowActionArea()
&& !node.isFlowWildcard();
}
class TransitionToolAction : public AbstractAction
{
public:
TransitionToolAction(const QString &name) : AbstractAction(name) {}
QByteArray category() const override
{
return QByteArray();
}
QByteArray menuId() const override
{
return "TransitionTool";
}
int priority() const override
{
return CustomActionsPriority;
}
Type type() const override
{
return ContextMenuAction;
}
protected:
bool isVisible(const SelectionContext &selectionContext) const override
{
if (selectionContext.scenePosition().isNull())
return false;
if (selectionContext.singleNodeIsSelected())
return isTransitionSource(selectionContext.currentSingleSelectedNode());
return false;
}
bool isEnabled(const SelectionContext &selectionContext) const override
{
return isVisible(selectionContext);
}
};
class TransitionCustomAction : public TransitionToolAction
{
public:
TransitionCustomAction(const QString &name) : TransitionToolAction(name) {}
QByteArray category() const override
{
return ComponentCoreConstants::flowCategory;
}
SelectionContext selectionContext() const
{
return AbstractAction::selectionContext();
}
};
static QRectF paintedBoundingRect(FormEditorItem *item)
{
QRectF boundingRect = item->qmlItemNode().instanceBoundingRect();
if (boundingRect.width() < 4)
boundingRect = item->boundingRect();
return boundingRect;
}
static QPointF centerPoint(FormEditorItem *item)
{
QRectF boundingRect = paintedBoundingRect(item);
return QPointF(item->scenePos().x() + boundingRect.width() / 2,
item->scenePos().y() + boundingRect.height() / 2);
}
void static setToBoundingRect(QGraphicsRectItem *rect, FormEditorItem *item)
{
QPolygonF boundingRectInSceneSpace(item->mapToScene(paintedBoundingRect(item)));
rect->setRect(boundingRectInSceneSpace.boundingRect());
}
TransitionTool::TransitionTool()
: QObject(), AbstractCustomTool()
{
TransitionToolAction *transitionToolAction = new TransitionToolAction(tr("Add Transition"));
QmlDesignerPlugin::instance()->designerActionManager().addDesignerAction(transitionToolAction);
connect(transitionToolAction->action(), &QAction::triggered,
this, &TransitionTool::activateTool);
TransitionCustomAction *removeAction = new TransitionCustomAction(tr("Remove Transitions"));
QmlDesignerPlugin::instance()->designerActionManager().addDesignerAction(removeAction);
connect(removeAction->action(), &QAction::triggered,
this, [removeAction](){
SelectionContext context = removeAction->selectionContext();
QmlFlowTargetNode node = QmlFlowTargetNode(context.currentSingleSelectedNode());
context.view()->executeInTransaction("Remove Transitions", [&node](){
if (node.isValid())
node.removeTransitions();
});
});
TransitionCustomAction *removeAllTransitionsAction = new TransitionCustomAction(tr("Remove All Transitions"));
QmlDesignerPlugin::instance()->designerActionManager().addDesignerAction(removeAllTransitionsAction);
connect(removeAllTransitionsAction->action(), &QAction::triggered,
this, [removeAllTransitionsAction](){
if (QMessageBox::question(Core::ICore::dialogParent(),
tr("Remove All Transitions"),
tr("Do you really want to remove all transitions?"),
QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes)
return;
SelectionContext context = removeAllTransitionsAction->selectionContext();
QmlFlowTargetNode node = QmlFlowTargetNode(context.currentSingleSelectedNode());
context.view()->executeInTransaction("Remove All Transitions", [&node](){
if (node.isValid() && node.flowView().isValid())
node.flowView().removeAllTransitions();
});
});
TransitionCustomAction *removeDanglingTransitionAction = new TransitionCustomAction(tr("Remove Dangling Transitions"));
QmlDesignerPlugin::instance()->designerActionManager().addDesignerAction(removeDanglingTransitionAction);
connect(removeDanglingTransitionAction->action(), &QAction::triggered,
this, [removeDanglingTransitionAction](){
SelectionContext context = removeDanglingTransitionAction->selectionContext();
QmlFlowTargetNode node = QmlFlowTargetNode(context.currentSingleSelectedNode());
context.view()->executeInTransaction("Remove Dangling Transitions", [&node](){
if (node.isValid() && node.flowView().isValid())
node.flowView().removeDanglingTransitions();
});
});
}
TransitionTool::~TransitionTool()
{
}
void TransitionTool::clear()
{
m_lineItem.reset(nullptr);
m_rectangleItem1.reset(nullptr);
m_rectangleItem2.reset(nullptr);
AbstractFormEditorTool::clear();
}
void TransitionTool::mousePressEvent(const QList<QGraphicsItem*> &itemList,
QGraphicsSceneMouseEvent *event)
{
if (m_blockEvents)
return;
if (event->button() != Qt::LeftButton)
return;
AbstractFormEditorTool::mousePressEvent(itemList, event);
TransitionTool::mouseMoveEvent(itemList, event);
}
void TransitionTool::mouseMoveEvent(const QList<QGraphicsItem*> & itemList,
QGraphicsSceneMouseEvent * event)
{
if (!m_lineItem)
return;
QTC_ASSERT(currentFormEditorItem(), return);
const QPointF pos = centerPoint(m_formEditorItem);
lineItem()->setLine(pos.x(),
pos.y(),
event->scenePos().x(),
event->scenePos().y());
FormEditorItem *formEditorItem = nearestFormEditorItem(event->scenePos(), itemList);
if (formEditorItem
&& formEditorItem->qmlItemNode().isValid()
&& isTransitionTarget(formEditorItem->qmlItemNode().modelNode())) {
rectangleItem2()->setVisible(true);
setToBoundingRect(rectangleItem2(), formEditorItem);
} else {
rectangleItem2()->setVisible(false);
}
}
void TransitionTool::hoverMoveEvent(const QList<QGraphicsItem*> & itemList,
QGraphicsSceneMouseEvent *event)
{
mouseMoveEvent(itemList, event);
}
void TransitionTool::keyPressEvent(QKeyEvent * /*keyEvent*/)
{
}
void TransitionTool::keyReleaseEvent(QKeyEvent * /*keyEvent*/)
{
view()->changeToSelectionTool();
}
void TransitionTool::dragLeaveEvent(const QList<QGraphicsItem*> &/*itemList*/, QGraphicsSceneDragDropEvent * /*event*/)
{
}
void TransitionTool::dragMoveEvent(const QList<QGraphicsItem*> &/*itemList*/, QGraphicsSceneDragDropEvent * /*event*/)
{
}
void TransitionTool::mouseReleaseEvent(const QList<QGraphicsItem*> &itemList,
QGraphicsSceneMouseEvent *event)
{
if (m_blockEvents)
return;
if (event->button() == Qt::LeftButton) {
FormEditorItem *formEditorItem = nearestFormEditorItem(event->scenePos(), itemList);
if (formEditorItem
&& QmlFlowTargetNode(formEditorItem->qmlItemNode().modelNode()).isValid())
createTransition(m_formEditorItem, formEditorItem);
}
view()->changeToSelectionTool();
}
void TransitionTool::mouseDoubleClickEvent(const QList<QGraphicsItem*> &itemList, QGraphicsSceneMouseEvent *event)
{
AbstractFormEditorTool::mouseDoubleClickEvent(itemList, event);
}
void TransitionTool::itemsAboutToRemoved(const QList<FormEditorItem*> &)
{
view()->changeCurrentToolTo(this);
}
void TransitionTool::selectedItemsChanged(const QList<FormEditorItem*> &itemList)
{
if (!itemList.isEmpty()) {
createItems();
m_formEditorItem = itemList.first();
setToBoundingRect(rectangleItem1(), m_formEditorItem);
}
}
void TransitionTool::instancesCompleted(const QList<FormEditorItem*> & /*itemList*/)
{
}
void TransitionTool::instancesParentChanged(const QList<FormEditorItem *> & /*itemList*/)
{
}
void TransitionTool::instancePropertyChange(const QList<QPair<ModelNode, PropertyName> > & /*propertyList*/)
{
}
void TransitionTool::formEditorItemsChanged(const QList<FormEditorItem*> & /*itemList*/)
{
}
int TransitionTool::wantHandleItem(const ModelNode &modelNode) const
{
if (isTransitionSource(modelNode))
return 10;
return 0;
}
QString TransitionTool::name() const
{
return tr("Transition Tool");
}
void TransitionTool::activateTool()
{
view()->changeToCustomTool();
}
void TransitionTool::unblock()
{
m_blockEvents = false;
}
QGraphicsLineItem *TransitionTool::lineItem()
{
return m_lineItem.get();
}
QGraphicsRectItem *TransitionTool::rectangleItem1()
{
return m_rectangleItem1.get();
}
QGraphicsRectItem *TransitionTool::rectangleItem2()
{
return m_rectangleItem2.get();
}
FormEditorItem *TransitionTool::currentFormEditorItem() const
{
if (scene()->items().contains(m_formEditorItem))
return m_formEditorItem;
return nullptr;
}
void TransitionTool::createItems() {
m_blockEvents = true;
QTimer::singleShot(200, this, [this](){ unblock(); });
if (!lineItem())
m_lineItem.reset(new QGraphicsLineItem(scene()->manipulatorLayerItem()));
if (!rectangleItem1())
m_rectangleItem1.reset(new QGraphicsRectItem(scene()->manipulatorLayerItem()));
if (!rectangleItem2())
m_rectangleItem2.reset(new QGraphicsRectItem(scene()->manipulatorLayerItem()));
m_rectangleItem2->setVisible(false);
QPen pen;
pen.setColor(QColor(Qt::lightGray));
pen.setStyle(Qt::DashLine);
pen.setWidth(0);
m_lineItem->setPen(pen);
pen.setColor(QColor(108, 141, 221));
pen.setStyle(Qt::SolidLine);
pen.setWidth(4);
pen.setCosmetic(true);
m_rectangleItem1->setPen(pen);
m_rectangleItem2->setPen(pen);
}
void TransitionTool::createTransition(FormEditorItem *source, FormEditorItem *target)
{
QmlFlowTargetNode sourceNode(source->qmlItemNode().modelNode());
QmlFlowTargetNode targetNode(target->qmlItemNode().modelNode());
if (sourceNode.isValid() && targetNode.isValid()
&& sourceNode != targetNode
&& !targetNode.isFlowActionArea()
&& !targetNode.isFlowWildcard()) {
view()->executeInTransaction("create transition", [&sourceNode, targetNode](){
sourceNode.assignTargetItem(targetNode);
});
} else {
qWarning() << Q_FUNC_INFO << "nodes invalid";
}
}
}

View File

@@ -0,0 +1,98 @@
/****************************************************************************
**
** Copyright (C) 2020 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 "abstractcustomtool.h"
#include "selectionindicator.h"
#include <QGraphicsLineItem>
#include <QHash>
#include <QPointer>
#include <memory>
namespace QmlDesigner {
class TransitionTool : public QObject, public AbstractCustomTool
{
Q_OBJECT
public:
TransitionTool();
~TransitionTool();
void mousePressEvent(const QList<QGraphicsItem*> &itemList,
QGraphicsSceneMouseEvent *event) override;
void mouseMoveEvent(const QList<QGraphicsItem*> &itemList,
QGraphicsSceneMouseEvent *event) override;
void mouseReleaseEvent(const QList<QGraphicsItem*> &itemList,
QGraphicsSceneMouseEvent *event) override;
void mouseDoubleClickEvent(const QList<QGraphicsItem*> &itemList,
QGraphicsSceneMouseEvent *event) override;
void hoverMoveEvent(const QList<QGraphicsItem*> &itemList,
QGraphicsSceneMouseEvent *event) override;
void keyPressEvent(QKeyEvent *event) override;
void keyReleaseEvent(QKeyEvent *keyEvent) override;
void dragLeaveEvent(const QList<QGraphicsItem*> &itemList,
QGraphicsSceneDragDropEvent * event) override;
void dragMoveEvent(const QList<QGraphicsItem*> &itemList,
QGraphicsSceneDragDropEvent * event) override;
void itemsAboutToRemoved(const QList<FormEditorItem*> &itemList) override;
void selectedItemsChanged(const QList<FormEditorItem*> &itemList) override;
void instancesCompleted(const QList<FormEditorItem*> &itemList) override;
void instancesParentChanged(const QList<FormEditorItem *> &itemList) override;
void instancePropertyChange(const QList<QPair<ModelNode, PropertyName> > &propertyList) override;
void clear() override;
void formEditorItemsChanged(const QList<FormEditorItem*> &itemList) override;
int wantHandleItem(const ModelNode &modelNode) const override;
QString name() const override;
void activateTool();
void unblock();
QGraphicsLineItem *lineItem();
QGraphicsRectItem *rectangleItem1();
QGraphicsRectItem *rectangleItem2();
private:
FormEditorItem *currentFormEditorItem() const;
void createItems();
void createTransition(FormEditorItem *item1, FormEditorItem *item2);
FormEditorItem* m_formEditorItem;
std::unique_ptr<QGraphicsLineItem> m_lineItem;
std::unique_ptr<QGraphicsRectItem> m_rectangleItem1;
std::unique_ptr<QGraphicsRectItem> m_rectangleItem2;
bool m_blockEvents = true;
};
} //QmlDesigner

View File

@@ -81,14 +81,16 @@ void ImportManagerView::modelAboutToBeDetached(Model *model)
void ImportManagerView::importsChanged(const QList<Import> &/*addedImports*/, const QList<Import> &/*removedImports*/) void ImportManagerView::importsChanged(const QList<Import> &/*addedImports*/, const QList<Import> &/*removedImports*/)
{ {
if (m_importsWidget) if (m_importsWidget) {
m_importsWidget->setImports(model()->imports()); m_importsWidget->setImports(model()->imports());
// setImports recreates labels, so we need to update used imports, as it is not guaranteed
// usedImportsChanged notification will come after this.
m_importsWidget->setUsedImports(model()->usedImports());
}
} }
void ImportManagerView::possibleImportsChanged(const QList<Import> &/*possibleImports*/) void ImportManagerView::possibleImportsChanged(const QList<Import> &/*possibleImports*/)
{ {
QmlDesignerPlugin::instance()->currentDesignDocument()->updateSubcomponentManager();
if (m_importsWidget) if (m_importsWidget)
m_importsWidget->setPossibleImports(model()->possibleImports()); m_importsWidget->setPossibleImports(model()->possibleImports());
} }

View File

@@ -32,6 +32,9 @@
#include "utils/outputformatter.h" #include "utils/outputformatter.h"
#include "theme.h" #include "theme.h"
#include <projectexplorer/project.h>
#include <projectexplorer/session.h>
#include <QtCore/qfileinfo.h> #include <QtCore/qfileinfo.h>
#include <QtCore/qdir.h> #include <QtCore/qdir.h>
#include <QtCore/qloggingcategory.h> #include <QtCore/qloggingcategory.h>
@@ -97,6 +100,20 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(const QStringList &im
ui->buttonBox->button(QDialogButtonBox::Close)->setDefault(true); ui->buttonBox->button(QDialogButtonBox::Close)->setDefault(true);
QStringList importPaths;
auto doc = QmlDesignerPlugin::instance()->currentDesignDocument();
if (doc) {
Model *model = doc->currentModel();
if (model)
importPaths = model->importPaths();
}
QString targetDir = defaulTargetDirectory;
ProjectExplorer::Project *currentProject = ProjectExplorer::SessionManager::projectForFile(doc->fileName());
if (currentProject)
targetDir = currentProject->projectDirectory().toString();
// Import is always done under known folder. The order of preference for folder is: // Import is always done under known folder. The order of preference for folder is:
// 1) An existing QUICK_3D_ASSETS_FOLDER under DEFAULT_ASSET_IMPORT_FOLDER project import path // 1) An existing QUICK_3D_ASSETS_FOLDER under DEFAULT_ASSET_IMPORT_FOLDER project import path
// 2) An existing QUICK_3D_ASSETS_FOLDER under any project import path // 2) An existing QUICK_3D_ASSETS_FOLDER under any project import path
@@ -105,19 +122,11 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(const QStringList &im
// 5) New QUICK_3D_ASSETS_FOLDER under new DEFAULT_ASSET_IMPORT_FOLDER under project // 5) New QUICK_3D_ASSETS_FOLDER under new DEFAULT_ASSET_IMPORT_FOLDER under project
const QString defaultAssetFolder = QLatin1String(Constants::DEFAULT_ASSET_IMPORT_FOLDER); const QString defaultAssetFolder = QLatin1String(Constants::DEFAULT_ASSET_IMPORT_FOLDER);
const QString quick3DFolder = QLatin1String(Constants::QUICK_3D_ASSETS_FOLDER); const QString quick3DFolder = QLatin1String(Constants::QUICK_3D_ASSETS_FOLDER);
QString candidatePath = defaulTargetDirectory + defaultAssetFolder + quick3DFolder; QString candidatePath = targetDir + defaultAssetFolder + quick3DFolder;
int candidatePriority = 5; int candidatePriority = 5;
QStringList importPaths;
auto doc = QmlDesignerPlugin::instance()->currentDesignDocument();
if (doc) {
Model *model = doc->currentModel();
if (model)
importPaths = model->importPaths();
}
for (auto importPath : qAsConst(importPaths)) { for (auto importPath : qAsConst(importPaths)) {
if (importPath.startsWith(defaulTargetDirectory)) { if (importPath.startsWith(targetDir)) {
const bool isDefaultFolder = importPath.endsWith(defaultAssetFolder); const bool isDefaultFolder = importPath.endsWith(defaultAssetFolder);
const QString assetFolder = importPath + quick3DFolder; const QString assetFolder = importPath + quick3DFolder;
const bool exists = QFileInfo(assetFolder).exists(); const bool exists = QFileInfo(assetFolder).exists();

View File

@@ -280,7 +280,16 @@ void ItemLibraryAssetImporter::parseQuick3DAsset(const QString &file, const QVar
return; return;
} }
QString originalAssetName = assetName;
if (targetDir.exists(assetName)) { if (targetDir.exists(assetName)) {
// If we have a file system with case insensitive filenames, assetName may be
// different from the existing name. Modify assetName to ensure exact match to
// the overwritten old asset capitalization
const QStringList assetDirs = targetDir.entryList({assetName}, QDir::Dirs);
if (assetDirs.size() == 1) {
assetName = assetDirs[0];
targetDirPath = targetDir.filePath(assetName);
}
if (!confirmAssetOverwrite(assetName)) { if (!confirmAssetOverwrite(assetName)) {
addWarning(tr("Skipped import of existing asset: \"%1\"").arg(assetName)); addWarning(tr("Skipped import of existing asset: \"%1\"").arg(assetName));
return; return;
@@ -306,6 +315,16 @@ void ItemLibraryAssetImporter::parseQuick3DAsset(const QString &file, const QVar
return; return;
} }
// The importer is reset after every import to avoid issues with it caching various things
m_quick3DAssetImporter.reset(new QSSGAssetImportManager);
if (originalAssetName != assetName) {
// Fix the generated qml file name
const QString assetQml = originalAssetName + ".qml";
if (outDir.exists(assetQml))
outDir.rename(assetQml, assetName + ".qml");
}
QHash<QString, QString> assetFiles; QHash<QString, QString> assetFiles;
const int outDirPathSize = outDir.path().size(); const int outDirPathSize = outDir.path().size();
auto insertAsset = [&](const QString &filePath) { auto insertAsset = [&](const QString &filePath) {
@@ -512,18 +531,24 @@ void ItemLibraryAssetImporter::finalizeQuick3DImport()
addInfo(progressTitle); addInfo(progressTitle);
notifyProgress(0, progressTitle); notifyProgress(0, progressTitle);
// There is an inbuilt delay before rewriter change actually updates the data model, // First we have to wait a while to ensure qmljs detects new files and updates its
// so we need to wait for a moment to allow the change to take effect. // internal model. Then we make a non-change to the document to trigger qmljs snapshot
// update. There is an inbuilt delay before rewriter change actually updates the data
// model, so we need to wait for another moment to allow the change to take effect.
// Otherwise subsequent subcomponent manager update won't detect new imports properly. // Otherwise subsequent subcomponent manager update won't detect new imports properly.
QTimer *timer = new QTimer(parent()); QTimer *timer = new QTimer(parent());
static int counter; static int counter;
counter = 0; counter = 0;
timer->callOnTimeout([this, timer, progressTitle, model]() { timer->callOnTimeout([this, timer, progressTitle, model, doc]() {
if (!isCancelled()) { if (!isCancelled()) {
notifyProgress(++counter * 10, progressTitle); notifyProgress(++counter * 5, progressTitle);
if (counter >= 10) { if (counter == 10) {
// Trigger underlying qmljs snapshot update by making a non-change to the doc
model->rewriterView()->textModifier()->replace(0, 0, {}); model->rewriterView()->textModifier()->replace(0, 0, {});
} else if (counter == 19) {
doc->updateSubcomponentManager();
} else if (counter >= 20) {
if (!m_overwrittenImports.isEmpty())
model->rewriterView()->emitCustomNotification("asset_import_update");
timer->stop(); timer->stop();
notifyFinished(); notifyFinished();
} }

View File

@@ -43,6 +43,7 @@ public:
virtual void notifyModelNodesRemoved(const QList<ModelNode> &modelNodes) = 0; virtual void notifyModelNodesRemoved(const QList<ModelNode> &modelNodes) = 0;
virtual void notifyModelNodesInserted(const QList<ModelNode> &modelNodes) = 0; virtual void notifyModelNodesInserted(const QList<ModelNode> &modelNodes) = 0;
virtual void notifyModelNodesMoved(const QList<ModelNode> &modelNodes) = 0; virtual void notifyModelNodesMoved(const QList<ModelNode> &modelNodes) = 0;
virtual void notifyIconsChanged() = 0;
virtual void setFilter(bool showObjects) = 0; virtual void setFilter(bool showObjects) = 0;
virtual void resetModel() = 0; virtual void resetModel() = 0;
}; };

View File

@@ -695,6 +695,11 @@ void NavigatorTreeModel::notifyModelNodesMoved(const QList<ModelNode> &modelNode
emit layoutChanged(indexes); emit layoutChanged(indexes);
} }
void NavigatorTreeModel::notifyIconsChanged()
{
emit dataChanged(index(0, 0), index(rowCount(), 0), {Qt::DecorationRole});
}
void NavigatorTreeModel::setFilter(bool showOnlyVisibleItems) void NavigatorTreeModel::setFilter(bool showOnlyVisibleItems)
{ {
m_showOnlyVisibleItems = showOnlyVisibleItems; m_showOnlyVisibleItems = showOnlyVisibleItems;

View File

@@ -87,6 +87,7 @@ public:
void notifyModelNodesRemoved(const QList<ModelNode> &modelNodes) override; void notifyModelNodesRemoved(const QList<ModelNode> &modelNodes) override;
void notifyModelNodesInserted(const QList<ModelNode> &modelNodes) override; void notifyModelNodesInserted(const QList<ModelNode> &modelNodes) override;
void notifyModelNodesMoved(const QList<ModelNode> &modelNodes) override; void notifyModelNodesMoved(const QList<ModelNode> &modelNodes) override;
void notifyIconsChanged() override;
void setFilter(bool showOnlyVisibleItems) override; void setFilter(bool showOnlyVisibleItems) override;
void resetModel() override; void resetModel() override;

View File

@@ -147,6 +147,17 @@ void NavigatorView::bindingPropertiesChanged(const QList<BindingProperty> & prop
} }
} }
void NavigatorView::customNotification(const AbstractView *view, const QString &identifier,
const QList<ModelNode> &nodeList, const QList<QVariant> &data)
{
Q_UNUSED(view)
Q_UNUSED(nodeList)
Q_UNUSED(data)
if (identifier == "asset_import_update")
m_currentModelInterface->notifyIconsChanged();
}
void NavigatorView::handleChangedExport(const ModelNode &modelNode, bool exported) void NavigatorView::handleChangedExport(const ModelNode &modelNode, bool exported)
{ {
const ModelNode rootNode = rootModelNode(); const ModelNode rootNode = rootModelNode();
@@ -434,7 +445,7 @@ void NavigatorView::updateItemSelection()
// make sure selected nodes a visible // make sure selected nodes a visible
foreach (const QModelIndex &selectedIndex, itemSelection.indexes()) { foreach (const QModelIndex &selectedIndex, itemSelection.indexes()) {
if (selectedIndex.column() == 0) if (selectedIndex.column() == 0)
expandRecursively(selectedIndex); expandAncestors(selectedIndex);
} }
} }
@@ -458,9 +469,9 @@ bool NavigatorView::blockSelectionChangedSignal(bool block)
return oldValue; return oldValue;
} }
void NavigatorView::expandRecursively(const QModelIndex &index) void NavigatorView::expandAncestors(const QModelIndex &index)
{ {
QModelIndex currentIndex = index; QModelIndex currentIndex = index.parent();
while (currentIndex.isValid()) { while (currentIndex.isValid()) {
if (!treeWidget()->isExpanded(currentIndex)) if (!treeWidget()->isExpanded(currentIndex))
treeWidget()->expand(currentIndex); treeWidget()->expand(currentIndex);

View File

@@ -84,6 +84,8 @@ public:
void bindingPropertiesChanged(const QList<BindingProperty> &propertyList, PropertyChangeFlags) override; void bindingPropertiesChanged(const QList<BindingProperty> &propertyList, PropertyChangeFlags) override;
void customNotification(const AbstractView *view, const QString &identifier, const QList<ModelNode> &nodeList, const QList<QVariant> &data) override;
void handleChangedExport(const ModelNode &modelNode, bool exported); void handleChangedExport(const ModelNode &modelNode, bool exported);
bool isNodeInvisible(const ModelNode &modelNode) const; bool isNodeInvisible(const ModelNode &modelNode) const;
@@ -108,7 +110,7 @@ protected: //functions
QTreeView *treeWidget() const; QTreeView *treeWidget() const;
NavigatorTreeModel *treeModel(); NavigatorTreeModel *treeModel();
bool blockSelectionChangedSignal(bool block); bool blockSelectionChangedSignal(bool block);
void expandRecursively(const QModelIndex &index); void expandAncestors(const QModelIndex &index);
void reparentAndCatch(NodeAbstractProperty property, const ModelNode &modelNode); void reparentAndCatch(NodeAbstractProperty property, const ModelNode &modelNode);
void setupWidget(); void setupWidget();

View File

@@ -0,0 +1,69 @@
/****************************************************************************
**
** Copyright (C) 2020 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.
**
****************************************************************************/
#include "hyperlinkdialog.h"
#include "ui_hyperlinkdialog.h"
#include <QPushButton>
namespace QmlDesigner {
HyperlinkDialog::HyperlinkDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::HyperlinkDialog)
{
ui->setupUi(this);
connect (ui->linkEdit, &QLineEdit::textChanged, [this] () {
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!(ui->linkEdit->text().isEmpty()));
});
}
HyperlinkDialog::~HyperlinkDialog()
{
delete ui;
}
QString HyperlinkDialog::getLink() const
{
return ui->linkEdit->text().trimmed();
}
void HyperlinkDialog::setLink(const QString &link)
{
ui->linkEdit->setText(link);
}
QString HyperlinkDialog::getAnchor() const
{
return ui->anchorEdit->text().trimmed();
}
void HyperlinkDialog::setAnchor(const QString &anchor)
{
ui->anchorEdit->setText(anchor);
}
}

View File

@@ -0,0 +1,54 @@
/****************************************************************************
**
** Copyright (C) 2020 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 <QDialog>
namespace QmlDesigner {
namespace Ui {
class HyperlinkDialog;
}
class HyperlinkDialog : public QDialog
{
Q_OBJECT
public:
explicit HyperlinkDialog(QWidget *parent = nullptr);
~HyperlinkDialog();
QString getLink() const;
void setLink(const QString &link);
QString getAnchor() const;
void setAnchor(const QString &anchor);
private:
Ui::HyperlinkDialog *ui;
};
}

View File

@@ -0,0 +1,88 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>QmlDesigner::HyperlinkDialog</class>
<widget class="QDialog" name="QmlDesigner::HyperlinkDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>403</width>
<height>156</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true">Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Link</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="linkEdit"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Anchor</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="anchorEdit"/>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>QmlDesigner::HyperlinkDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>QmlDesigner::HyperlinkDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@@ -0,0 +1,684 @@
/****************************************************************************
**
** Copyright (C) 2020 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.
**
****************************************************************************/
#include "richtexteditor.h"
#include "ui_richtexteditor.h"
#include "hyperlinkdialog.h"
#include <functional>
#include <QToolButton>
#include <QAction>
#include <QStyle>
#include <QStyleFactory>
#include <QColorDialog>
#include <QWidgetAction>
#include <QTextTable>
#include <QScopeGuard>
#include <QPointer>
#include <utils/stylehelper.h>
namespace QmlDesigner {
template <class T>
class FontWidgetActions : public QWidgetAction {
public:
FontWidgetActions(QObject *parent = nullptr)
: QWidgetAction(parent) {}
~FontWidgetActions () override {}
void setInitializer(std::function<void(T*)> func)
{
m_initializer = func;
}
QList<QWidget *> createdWidgets()
{
return QWidgetAction::createdWidgets();
}
protected:
QWidget *createWidget(QWidget *parent) override
{
T *w = new T(parent);
if (m_initializer)
m_initializer(w);
return w;
}
void deleteWidget(QWidget *widget) override
{
widget->deleteLater();
}
private:
std::function<void(T*)> m_initializer;
};
static void cursorEditBlock(QTextCursor& cursor, std::function<void()> f) {
cursor.beginEditBlock();
f();
cursor.endEditBlock();
}
RichTextEditor::RichTextEditor(QWidget *parent)
: QWidget(parent)
, ui(new Ui::RichTextEditor)
, m_linkDialog(new HyperlinkDialog(this))
{
ui->setupUi(this);
ui->textEdit->setTextInteractionFlags(Qt::TextEditorInteraction | Qt::LinksAccessibleByMouse);
ui->tableBar->setVisible(false);
setupEditActions();
setupTextActions();
setupHyperlinkActions();
setupAlignActions();
setupListActions();
setupFontActions();
setupTableActions();
connect(ui->textEdit, &QTextEdit::currentCharFormatChanged,
this, &RichTextEditor::currentCharFormatChanged);
connect(ui->textEdit, &QTextEdit::cursorPositionChanged,
this, &RichTextEditor::cursorPositionChanged);
connect(m_linkDialog, &QDialog::accepted, [this]() {
QTextCharFormat oldFormat = ui->textEdit->textCursor().charFormat();
QTextCursor tcursor = ui->textEdit->textCursor();
QTextCharFormat charFormat = tcursor.charFormat();
charFormat.setForeground(QApplication::palette().color(QPalette::Link));
charFormat.setFontUnderline(true);
QString link = m_linkDialog->getLink();
QString anchor = m_linkDialog->getAnchor();
if (anchor.isEmpty())
anchor = link;
charFormat.setAnchor(true);
charFormat.setAnchorHref(link);
charFormat.setAnchorNames(QStringList(anchor));
tcursor.insertText(anchor, charFormat);
tcursor.insertText(" ", oldFormat);
m_linkDialog->hide();
});
ui->textEdit->setFocus();
m_linkDialog->hide();
}
RichTextEditor::~RichTextEditor()
{
}
void RichTextEditor::setPlainText(const QString &text)
{
ui->textEdit->setPlainText(text);
}
QString RichTextEditor::plainText() const
{
return ui->textEdit->toPlainText();
}
void RichTextEditor::setRichText(const QString &text)
{
ui->textEdit->setHtml(text);
}
void RichTextEditor::setTabChangesFocus(bool change)
{
ui->textEdit->setTabChangesFocus(change);
}
QIcon RichTextEditor::getIcon(Theme::Icon icon)
{
const QString fontName = "qtds_propertyIconFont.ttf";
return Utils::StyleHelper::getIconFromIconFont(fontName, Theme::getIconUnicode(icon), 20, 20);
}
QString RichTextEditor::richText() const
{
return ui->textEdit->toHtml();
}
void RichTextEditor::currentCharFormatChanged(const QTextCharFormat &format)
{
fontChanged(format.font());
colorChanged(format.foreground().color());
}
void RichTextEditor::cursorPositionChanged()
{
alignmentChanged(ui->textEdit->alignment());
styleChanged(ui->textEdit->textCursor());
tableChanged(ui->textEdit->textCursor());
}
void RichTextEditor::mergeFormatOnWordOrSelection(const QTextCharFormat &format)
{
QTextCursor cursor = ui->textEdit->textCursor();
if (!cursor.hasSelection())
cursor.select(QTextCursor::WordUnderCursor);
cursor.mergeCharFormat(format);
ui->textEdit->mergeCurrentCharFormat(format);
}
void RichTextEditor::fontChanged(const QFont &f)
{
for (QWidget* w: m_fontNameAction->createdWidgets() ) {
QFontComboBox* box = qobject_cast<QFontComboBox*>(w);
if (box)
box->setCurrentFont(f);
}
for (QWidget* w: m_fontSizeAction->createdWidgets() ) {
QComboBox* box = qobject_cast<QComboBox*>(w);
if (box)
box->setCurrentText(QString::number(f.pointSize()));
}
m_actionTextBold->setChecked(f.bold());
m_actionTextItalic->setChecked(f.italic());
m_actionTextUnderline->setChecked(f.underline());
}
void RichTextEditor::colorChanged(const QColor &c)
{
QPixmap colorBox(ui->tableBar->iconSize());
colorBox.fill(c);
m_actionTextColor->setIcon(colorBox);
}
void RichTextEditor::alignmentChanged(Qt::Alignment a)
{
if (a & Qt::AlignLeft)
m_actionAlignLeft->setChecked(true);
else if (a & Qt::AlignHCenter)
m_actionAlignCenter->setChecked(true);
else if (a & Qt::AlignRight)
m_actionAlignRight->setChecked(true);
else if (a & Qt::AlignJustify)
m_actionAlignJustify->setChecked(true);
}
void RichTextEditor::styleChanged(const QTextCursor &cursor)
{
if (!m_actionBulletList || !m_actionNumberedList) return;
QTextList *currentList = cursor.currentList();
if (currentList) {
if (currentList->format().style() == QTextListFormat::ListDisc) {
m_actionBulletList->setChecked(true);
m_actionNumberedList->setChecked(false);
}
else if (currentList->format().style() == QTextListFormat::ListDecimal) {
m_actionBulletList->setChecked(false);
m_actionNumberedList->setChecked(true);
}
else {
m_actionBulletList->setChecked(false);
m_actionNumberedList->setChecked(false);
}
}
else {
m_actionBulletList->setChecked(false);
m_actionNumberedList->setChecked(false);
}
}
void RichTextEditor::tableChanged(const QTextCursor &cursor)
{
if (!m_actionTableSettings) return;
QTextTable *currentTable = cursor.currentTable();
if (currentTable) {
m_actionTableSettings->setChecked(true);
ui->tableBar->setVisible(true);
setTableActionsActive(true);
}
else {
setTableActionsActive(false);
}
}
void RichTextEditor::setupEditActions()
{
const QIcon undoIcon(getIcon(Theme::Icon::undo));
QAction *actionUndo = ui->toolBar->addAction(undoIcon, tr("&Undo"), ui->textEdit, &QTextEdit::undo);
actionUndo->setShortcut(QKeySequence::Undo);
connect(ui->textEdit->document(), &QTextDocument::undoAvailable,
actionUndo, &QAction::setEnabled);
const QIcon redoIcon(getIcon(Theme::Icon::redo));
QAction *actionRedo = ui->toolBar->addAction(redoIcon, tr("&Redo"), ui->textEdit, &QTextEdit::redo);
actionRedo->setShortcut(QKeySequence::Redo);
connect(ui->textEdit->document(), &QTextDocument::redoAvailable,
actionRedo, &QAction::setEnabled);
actionUndo->setEnabled(ui->textEdit->document()->isUndoAvailable());
actionRedo->setEnabled(ui->textEdit->document()->isRedoAvailable());
ui->toolBar->addSeparator();
}
void RichTextEditor::setupTextActions()
{
const QIcon boldIcon(getIcon(Theme::Icon::fontStyleBold));
m_actionTextBold = ui->toolBar->addAction(boldIcon, tr("&Bold"),
[this](bool checked) {
QTextCharFormat fmt;
fmt.setFontWeight(checked ? QFont::Bold : QFont::Normal);
mergeFormatOnWordOrSelection(fmt);
});
m_actionTextBold->setShortcut(Qt::CTRL + Qt::Key_B);
QFont bold;
bold.setBold(true);
m_actionTextBold->setFont(bold);
m_actionTextBold->setCheckable(true);
const QIcon italicIcon(getIcon(Theme::Icon::fontStyleItalic));
m_actionTextItalic = ui->toolBar->addAction(italicIcon, tr("&Italic"),
[this](bool checked) {
QTextCharFormat fmt;
fmt.setFontItalic(checked);
mergeFormatOnWordOrSelection(fmt);
});
m_actionTextItalic->setShortcut(Qt::CTRL + Qt::Key_I);
QFont italic;
italic.setItalic(true);
m_actionTextItalic->setFont(italic);
m_actionTextItalic->setCheckable(true);
const QIcon underlineIcon(getIcon(Theme::Icon::fontStyleUnderline));
m_actionTextUnderline = ui->toolBar->addAction(underlineIcon, tr("&Underline"),
[this](bool checked) {
QTextCharFormat fmt;
fmt.setFontUnderline(checked);
mergeFormatOnWordOrSelection(fmt);
});
m_actionTextUnderline->setShortcut(Qt::CTRL + Qt::Key_U);
QFont underline;
underline.setUnderline(true);
m_actionTextUnderline->setFont(underline);
m_actionTextUnderline->setCheckable(true);
ui->toolBar->addSeparator();
}
void RichTextEditor::setupHyperlinkActions()
{
const QIcon bulletIcon(getIcon(Theme::Icon::actionIconBinding));
m_actionHyperlink = ui->toolBar->addAction(bulletIcon, tr("Hyperlink Settings"), [this]() {
QTextCursor cursor = ui->textEdit->textCursor();
QTextCharFormat linkFormat = cursor.charFormat();
if (linkFormat.isAnchor()) {
m_linkDialog->setLink(linkFormat.anchorHref());
m_linkDialog->setAnchor(linkFormat.anchorName());
}
else {
m_linkDialog->setLink("http://");
m_linkDialog->setAnchor("");
}
m_linkDialog->show();
});
m_actionHyperlink->setCheckable(false);
ui->toolBar->addSeparator();
}
void RichTextEditor::setupAlignActions()
{
const QIcon leftIcon(getIcon(Theme::Icon::textAlignLeft));
m_actionAlignLeft = ui->toolBar->addAction(leftIcon, tr("&Left"), [this]() { ui->textEdit->setAlignment(Qt::AlignLeft | Qt::AlignAbsolute); });
m_actionAlignLeft->setShortcut(Qt::CTRL + Qt::Key_L);
m_actionAlignLeft->setCheckable(true);
m_actionAlignLeft->setPriority(QAction::LowPriority);
const QIcon centerIcon(getIcon(Theme::Icon::textAlignCenter));
m_actionAlignCenter = ui->toolBar->addAction(centerIcon, tr("C&enter"), [this]() { ui->textEdit->setAlignment(Qt::AlignHCenter); });
m_actionAlignCenter->setShortcut(Qt::CTRL + Qt::Key_E);
m_actionAlignCenter->setCheckable(true);
m_actionAlignCenter->setPriority(QAction::LowPriority);
const QIcon rightIcon(getIcon(Theme::Icon::textAlignRight));
m_actionAlignRight = ui->toolBar->addAction(rightIcon, tr("&Right"), [this]() { ui->textEdit->setAlignment(Qt::AlignRight | Qt::AlignAbsolute); });
m_actionAlignRight->setShortcut(Qt::CTRL + Qt::Key_R);
m_actionAlignRight->setCheckable(true);
m_actionAlignRight->setPriority(QAction::LowPriority);
const QIcon fillIcon(getIcon(Theme::Icon::textFullJustification));
m_actionAlignJustify = ui->toolBar->addAction(fillIcon, tr("&Justify"), [this]() { ui->textEdit->setAlignment(Qt::AlignJustify); });
m_actionAlignJustify->setShortcut(Qt::CTRL + Qt::Key_J);
m_actionAlignJustify->setCheckable(true);
m_actionAlignJustify->setPriority(QAction::LowPriority);
// Make sure the alignLeft is always left of the alignRight
QActionGroup *alignGroup = new QActionGroup(ui->toolBar);
if (QApplication::isLeftToRight()) {
alignGroup->addAction(m_actionAlignLeft);
alignGroup->addAction(m_actionAlignCenter);
alignGroup->addAction(m_actionAlignRight);
} else {
alignGroup->addAction(m_actionAlignRight);
alignGroup->addAction(m_actionAlignCenter);
alignGroup->addAction(m_actionAlignLeft);
}
alignGroup->addAction(m_actionAlignJustify);
ui->toolBar->addActions(alignGroup->actions());
ui->toolBar->addSeparator();
}
void RichTextEditor::setupListActions()
{
const QIcon bulletIcon(getIcon(Theme::Icon::textBulletList));
m_actionBulletList = ui->toolBar->addAction(bulletIcon, tr("Bullet List"), [this](bool checked) {
if (checked) {
m_actionNumberedList->setChecked(false);
textStyle(QTextListFormat::ListDisc);
}
else if (!m_actionNumberedList->isChecked()) {
textStyle(QTextListFormat::ListStyleUndefined);
}
});
m_actionBulletList->setCheckable(true);
const QIcon numberedIcon(getIcon(Theme::Icon::textNumberedList));
m_actionNumberedList = ui->toolBar->addAction(numberedIcon, tr("Numbered List"), [this](bool checked) {
if (checked) {
m_actionBulletList->setChecked(false);
textStyle(QTextListFormat::ListDecimal);
}
else if (!m_actionBulletList->isChecked()) {
textStyle(QTextListFormat::ListStyleUndefined);
}
});
m_actionNumberedList->setCheckable(true);
ui->toolBar->addSeparator();
}
void RichTextEditor::setupFontActions()
{
QPixmap colorBox(ui->tableBar->iconSize());
colorBox.fill(ui->textEdit->textColor());
m_actionTextColor = ui->toolBar->addAction(colorBox, tr("&Color..."), [this]() {
QColor col = QColorDialog::getColor(ui->textEdit->textColor(), this);
if (!col.isValid())
return;
QTextCharFormat fmt;
fmt.setForeground(col);
mergeFormatOnWordOrSelection(fmt);
colorChanged(col);
});
m_fontNameAction = new FontWidgetActions<QFontComboBox>(this);
m_fontNameAction->setInitializer([this](QFontComboBox *w) {
if (!w) return;
w->setCurrentIndex(w->findText(ui->textEdit->currentCharFormat().font().family()));
connect(w, QOverload<const QString &>::of(&QComboBox::activated), [this](const QString &f) {
QTextCharFormat fmt;
fmt.setFontFamily(f);
mergeFormatOnWordOrSelection(fmt);
});
});
m_fontNameAction->setDefaultWidget(new QFontComboBox);
ui->toolBar->addAction(m_fontNameAction);
m_fontSizeAction = new FontWidgetActions<QComboBox>(this);
m_fontSizeAction->setInitializer([this](QComboBox *w) {
if (!w) return;
w->setEditable(true);
const QList<int> standardSizes = QFontDatabase::standardSizes();
foreach (int size, standardSizes)
w->addItem(QString::number(size));
w->setCurrentText(QString::number(ui->textEdit->currentCharFormat().font().pointSize()));
connect(w, QOverload<const QString &>::of(&QComboBox::activated), [this](const QString &p) {
qreal pointSize = p.toDouble();
if (pointSize > 0.0) {
QTextCharFormat fmt;
fmt.setFontPointSize(pointSize);
mergeFormatOnWordOrSelection(fmt);
}
});
});
m_fontSizeAction->setDefaultWidget(new QComboBox);
ui->toolBar->addAction(m_fontSizeAction);
ui->toolBar->addSeparator();
}
void RichTextEditor::setupTableActions()
{
const QIcon tableIcon(getIcon(Theme::Icon::addTable));
m_actionTableSettings = ui->toolBar->addAction(tableIcon, tr("&Table Settings"), [this](bool checked) {
ui->tableBar->setVisible(checked);
});
m_actionTableSettings->setShortcut(Qt::CTRL + Qt::Key_T);
m_actionTableSettings->setCheckable(true);
m_actionTableSettings->setPriority(QAction::LowPriority);
//table bar:
const QIcon createTableIcon(getIcon(Theme::Icon::addTable));
m_actionCreateTable = ui->tableBar->addAction(createTableIcon, tr("Create Table"), [this]() {
QTextCursor cursor = ui->textEdit->textCursor();
cursorEditBlock(cursor, [&] () {
cursor.insertTable(1,1);
});
});
m_actionCreateTable->setCheckable(false);
const QIcon removeTableIcon(getIcon(Theme::Icon::deleteTable));
m_actionRemoveTable = ui->tableBar->addAction(removeTableIcon, tr("Remove Table"), [this]() {
QTextCursor cursor = ui->textEdit->textCursor();
if (QTextTable *currentTable = ui->textEdit->textCursor().currentTable()) {
cursorEditBlock(cursor, [&] () {
currentTable->removeRows(0, currentTable->rows());
});
}
});
m_actionRemoveTable->setCheckable(false);
ui->tableBar->addSeparator();
const QIcon addRowIcon(getIcon(Theme::Icon::addRowAfter)); //addRowAfter
m_actionAddRow = ui->tableBar->addAction(addRowIcon, tr("Add Row"), [this]() {
QTextCursor cursor = ui->textEdit->textCursor();
if (QTextTable *currentTable = ui->textEdit->textCursor().currentTable()) {
cursorEditBlock(cursor, [&] () {
currentTable->insertRows(currentTable->cellAt(cursor).row()+1, 1);
});
}
});
m_actionAddRow->setCheckable(false);
const QIcon addColumnIcon(getIcon(Theme::Icon::addColumnAfter)); //addColumnAfter
m_actionAddColumn = ui->tableBar->addAction(addColumnIcon, tr("Add Column"), [this]() {
QTextCursor cursor = ui->textEdit->textCursor();
if (QTextTable *currentTable = ui->textEdit->textCursor().currentTable()) {
cursorEditBlock(cursor, [&] () {
currentTable->insertColumns(currentTable->cellAt(cursor).column()+1, 1);
});
}
});
m_actionAddColumn->setCheckable(false);
const QIcon removeRowIcon(getIcon(Theme::Icon::deleteRow));
m_actionRemoveRow = ui->tableBar->addAction(removeRowIcon, tr("Remove Row"), [this]() {
QTextCursor cursor = ui->textEdit->textCursor();
if (QTextTable *currentTable = cursor.currentTable()) {
cursorEditBlock(cursor, [&] () {
currentTable->insertColumns(currentTable->cellAt(cursor).column()+1, 1);
int firstRow = 0;
int numRows = 0;
int firstColumn = 0;
int numColumns = 0;
if (cursor.hasSelection())
cursor.selectedTableCells(&firstRow, &numRows, &firstColumn, &numColumns);
if (numRows < 1)
currentTable->removeRows(currentTable->cellAt(cursor).row(), 1);
else
currentTable->removeRows(firstRow, numRows);
});
}
});
m_actionRemoveRow->setCheckable(false);
const QIcon removeColumnIcon(getIcon(Theme::Icon::deleteColumn));
m_actionRemoveColumn = ui->tableBar->addAction(removeColumnIcon, tr("Remove Column"), [this]() {
QTextCursor cursor = ui->textEdit->textCursor();
if (QTextTable *currentTable = cursor.currentTable()) {
cursorEditBlock(cursor, [&] () {
int firstRow = 0;
int numRows = 0;
int firstColumn = 0;
int numColumns = 0;
if (cursor.hasSelection())
cursor.selectedTableCells(&firstRow, &numRows, &firstColumn, &numColumns);
if (numColumns < 1)
currentTable->removeColumns(currentTable->cellAt(cursor).column(), 1);
else
currentTable->removeColumns(firstColumn, numColumns);
});
}
});
m_actionRemoveColumn->setCheckable(false);
ui->tableBar->addSeparator();
const QIcon mergeCellsIcon(getIcon(Theme::Icon::mergeCells));
m_actionMergeCells = ui->tableBar->addAction(mergeCellsIcon, tr("Merge Cells"), [this]() {
QTextCursor cursor = ui->textEdit->textCursor();
if (QTextTable *currentTable = cursor.currentTable()) {
if (cursor.hasSelection()) {
cursorEditBlock(cursor, [&] () {
currentTable->mergeCells(cursor);
});
}
}
});
m_actionMergeCells->setCheckable(false);
const QIcon splitRowIcon(getIcon(Theme::Icon::splitRows));
m_actionSplitRow = ui->tableBar->addAction(splitRowIcon, tr("Split Row"), [this]() {
QTextCursor cursor = ui->textEdit->textCursor();
if (QTextTable *currentTable = cursor.currentTable()) {
cursorEditBlock(cursor, [&] () {
currentTable->splitCell(currentTable->cellAt(cursor).row(),
currentTable->cellAt(cursor).column(),
2, 1);
});
}
});
m_actionSplitRow->setCheckable(false);
const QIcon splitColumnIcon(getIcon(Theme::Icon::splitColumns));
m_actionSplitColumn = ui->tableBar->addAction(splitRowIcon, tr("Split Column"), [this]() {
QTextCursor cursor = ui->textEdit->textCursor();
if (QTextTable *currentTable = cursor.currentTable()) {
cursorEditBlock(cursor, [&] () {
currentTable->splitCell(currentTable->cellAt(cursor).row(),
currentTable->cellAt(cursor).column(),
1, 2);
});
}
});
m_actionSplitColumn->setCheckable(false);
}
void RichTextEditor::textStyle(QTextListFormat::Style style)
{
QTextCursor cursor = ui->textEdit->textCursor();
cursorEditBlock(cursor, [&] () {
if (style != QTextListFormat::ListStyleUndefined) {
QTextBlockFormat blockFmt = cursor.blockFormat();
QTextListFormat listFmt;
if (cursor.currentList()) {
listFmt = cursor.currentList()->format();
} else {
listFmt.setIndent(blockFmt.indent() + 1);
blockFmt.setIndent(0);
cursor.setBlockFormat(blockFmt);
}
listFmt.setStyle(style);
cursor.createList(listFmt);
} else {
QTextList* currentList = cursor.currentList();
QTextBlock currentBlock = cursor.block();
currentList->remove(currentBlock);
QTextBlockFormat blockFormat = cursor.blockFormat();
blockFormat.setIndent(0);
cursor.setBlockFormat(blockFormat);
}
});
}
void RichTextEditor::setTableActionsActive(bool active)
{
m_actionCreateTable->setEnabled(!active);
m_actionRemoveTable->setEnabled(active);
m_actionAddRow->setEnabled(active);
m_actionAddColumn->setEnabled(active);
m_actionRemoveRow->setEnabled(active);
m_actionRemoveColumn->setEnabled(active);
m_actionMergeCells->setEnabled(active);
m_actionSplitRow->setEnabled(active);
m_actionSplitColumn->setEnabled(active);
}
}

View File

@@ -0,0 +1,130 @@
/****************************************************************************
**
** Copyright (C) 2020 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 <theme.h>
#include <QWidget>
#include <QToolBar>
#include <QList>
#include <QTextCharFormat>
#include <QTextList>
#include <QFontComboBox>
#include <QWidgetAction>
#include <QPointer>
namespace QmlDesigner {
namespace Ui {
class RichTextEditor;
}
template <class>
class FontWidgetActions;
class HyperlinkDialog;
class RichTextEditor : public QWidget
{
Q_OBJECT
public:
explicit RichTextEditor(QWidget *parent = nullptr);
~RichTextEditor();
void setPlainText(const QString &text);
QString plainText() const;
void setRichText(const QString &text);
QString richText() const;
void setTabChangesFocus(bool change);
private slots:
void currentCharFormatChanged(const QTextCharFormat &format);
void cursorPositionChanged();
private:
QIcon getIcon(Theme::Icon icon);
void mergeFormatOnWordOrSelection(const QTextCharFormat &format);
void fontChanged(const QFont &f);
void colorChanged(const QColor &c);
void alignmentChanged(Qt::Alignment a);
void styleChanged(const QTextCursor &cursor);
void tableChanged(const QTextCursor &cursor);
void setupEditActions();
void setupTextActions();
void setupHyperlinkActions();
void setupAlignActions();
void setupListActions();
void setupFontActions();
void setupTableActions();
void textStyle(QTextListFormat::Style style);
void setTableActionsActive(bool active); //switches between "has table/has no table" ui setup
private:
QScopedPointer<Ui::RichTextEditor> ui;
QPointer<HyperlinkDialog> m_linkDialog;
QAction *m_actionTextBold;
QAction *m_actionTextItalic;
QAction *m_actionTextUnderline;
QAction *m_actionHyperlink;
QAction *m_actionAlignLeft;
QAction *m_actionAlignCenter;
QAction *m_actionAlignRight;
QAction *m_actionAlignJustify;
QAction *m_actionTextColor;
QAction *m_actionBulletList;
QAction *m_actionNumberedList;
QAction *m_actionTableSettings;
QAction *m_actionCreateTable;
QAction *m_actionRemoveTable;
QAction *m_actionAddRow;
QAction *m_actionAddColumn;
QAction *m_actionRemoveRow;
QAction *m_actionRemoveColumn;
QAction *m_actionMergeCells;
QAction *m_actionSplitRow;
QAction *m_actionSplitColumn;
QPointer<FontWidgetActions<QFontComboBox>> m_fontNameAction;
QPointer<FontWidgetActions<QComboBox>> m_fontSizeAction;
};
} //namespace QmlDesigner

View File

@@ -0,0 +1,8 @@
HEADERS += $$PWD/richtexteditor.h
HEADERS += $$PWD/hyperlinkdialog.h
SOURCES += $$PWD/richtexteditor.cpp
SOURCES += $$PWD/hyperlinkdialog.cpp
FORMS += $$PWD/richtexteditor.ui
FORMS += $$PWD/hyperlinkdialog.ui

View File

@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>QmlDesigner::RichTextEditor</class>
<widget class="QWidget" name="QmlDesigner::RichTextEditor">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>428</width>
<height>283</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>5</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string notr="true">Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QToolBar" name="toolBar">
<property name="iconSize">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QToolBar" name="tableBar">
<property name="iconSize">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QTextEdit" name="textEdit"/>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -58,6 +58,7 @@
#include <QSlider> #include <QSlider>
#include <QVBoxLayout> #include <QVBoxLayout>
#include <QtGlobal> #include <QtGlobal>
#include <QSpacerItem>
namespace QmlDesigner { namespace QmlDesigner {
@@ -118,6 +119,7 @@ TimelineWidget::TimelineWidget(TimelineView *view)
, m_timelineView(view) , m_timelineView(view)
, m_graphicsScene(new TimelineGraphicsScene(this)) , m_graphicsScene(new TimelineGraphicsScene(this))
, m_addButton(new QPushButton(this)) , m_addButton(new QPushButton(this))
, m_onboardingContainer(new QWidget(this))
{ {
setWindowTitle(tr("Timeline", "Title of timeline view")); setWindowTitle(tr("Timeline", "Title of timeline view"));
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
@@ -185,6 +187,50 @@ TimelineWidget::TimelineWidget(TimelineView *view)
m_addButton->setFlat(true); m_addButton->setFlat(true);
m_addButton->setFixedSize(32, 32); m_addButton->setFixedSize(32, 32);
widgetLayout->addWidget(m_onboardingContainer);
auto *onboardingTopLabel = new QLabel(m_onboardingContainer);
auto *onboardingBottomLabel = new QLabel(m_onboardingContainer);
auto *onboardingBottomIcon = new QLabel(m_onboardingContainer);
auto *onboardingLayout = new QVBoxLayout;
auto *onboardingSublayout = new QHBoxLayout;
auto *leftSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
auto *rightSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
auto *topSpacer = new QSpacerItem(40, 20, QSizePolicy::Minimum, QSizePolicy::Expanding);
auto *bottomSpacer = new QSpacerItem(40, 20, QSizePolicy::Minimum, QSizePolicy::Expanding);
QString labelText =
tr("This file does not contain a timeline. <br><br> \
To create an animation, add a timeline by clicking the + button.");
onboardingTopLabel->setText(labelText);
onboardingTopLabel->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
m_onboardingContainer->setLayout(onboardingLayout);
onboardingLayout->setContentsMargins(0, 0, 0, 0);
onboardingLayout->setSpacing(0);
onboardingLayout->addSpacerItem(topSpacer);
onboardingLayout->addWidget(onboardingTopLabel);
onboardingLayout->addLayout(onboardingSublayout);
onboardingSublayout->setContentsMargins(0, 0, 0, 0);
onboardingSublayout->setSpacing(0);
onboardingSublayout->addSpacerItem(leftSpacer);
onboardingBottomLabel->setAlignment(Qt::AlignRight | Qt::AlignTop);
onboardingBottomLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
onboardingSublayout->addWidget(onboardingBottomLabel);
onboardingBottomLabel->setText(tr("To edit the timeline settings, click "));
onboardingBottomIcon->setAlignment(Qt::AlignLeft | Qt::AlignTop);
onboardingBottomIcon->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
onboardingSublayout->addWidget(onboardingBottomIcon);
onboardingBottomIcon->setPixmap(TimelineIcons::ANIMATION.pixmap());
onboardingSublayout->addSpacerItem(rightSpacer);
onboardingLayout->addSpacerItem(bottomSpacer);
widgetLayout->addLayout(contentLayout); widgetLayout->addLayout(contentLayout);
this->setLayout(widgetLayout); this->setLayout(widgetLayout);
@@ -532,6 +578,7 @@ void TimelineWidget::setTimelineActive(bool b)
m_rulerView->setVisible(true); m_rulerView->setVisible(true);
m_scrollbar->setVisible(true); m_scrollbar->setVisible(true);
m_addButton->setVisible(false); m_addButton->setVisible(false);
m_onboardingContainer->setVisible(false);
m_graphicsView->update(); m_graphicsView->update();
m_rulerView->update(); m_rulerView->update();
} else { } else {
@@ -540,6 +587,7 @@ void TimelineWidget::setTimelineActive(bool b)
m_rulerView->setVisible(false); m_rulerView->setVisible(false);
m_scrollbar->setVisible(false); m_scrollbar->setVisible(false);
m_addButton->setVisible(true); m_addButton->setVisible(true);
m_onboardingContainer->setVisible(true);
} }
} }

View File

@@ -104,6 +104,8 @@ private:
TimelineGraphicsScene *m_graphicsScene; TimelineGraphicsScene *m_graphicsScene;
QPushButton *m_addButton = nullptr; QPushButton *m_addButton = nullptr;
QWidget *m_onboardingContainer = nullptr;
}; };
} // namespace QmlDesigner } // namespace QmlDesigner

View File

@@ -85,10 +85,25 @@ bool ChangeImportsVisitor::remove(QmlJS::AST::UiProgram *ast, const Import &impo
bool ChangeImportsVisitor::equals(QmlJS::AST::UiImport *ast, const Import &import) bool ChangeImportsVisitor::equals(QmlJS::AST::UiImport *ast, const Import &import)
{ {
bool equal = false;
if (import.isLibraryImport()) if (import.isLibraryImport())
return toString(ast->importUri) == import.url(); equal = toString(ast->importUri) == import.url();
else if (import.isFileImport()) else if (import.isFileImport())
return ast->fileName == import.file(); equal = ast->fileName == import.file();
else
return false; if (equal) {
equal = (!ast->version || (ast->version->minorVersion == 0 && ast->version->majorVersion == 0))
&& import.version().isEmpty();
if (!equal && ast->version) {
const QStringList versions = import.version().split('.');
if (versions.size() >= 1 && versions[0].toInt() == ast->version->majorVersion) {
if (versions.size() >= 2)
equal = versions[1].toInt() == ast->version->minorVersion;
else
equal = ast->version->minorVersion == 0;
}
}
}
return equal;
} }

View File

@@ -35,6 +35,7 @@ namespace QmlDesigner {
static const PropertyName customIdProperty = {("customId")}; static const PropertyName customIdProperty = {("customId")};
static const PropertyName annotationProperty = {("annotation")}; static const PropertyName annotationProperty = {("annotation")};
static const PropertyName globalAnnotationProperty = {("globalAnnotation")};
class Comment class Comment
{ {

View File

@@ -202,6 +202,11 @@ public:
void setAnnotation(const Annotation &annotation); void setAnnotation(const Annotation &annotation);
void removeAnnotation(); void removeAnnotation();
Annotation globalAnnotation() const;
bool hasGlobalAnnotation() const;
void setGlobalAnnotation(const Annotation &annotation);
void removeGlobalAnnotation();
qint32 internalId() const; qint32 internalId() const;
void setNodeSource(const QString&); void setNodeSource(const QString&);

View File

@@ -182,8 +182,13 @@ public:
const QList<ModelNode> wildcards() const; const QList<ModelNode> wildcards() const;
const QList<ModelNode> decicions() const; const QList<ModelNode> decicions() const;
QList<ModelNode> transitionsForTarget(const ModelNode &modelNode); QList<ModelNode> transitionsForTarget(const ModelNode &modelNode);
QList<ModelNode> transitionsForSource(const ModelNode &modelNode);
void removeDanglingTransitions(); void removeDanglingTransitions();
void removeAllTransitions(); void removeAllTransitions();
void setStartFlowItem(const QmlFlowItemNode &flowItem);
ModelNode createTransition();
protected:
QList<ModelNode> transitionsForProperty(const PropertyName &propertyName, const ModelNode &modelNode);
}; };

View File

@@ -420,8 +420,7 @@ void SubComponentManager::parseQuick3DAssetDir(const QString &assetPath)
itemLibraryEntry.addHints(hints); itemLibraryEntry.addHints(hints);
} }
if (!model()->metaInfo().itemLibraryInfo()->containsEntry(itemLibraryEntry)) model()->metaInfo().itemLibraryInfo()->addEntries({itemLibraryEntry}, true);
model()->metaInfo().itemLibraryInfo()->addEntries({itemLibraryEntry});
} }
} }
} }

View File

@@ -1150,6 +1150,35 @@ void ModelNode::removeAnnotation()
} }
} }
Annotation ModelNode::globalAnnotation() const
{
Annotation result;
ModelNode root = view()->rootModelNode();
if (hasGlobalAnnotation())
result.fromQString(root.auxiliaryData(globalAnnotationProperty).value<QString>());
return result;
}
bool ModelNode::hasGlobalAnnotation() const
{
return view()->rootModelNode().hasAuxiliaryData(globalAnnotationProperty);
}
void ModelNode::setGlobalAnnotation(const Annotation &annotation)
{
view()->rootModelNode().setAuxiliaryData(globalAnnotationProperty,
QVariant::fromValue<QString>(annotation.toQString()));
}
void ModelNode::removeGlobalAnnotation()
{
if (hasGlobalAnnotation()) {
view()->rootModelNode().removeAuxiliaryData(globalAnnotationProperty);
}
}
void ModelNode::setScriptFunctions(const QStringList &scriptFunctionList) void ModelNode::setScriptFunctions(const QStringList &scriptFunctionList)
{ {
model()->d->setScriptFunctions(internalNode(), scriptFunctionList); model()->d->setScriptFunctions(internalNode(), scriptFunctionList);

View File

@@ -664,9 +664,7 @@ QList<QmlFlowItemNode> QmlFlowViewNode::flowItems() const
ModelNode QmlFlowViewNode::addTransition(const QmlFlowTargetNode &from, const QmlFlowTargetNode &to) ModelNode QmlFlowViewNode::addTransition(const QmlFlowTargetNode &from, const QmlFlowTargetNode &to)
{ {
ModelNode transition = view()->createModelNode("FlowView.FlowTransition", 1, 0); ModelNode transition = createTransition();
nodeListProperty("flowTransitions").reparentHere(transition);
QmlFlowTargetNode f = from; QmlFlowTargetNode f = from;
QmlFlowTargetNode t = to; QmlFlowTargetNode t = to;
@@ -684,8 +682,6 @@ const QList<ModelNode> QmlFlowViewNode::transitions() const
return modelNode().nodeListProperty("flowTransitions").toModelNodeList(); return modelNode().nodeListProperty("flowTransitions").toModelNodeList();
return {}; return {};
} }
const QList<ModelNode> QmlFlowViewNode::wildcards() const const QList<ModelNode> QmlFlowViewNode::wildcards() const
@@ -706,13 +702,12 @@ const QList<ModelNode> QmlFlowViewNode::decicions() const
QList<ModelNode> QmlFlowViewNode::transitionsForTarget(const ModelNode &modelNode) QList<ModelNode> QmlFlowViewNode::transitionsForTarget(const ModelNode &modelNode)
{ {
QList<ModelNode> list; return transitionsForProperty("to", modelNode);
for (const ModelNode &transition : transitions()) { }
if (transition.hasBindingProperty("to")
&& transition.bindingProperty("to").resolveToModelNode() == modelNode) QList<ModelNode> QmlFlowViewNode::transitionsForSource(const ModelNode &modelNode)
list.append(transition); {
} return transitionsForProperty("from", modelNode);
return list;
} }
void QmlFlowViewNode::removeDanglingTransitions() void QmlFlowViewNode::removeDanglingTransitions()
@@ -830,4 +825,41 @@ void QmlFlowViewNode::removeAllTransitions()
removeProperty("flowTransitions"); removeProperty("flowTransitions");
} }
void QmlFlowViewNode::setStartFlowItem(const QmlFlowItemNode &flowItem)
{
QTC_ASSERT(flowItem.isValid(), return);
QmlFlowItemNode item = flowItem;
ModelNode transition;
for (const ModelNode &node : transitionsForSource(modelNode()))
transition = node;
if (!transition.isValid())
transition = createTransition();
transition.bindingProperty("from").setExpression(modelNode().validId());
transition.bindingProperty("to").setExpression(item.validId());
}
ModelNode QmlFlowViewNode::createTransition()
{
ModelNode transition = view()->createModelNode("FlowView.FlowTransition", 1, 0);
nodeListProperty("flowTransitions").reparentHere(transition);
return transition;
}
QList<ModelNode> QmlFlowViewNode::transitionsForProperty(const PropertyName &propertyName,
const ModelNode &modelNode)
{
QList<ModelNode> list;
for (const ModelNode &transition : transitions()) {
if (transition.hasBindingProperty(propertyName)
&& transition.bindingProperty(propertyName).resolveToModelNode() == modelNode)
list.append(transition);
}
return list;
}
} //QmlDesigner } //QmlDesigner

View File

@@ -91,7 +91,12 @@ QStringList globalQtEnums()
"Horizontal", "Vertical", "AlignVCenter", "AlignLeft", "LeftToRight", "RightToLeft", "Horizontal", "Vertical", "AlignVCenter", "AlignLeft", "LeftToRight", "RightToLeft",
"AlignHCenter", "AlignRight", "AlignBottom", "AlignBaseline", "AlignTop", "BottomLeft", "AlignHCenter", "AlignRight", "AlignBottom", "AlignBaseline", "AlignTop", "BottomLeft",
"LeftEdge", "RightEdge", "BottomEdge", "TopEdge", "TabFocus", "ClickFocus", "StrongFocus", "LeftEdge", "RightEdge", "BottomEdge", "TopEdge", "TabFocus", "ClickFocus", "StrongFocus",
"WheelFocus", "NoFocus" "WheelFocus", "NoFocus", "ArrowCursor", "UpArrowCursor", "CrossCursor", "WaitCursor",
"IBeamCursor", "SizeVerCursor", "SizeHorCursor", "SizeBDiagCursor", "SizeFDiagCursor",
"SizeAllCursor", "BlankCursor", "SplitVCursor", "SplitHCursor", "PointingHandCursor",
"ForbiddenCursor", "WhatsThisCursor", "BusyCursor", "OpenHandCursor", "ClosedHandCursor",
"DragCopyCursor", "DragMoveCursor", "DragLinkCursor", "TopToBottom",
"LeftButton", "RightButton", "MiddleButton", "BackButton", "ForwardButton", "AllButtons"
}; };
return list; return list;
@@ -101,7 +106,7 @@ QStringList knownEnumScopes()
{ {
static const QStringList list = { static const QStringList list = {
"TextInput", "TextEdit", "Material", "Universal", "Font", "Shape", "ShapePath", "TextInput", "TextEdit", "Material", "Universal", "Font", "Shape", "ShapePath",
"AbstractButton", "Text", "ShaderEffectSource" "AbstractButton", "Text", "ShaderEffectSource", "Grid"
}; };
return list; return list;
} }

View File

@@ -60,6 +60,7 @@
#include <utils/algorithm.h> #include <utils/algorithm.h>
#include <utils/fileutils.h> #include <utils/fileutils.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <utils/stylehelper.h>
#include <QSettings> #include <QSettings>
#include <QToolBar> #include <QToolBar>
@@ -70,6 +71,7 @@
#include <advanceddockingsystem/dockareawidget.h> #include <advanceddockingsystem/dockareawidget.h>
#include <advanceddockingsystem/docksplitter.h> #include <advanceddockingsystem/docksplitter.h>
#include <advanceddockingsystem/iconprovider.h>
using Core::MiniSplitter; using Core::MiniSplitter;
using Core::IEditor; using Core::IEditor;
@@ -227,6 +229,26 @@ void DesignModeWidget::setup()
QString sheet = QString::fromUtf8(Utils::FileReader::fetchQrc(":/qmldesigner/dockwidgets.css")); QString sheet = QString::fromUtf8(Utils::FileReader::fetchQrc(":/qmldesigner/dockwidgets.css"));
m_dockManager->setStyleSheet(Theme::replaceCssColors(sheet)); m_dockManager->setStyleSheet(Theme::replaceCssColors(sheet));
// Setup icons
QColor buttonColor(Theme::getColor(Theme::QmlDesigner_TabLight)); // TODO Use correct color roles
QColor tabColor(Theme::getColor(Theme::QmlDesigner_TabDark));
const QString closeUnicode = Theme::getIconUnicode(Theme::Icon::adsClose);
const QString menuUnicode = Theme::getIconUnicode(Theme::Icon::adsDropDown);
const QString undockUnicode = Theme::getIconUnicode(Theme::Icon::adsDetach);
const QString fontName = "qtds_propertyIconFont.ttf";
const QIcon tabsCloseIcon = Utils::StyleHelper::getIconFromIconFont(fontName, closeUnicode, 28, 28, tabColor);
const QIcon menuIcon = Utils::StyleHelper::getIconFromIconFont(fontName, menuUnicode, 28, 28, buttonColor);
const QIcon undockIcon = Utils::StyleHelper::getIconFromIconFont(fontName, undockUnicode, 28, 28, buttonColor);
const QIcon closeIcon = Utils::StyleHelper::getIconFromIconFont(fontName, closeUnicode, 28, 28, buttonColor);
m_dockManager->iconProvider().registerCustomIcon(ADS::TabCloseIcon, tabsCloseIcon);
m_dockManager->iconProvider().registerCustomIcon(ADS::DockAreaMenuIcon, menuIcon);
m_dockManager->iconProvider().registerCustomIcon(ADS::DockAreaUndockIcon, undockIcon);
m_dockManager->iconProvider().registerCustomIcon(ADS::DockAreaCloseIcon, closeIcon);
m_dockManager->iconProvider().registerCustomIcon(ADS::FloatingWidgetCloseIcon, closeIcon);
// Setup Actions and Menus // Setup Actions and Menus
Core::ActionContainer *mview = Core::ActionManager::actionContainer(Core::Constants::M_VIEW); Core::ActionContainer *mview = Core::ActionManager::actionContainer(Core::Constants::M_VIEW);
// Window > Views // Window > Views
@@ -409,6 +431,19 @@ void DesignModeWidget::setup()
m_dockManager->openWorkspace(workspaceComboBox->currentText()); m_dockManager->openWorkspace(workspaceComboBox->currentText());
}); });
const QIcon gaIcon = Utils::StyleHelper::getIconFromIconFont(fontName,
Theme::getIconUnicode(Theme::Icon::annotationBubble), 36, 36);
toolBar->addAction(gaIcon, tr("Edit global annotation for current file."), [&](){
ModelNode node = currentDesignDocument()->rewriterView()->rootModelNode();
if (node.isValid()) {
m_globalAnnotationEditor.setModelNode(node);
m_globalAnnotationEditor.showWidget();
}
});
viewManager().enableWidgets(); viewManager().enableWidgets();
readSettings(); readSettings();
show(); show();

View File

@@ -36,6 +36,7 @@
#include <QScopedPointer> #include <QScopedPointer>
#include <advanceddockingsystem/dockmanager.h> #include <advanceddockingsystem/dockmanager.h>
#include <annotationeditor/globalannotationeditor.h>
namespace Core { namespace Core {
class SideBar; class SideBar;
@@ -120,6 +121,7 @@ private: // variables
ADS::DockManager *m_dockManager = nullptr; ADS::DockManager *m_dockManager = nullptr;
ADS::DockWidget *m_outputPaneDockWidget = nullptr; ADS::DockWidget *m_outputPaneDockWidget = nullptr;
GlobalAnnotationEditor m_globalAnnotationEditor;
}; };
} // namespace Internal } // namespace Internal

View File

@@ -38,6 +38,7 @@
#include <sourcetool/sourcetool.h> #include <sourcetool/sourcetool.h>
#include <colortool/colortool.h> #include <colortool/colortool.h>
#include <annotationeditor/annotationtool.h> #include <annotationeditor/annotationtool.h>
#include <formeditor/transitiontool.h>
#include <texttool/texttool.h> #include <texttool/texttool.h>
#include <timelineeditor/timelineview.h> #include <timelineeditor/timelineview.h>
#include <pathtool/pathtool.h> #include <pathtool/pathtool.h>
@@ -216,6 +217,11 @@ bool QmlDesignerPlugin::initialize(const QStringList & /*arguments*/, QString *e
if (DesignerSettings::getValue(DesignerSettingsKey::STANDALONE_MODE).toBool()) if (DesignerSettings::getValue(DesignerSettingsKey::STANDALONE_MODE).toBool())
GenerateResource::generateMenuEntry(); GenerateResource::generateMenuEntry();
QString fontPath = Core::ICore::resourcePath() +
QStringLiteral("/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf");
if (QFontDatabase::addApplicationFont(fontPath) < 0)
qCWarning(qmldesignerLog) << "Could not add font " << fontPath << "to font database";
return true; return true;
} }
@@ -242,6 +248,7 @@ bool QmlDesignerPlugin::delayedInitialize()
d->viewManager.registerFormEditorToolTakingOwnership(new QmlDesigner::AnnotationTool); d->viewManager.registerFormEditorToolTakingOwnership(new QmlDesigner::AnnotationTool);
d->viewManager.registerFormEditorToolTakingOwnership(new QmlDesigner::TextTool); d->viewManager.registerFormEditorToolTakingOwnership(new QmlDesigner::TextTool);
d->viewManager.registerFormEditorToolTakingOwnership(new QmlDesigner::PathTool); d->viewManager.registerFormEditorToolTakingOwnership(new QmlDesigner::PathTool);
d->viewManager.registerFormEditorToolTakingOwnership(new QmlDesigner::TransitionTool);
return true; return true;
} }

View File

@@ -31,6 +31,7 @@ include(components/connectioneditor/connectioneditor.pri)
include(components/curveeditor/curveeditor.pri) include(components/curveeditor/curveeditor.pri)
include(components/bindingeditor/bindingeditor.pri) include(components/bindingeditor/bindingeditor.pri)
include(components/annotationeditor/annotationeditor.pri) include(components/annotationeditor/annotationeditor.pri)
include(components/richtexteditor/richtexteditor.pri)
BUILD_PUPPET_IN_CREATOR_BINPATH = $$(BUILD_PUPPET_IN_CREATOR_BINPATH) BUILD_PUPPET_IN_CREATOR_BINPATH = $$(BUILD_PUPPET_IN_CREATOR_BINPATH)

View File

@@ -530,6 +530,8 @@ Project {
"formeditor/toolbox.h", "formeditor/toolbox.h",
"formeditor/formeditortoolbutton.cpp", "formeditor/formeditortoolbutton.cpp",
"formeditor/formeditortoolbutton.h", "formeditor/formeditortoolbutton.h",
"formeditor/transitiontool.cpp",
"formeditor/transitiontool.h",
"importmanager/importlabel.cpp", "importmanager/importlabel.cpp",
"importmanager/importlabel.h", "importmanager/importlabel.h",
"importmanager/importmanagercombobox.cpp", "importmanager/importmanagercombobox.cpp",
@@ -654,6 +656,8 @@ Project {
"annotationeditor/annotationcommenttab.ui", "annotationeditor/annotationcommenttab.ui",
"annotationeditor/annotationeditor.cpp", "annotationeditor/annotationeditor.cpp",
"annotationeditor/annotationeditor.h", "annotationeditor/annotationeditor.h",
"annotationeditor/globalannotationeditor.cpp",
"annotationeditor/globalannotationeditor.h",
"annotationeditor/annotationeditordialog.cpp", "annotationeditor/annotationeditordialog.cpp",
"annotationeditor/annotationeditordialog.h", "annotationeditor/annotationeditordialog.h",
"annotationeditor/annotationeditordialog.ui", "annotationeditor/annotationeditordialog.ui",
@@ -746,6 +750,12 @@ Project {
"pathtool/pathtool.h", "pathtool/pathtool.h",
"pathtool/pathtoolview.cpp", "pathtool/pathtoolview.cpp",
"pathtool/pathtoolview.h", "pathtool/pathtoolview.h",
"richtexteditor/hyperlinkdialog.cpp",
"richtexteditor/hyperlinkdialog.h",
"richtexteditor/hyperlinkdialog.ui",
"richtexteditor/richtexteditor.cpp",
"richtexteditor/richtexteditor.h",
"richtexteditor/richtexteditor.ui",
"sourcetool/sourcetool.cpp", "sourcetool/sourcetool.cpp",
"sourcetool/sourcetool.h", "sourcetool/sourcetool.h",
"texttool/textedititem.cpp", "texttool/textedititem.cpp",

View File

@@ -164,6 +164,14 @@ add_qtc_test(unittest GTEST
unittest-utility-functions.h unittest-utility-functions.h
usedmacrofilter-test.cpp usedmacrofilter-test.cpp
utf8-test.cpp utf8-test.cpp
sqlitecolumn-test.cpp
sqlitedatabasebackend-test.cpp
sqlitedatabase-test.cpp
sqlitestatement-test.cpp
sqlitetable-test.cpp
sqlstatementbuilder-test.cpp
createtablesqlstatementbuilder-test.cpp
sqlitevalue-test.cpp
) )
# Do not work on the source directory data # Do not work on the source directory data
@@ -219,7 +227,6 @@ if (TARGET libclang)
codecompleter-test.cpp codecompleter-test.cpp
codecompletionsextractor-test.cpp codecompletionsextractor-test.cpp
completionchunkstotextconverter-test.cpp completionchunkstotextconverter-test.cpp
createtablesqlstatementbuilder-test.cpp
cursor-test.cpp cursor-test.cpp
diagnosticset-test.cpp diagnosticset-test.cpp
diagnostic-test.cpp diagnostic-test.cpp
@@ -228,12 +235,6 @@ if (TARGET libclang)
skippedsourceranges-test.cpp skippedsourceranges-test.cpp
sourcelocation-test.cpp sourcelocation-test.cpp
sourcerange-test.cpp sourcerange-test.cpp
sqlitecolumn-test.cpp
sqlitedatabasebackend-test.cpp
sqlitedatabase-test.cpp
sqlitestatement-test.cpp
sqlitetable-test.cpp
sqlstatementbuilder-test.cpp
token-test.cpp token-test.cpp
translationunitupdater-test.cpp translationunitupdater-test.cpp
unsavedfiles-test.cpp unsavedfiles-test.cpp

View File

@@ -14,11 +14,11 @@ include($$PWD/../../../src/tools/clangpchmanagerbackend/source/clangpchmanagerba
include($$PWD/../../../src/plugins/clangrefactoring/clangrefactoring-source.pri) include($$PWD/../../../src/plugins/clangrefactoring/clangrefactoring-source.pri)
include($$PWD/../../../src/plugins/clangpchmanager/clangpchmanager-source.pri) include($$PWD/../../../src/plugins/clangpchmanager/clangpchmanager-source.pri)
include($$PWD/../../../src/plugins/cpptools/cpptoolsunittestfiles.pri) include($$PWD/../../../src/plugins/cpptools/cpptoolsunittestfiles.pri)
include($$PWD/../../../src/plugins/clangtools/clangtoolsunittestfiles.pri)
include($$PWD/../../../src/plugins/debugger/debuggerunittestfiles.pri) include($$PWD/../../../src/plugins/debugger/debuggerunittestfiles.pri)
include($$PWD/../../../src/plugins/compilationdatabaseprojectmanager/compilationdatabaseunittestfiles.pri) include($$PWD/../../../src/plugins/compilationdatabaseprojectmanager/compilationdatabaseunittestfiles.pri)
include(cplusplus.pri) include(cplusplus.pri)
!isEmpty(LLVM_VERSION) { !isEmpty(LLVM_VERSION) {
include($$PWD/../../../src/plugins/clangtools/clangtoolsunittestfiles.pri)
include($$PWD/../../../src/shared/clang/clang_defines.pri) include($$PWD/../../../src/shared/clang/clang_defines.pri)
include($$PWD/../../../src/tools/clangbackend/source/clangbackendclangipc-source.pri) include($$PWD/../../../src/tools/clangbackend/source/clangbackendclangipc-source.pri)
include($$PWD/../../../src/plugins/clangcodemodel/clangcodemodelunittestfiles.pri) include($$PWD/../../../src/plugins/clangcodemodel/clangcodemodelunittestfiles.pri)

View File

@@ -37,6 +37,7 @@
#include <clangcodemodelservermessages.h> #include <clangcodemodelservermessages.h>
#include <clangpathwatcher.h> #include <clangpathwatcher.h>
#include <clangrefactoringmessages.h> #include <clangrefactoringmessages.h>
#include <clangtools/clangtoolsdiagnostic.h>
#include <coreplugin/find/searchresultitem.h> #include <coreplugin/find/searchresultitem.h>
#include <coreplugin/locator/ilocatorfilter.h> #include <coreplugin/locator/ilocatorfilter.h>
#include <cpptools/usages.h> #include <cpptools/usages.h>
@@ -57,6 +58,7 @@
#include <sourcedependency.h> #include <sourcedependency.h>
#include <sourcelocationentry.h> #include <sourcelocationentry.h>
#include <sourcelocationscontainer.h> #include <sourcelocationscontainer.h>
#include <sqlitevalue.h>
#include <symbol.h> #include <symbol.h>
#include <symbolentry.h> #include <symbolentry.h>
#include <symbolindexertaskqueue.h> #include <symbolindexertaskqueue.h>
@@ -64,12 +66,6 @@
#include <tooltipinfo.h> #include <tooltipinfo.h>
#include <usedmacro.h> #include <usedmacro.h>
#include <utils/link.h> #include <utils/link.h>
#include <cpptools/usages.h>
#include <projectexplorer/projectmacro.h>
#include <projectexplorer/headerpath.h>
#include <coreplugin/find/searchresultitem.h>
#include <coreplugin/locator/ilocatorfilter.h>
#include <clangtools/clangtoolsdiagnostic.h>
namespace { namespace {
ClangBackEnd::FilePathCaching *filePathCache = nullptr; ClangBackEnd::FilePathCaching *filePathCache = nullptr;
@@ -306,6 +302,27 @@ void PrintTo(const Utils::PathString &text, ::std::ostream *os)
} // namespace Utils } // namespace Utils
namespace Sqlite {
std::ostream &operator<<(std::ostream &out, const Value &value)
{
out << "(";
switch (value.type()) {
case Sqlite::ValueType::Integer:
out << value.toInteger();
break;
case Sqlite::ValueType::Float:
out << value.toFloat();
break;
case Sqlite::ValueType::String:
out << "\"" << value.toStringView() << "\"";
break;
}
return out << ")";
}
} // namespace Sqlite
namespace ClangBackEnd { namespace ClangBackEnd {
std::ostream &operator<<(std::ostream &out, const FilePathId &id) std::ostream &operator<<(std::ostream &out, const FilePathId &id)

View File

@@ -64,6 +64,12 @@ void PrintTo(const TextRange &range, ::std::ostream *os);
} // namespace TextPosition } // namespace TextPosition
} // namespace TextPosition } // namespace TextPosition
namespace Sqlite {
class Value;
std::ostream &operator<<(std::ostream &out, const Value &value);
} // namespace Sqlite
namespace ProjectExplorer { namespace ProjectExplorer {
enum class MacroType; enum class MacroType;

View File

@@ -40,11 +40,12 @@
namespace { namespace {
using Sqlite::JournalMode;
using Sqlite::Exception;
using Sqlite::Database; using Sqlite::Database;
using Sqlite::Exception;
using Sqlite::JournalMode;
using Sqlite::ReadStatement; using Sqlite::ReadStatement;
using Sqlite::ReadWriteStatement; using Sqlite::ReadWriteStatement;
using Sqlite::Value;
using Sqlite::WriteStatement; using Sqlite::WriteStatement;
MATCHER_P3(HasValues, value1, value2, rowid, MATCHER_P3(HasValues, value1, value2, rowid,
@@ -125,7 +126,7 @@ TEST_F(SqliteStatement, CountRows)
TEST_F(SqliteStatement, Value) TEST_F(SqliteStatement, Value)
{ {
SqliteTestStatement statement("SELECT name, number FROM test ORDER BY name", database); SqliteTestStatement statement("SELECT name, number, value FROM test ORDER BY name", database);
statement.next(); statement.next();
statement.next(); statement.next();
@@ -142,6 +143,9 @@ TEST_F(SqliteStatement, Value)
ASSERT_THAT(statement.fetchValue<Utils::SmallString>(1), "23.3"); ASSERT_THAT(statement.fetchValue<Utils::SmallString>(1), "23.3");
ASSERT_THAT(statement.fetchValue<Utils::PathString>(1), "23.3"); ASSERT_THAT(statement.fetchValue<Utils::PathString>(1), "23.3");
ASSERT_THAT(statement.fetchSmallStringViewValue(1), "23.3"); ASSERT_THAT(statement.fetchSmallStringViewValue(1), "23.3");
ASSERT_THAT(statement.fetchValueView(0), Eq("foo"));
ASSERT_THAT(statement.fetchValueView(1), Eq(23.3));
ASSERT_THAT(statement.fetchValueView(2), Eq(2));
} }
TEST_F(SqliteStatement, ThrowNoValuesToFetchForNotSteppedStatement) TEST_F(SqliteStatement, ThrowNoValuesToFetchForNotSteppedStatement)
@@ -175,14 +179,14 @@ TEST_F(SqliteStatement, ThrowInvalidColumnFetchedForNotExistingColumn)
ASSERT_THROW(statement.fetchValue<int>(2), Sqlite::InvalidColumnFetched); ASSERT_THROW(statement.fetchValue<int>(2), Sqlite::InvalidColumnFetched);
} }
TEST_F(SqliteStatement, ToIntergerValue) TEST_F(SqliteStatement, ToIntegerValue)
{ {
auto value = ReadStatement::toValue<int>("SELECT number FROM test WHERE name='foo'", database); auto value = ReadStatement::toValue<int>("SELECT number FROM test WHERE name='foo'", database);
ASSERT_THAT(value, 23); ASSERT_THAT(value, 23);
} }
TEST_F(SqliteStatement, ToLongIntergerValue) TEST_F(SqliteStatement, ToLongIntegerValue)
{ {
ASSERT_THAT(ReadStatement::toValue<qint64>("SELECT number FROM test WHERE name='foo'", database), Eq(23)); ASSERT_THAT(ReadStatement::toValue<qint64>("SELECT number FROM test WHERE name='foo'", database), Eq(23));
} }
@@ -319,6 +323,15 @@ TEST_F(SqliteStatement, WriteValues)
ASSERT_THAT(statement, HasValues("see", "7.23", 1)); ASSERT_THAT(statement, HasValues("see", "7.23", 1));
} }
TEST_F(SqliteStatement, WriteSqliteValues)
{
WriteStatement statement("UPDATE test SET name=?, number=? WHERE rowid=?", database);
statement.write(Value{"see"}, Value{7.23}, Value{1});
ASSERT_THAT(statement, HasValues("see", "7.23", 1));
}
TEST_F(SqliteStatement, BindNamedValues) TEST_F(SqliteStatement, BindNamedValues)
{ {
SqliteTestStatement statement("UPDATE test SET name=@name, number=@number WHERE rowid=@id", database); SqliteTestStatement statement("UPDATE test SET name=@name, number=@number WHERE rowid=@id", database);
@@ -375,6 +388,31 @@ TEST_F(SqliteStatement, GetSingleValuesWithoutArguments)
ASSERT_THAT(values, ElementsAre("bar", "foo", "poo")); ASSERT_THAT(values, ElementsAre("bar", "foo", "poo"));
} }
class FooValue
{
public:
FooValue(Sqlite::ValueView value)
: value(value)
{}
Sqlite::Value value;
template<typename Type>
friend bool operator==(const FooValue &value, const Type &other)
{
return value.value == other;
}
};
TEST_F(SqliteStatement, GetSingleSqliteValuesWithoutArguments)
{
ReadStatement statement("SELECT number FROM test", database);
std::vector<FooValue> values = statement.values<FooValue>(3);
ASSERT_THAT(values, ElementsAre(Eq("blah"), Eq(23.3), Eq(40)));
}
TEST_F(SqliteStatement, GetStructValuesWithoutArguments) TEST_F(SqliteStatement, GetStructValuesWithoutArguments)
{ {
ReadStatement statement("SELECT name, number, value FROM test", database); ReadStatement statement("SELECT name, number, value FROM test", database);

View File

@@ -0,0 +1,348 @@
/****************************************************************************
**
** Copyright (C) 2020 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.
**
****************************************************************************/
#include "googletest.h"
#include <sqlitevalue.h>
namespace {
TEST(SqliteValue, ConstructLongLong)
{
Sqlite::Value value{1LL};
ASSERT_THAT(value.toInteger(), Eq(1LL));
}
TEST(SqliteValue, Construct)
{
Sqlite::Value value{1};
ASSERT_THAT(value.toInteger(), Eq(1LL));
}
TEST(SqliteValue, ConstructFloatingPoint)
{
Sqlite::Value value{1.1};
ASSERT_THAT(value.toFloat(), Eq(1.1));
}
TEST(SqliteValue, ConstructStringFromCString)
{
Sqlite::Value value{"foo"};
ASSERT_THAT(value.toStringView(), Eq("foo"));
}
TEST(SqliteValue, ConstructStringFromUtilsString)
{
Sqlite::Value value{Utils::SmallString{"foo"}};
ASSERT_THAT(value.toStringView(), Eq("foo"));
}
TEST(SqliteValue, ConstructStringFromQString)
{
Sqlite::Value value{QString{"foo"}};
ASSERT_THAT(value.toStringView(), Eq("foo"));
}
TEST(SqliteValue, ConstructStringFromIntQVariant)
{
QVariant variant{1};
Sqlite::Value value{variant};
ASSERT_THAT(value.toInteger(), Eq(1));
}
TEST(SqliteValue, ConstructStringFromLongLongQVariant)
{
QVariant variant{1LL};
Sqlite::Value value{variant};
ASSERT_THAT(value.toInteger(), Eq(1));
}
TEST(SqliteValue, ConstructStringFromUintQVariant)
{
QVariant variant{1u};
Sqlite::Value value{variant};
ASSERT_THAT(value.toInteger(), Eq(1));
}
TEST(SqliteValue, ConstructStringFromFloatQVariant)
{
QVariant variant{1.};
Sqlite::Value value{variant};
ASSERT_THAT(value.toFloat(), Eq(1));
}
TEST(SqliteValue, ConstructStringFromStringQVariant)
{
QVariant variant{QString{"foo"}};
Sqlite::Value value{variant};
ASSERT_THAT(value.toStringView(), Eq("foo"));
}
TEST(SqliteValue, ConvertToStringQVariant)
{
Sqlite::Value value{"foo"};
auto variant = QVariant{value};
ASSERT_THAT(variant, Eq("foo"));
}
TEST(SqliteValue, ConvertToIntegerQVariant)
{
Sqlite::Value value{1};
auto variant = QVariant{value};
ASSERT_THAT(variant, Eq(1));
}
TEST(SqliteValue, ConvertToFloatQVariant)
{
Sqlite::Value value{1.1};
auto variant = QVariant{value};
ASSERT_THAT(variant, Eq(1.1));
}
TEST(SqliteValue, IntegerEquals)
{
bool isEqual = Sqlite::Value{1} == 1LL;
ASSERT_TRUE(isEqual);
}
TEST(SqliteValue, IntegerEqualsInverse)
{
bool isEqual = 1LL == Sqlite::Value{1};
ASSERT_TRUE(isEqual);
}
TEST(SqliteValue, FloatEquals)
{
bool isEqual = Sqlite::Value{1.0} == 1.;
ASSERT_TRUE(isEqual);
}
TEST(SqliteValue, FloatEqualsInverse)
{
bool isEqual = 1. == Sqlite::Value{1.0};
ASSERT_TRUE(isEqual);
}
TEST(SqliteValue, StringEquals)
{
bool isEqual = Sqlite::Value{"foo"} == "foo";
ASSERT_TRUE(isEqual);
}
TEST(SqliteValue, StringEqualsInverse)
{
bool isEqual = "foo" == Sqlite::Value{"foo"};
ASSERT_TRUE(isEqual);
}
TEST(SqliteValue, IntegerAndFloatAreNotEquals)
{
bool isEqual = Sqlite::Value{1} == 1.;
ASSERT_FALSE(isEqual);
}
TEST(SqliteValue, IntegerValuesAreEquals)
{
bool isEqual = Sqlite::Value{1} == Sqlite::Value{1};
ASSERT_TRUE(isEqual);
}
TEST(SqliteValue, IntegerAndFloatValuesAreNotEquals)
{
bool isEqual = Sqlite::Value{1} == Sqlite::Value{1.};
ASSERT_FALSE(isEqual);
}
TEST(SqliteValue, StringAndQStringAreEquals)
{
bool isEqual = Sqlite::Value{"foo"} == QString{"foo"};
ASSERT_TRUE(isEqual);
}
TEST(SqliteValue, IntegerAndFloatValuesAreUnequal)
{
bool isUnequal = Sqlite::Value{1} != Sqlite::Value{1.0};
ASSERT_TRUE(isUnequal);
}
TEST(SqliteValue, IntegerAndFloatAreUnequal)
{
bool isUnequal = Sqlite::Value{1} != 1.0;
ASSERT_TRUE(isUnequal);
}
TEST(SqliteValue, IntegerAndFloatAreUnequalInverse)
{
bool isUnequal = 1.0 != Sqlite::Value{1};
ASSERT_TRUE(isUnequal);
}
TEST(SqliteValue, IntegersAreUnequal)
{
bool isUnequal = Sqlite::Value{1} != 2;
ASSERT_TRUE(isUnequal);
}
TEST(SqliteValue, IntegersAreUnequalInverse)
{
bool isUnequal = 2 != Sqlite::Value{1};
ASSERT_TRUE(isUnequal);
}
TEST(SqliteValue, IntegerType)
{
auto type = Sqlite::Value{1}.type();
ASSERT_THAT(type, Sqlite::ValueType::Integer);
}
TEST(SqliteValue, FloatType)
{
auto type = Sqlite::Value{1.}.type();
ASSERT_THAT(type, Sqlite::ValueType::Float);
}
TEST(SqliteValue, StringType)
{
auto type = Sqlite::Value{"foo"}.type();
ASSERT_THAT(type, Sqlite::ValueType::String);
}
TEST(SqliteValue, StringValueAndValueViewEquals)
{
bool isEqual = Sqlite::ValueView::create("foo") == Sqlite::Value{"foo"};
ASSERT_TRUE(isEqual);
}
TEST(SqliteValue, StringValueAndValueViewEqualsInverse)
{
bool isEqual = Sqlite::Value{"foo"} == Sqlite::ValueView::create("foo");
ASSERT_TRUE(isEqual);
}
TEST(SqliteValue, IntegerValueAndValueViewEquals)
{
bool isEqual = Sqlite::ValueView::create(1) == Sqlite::Value{1};
ASSERT_TRUE(isEqual);
}
TEST(SqliteValue, IntegerValueAndValueViewEqualsInverse)
{
bool isEqual = Sqlite::Value{2} == Sqlite::ValueView::create(2);
ASSERT_TRUE(isEqual);
}
TEST(SqliteValue, FloatValueAndValueViewEquals)
{
bool isEqual = Sqlite::ValueView::create(1.1) == Sqlite::Value{1.1};
ASSERT_TRUE(isEqual);
}
TEST(SqliteValue, FloatValueAndValueViewEqualsInverse)
{
bool isEqual = Sqlite::Value{1.1} == Sqlite::ValueView::create(1.1);
ASSERT_TRUE(isEqual);
}
TEST(SqliteValue, StringValueAndIntergerValueViewAreNotEqual)
{
bool isEqual = Sqlite::Value{"foo"} == Sqlite::ValueView::create(1);
ASSERT_FALSE(isEqual);
}
TEST(SqliteValue, ConvertStringValueViewIntoValue)
{
auto view = Sqlite::ValueView::create("foo");
Sqlite::Value value{view};
ASSERT_THAT(value, Eq("foo"));
}
TEST(SqliteValue, ConvertIntegerValueViewIntoValue)
{
auto view = Sqlite::ValueView::create(1);
Sqlite::Value value{view};
ASSERT_THAT(value, Eq(1));
}
TEST(SqliteValue, ConvertFloatValueViewIntoValue)
{
auto view = Sqlite::ValueView::create(1.4);
Sqlite::Value value{view};
ASSERT_THAT(value, Eq(1.4));
}
} // namespace

View File

@@ -80,6 +80,7 @@ SOURCES += \
smallstring-test.cpp \ smallstring-test.cpp \
sourcerangefilter-test.cpp \ sourcerangefilter-test.cpp \
spydummy.cpp \ spydummy.cpp \
sqlitevalue-test.cpp \
symbolindexer-test.cpp \ symbolindexer-test.cpp \
symbolsfindfilter-test.cpp \ symbolsfindfilter-test.cpp \
stringcache-test.cpp \ stringcache-test.cpp \
@@ -122,7 +123,13 @@ SOURCES += \
headerpathfilter-test.cpp \ headerpathfilter-test.cpp \
toolchainargumentscache-test.cpp \ toolchainargumentscache-test.cpp \
modifiedtimechecker-test.cpp \ modifiedtimechecker-test.cpp \
readexporteddiagnostics-test.cpp sqlitecolumn-test.cpp \
sqlitedatabasebackend-test.cpp \
sqlitedatabase-test.cpp \
sqlitestatement-test.cpp \
sqlitetable-test.cpp \
sqlstatementbuilder-test.cpp \
createtablesqlstatementbuilder-test.cpp
!isEmpty(LIBCLANG_LIBS) { !isEmpty(LIBCLANG_LIBS) {
SOURCES += \ SOURCES += \
@@ -158,7 +165,6 @@ SOURCES += \
codecompleter-test.cpp \ codecompleter-test.cpp \
codecompletionsextractor-test.cpp \ codecompletionsextractor-test.cpp \
completionchunkstotextconverter-test.cpp \ completionchunkstotextconverter-test.cpp \
createtablesqlstatementbuilder-test.cpp \
cursor-test.cpp \ cursor-test.cpp \
diagnosticset-test.cpp \ diagnosticset-test.cpp \
diagnostic-test.cpp \ diagnostic-test.cpp \
@@ -168,17 +174,12 @@ SOURCES += \
skippedsourceranges-test.cpp \ skippedsourceranges-test.cpp \
sourcelocation-test.cpp \ sourcelocation-test.cpp \
sourcerange-test.cpp \ sourcerange-test.cpp \
sqlitecolumn-test.cpp \
sqlitedatabasebackend-test.cpp \
sqlitedatabase-test.cpp \
sqlitestatement-test.cpp \
sqlitetable-test.cpp \
sqlstatementbuilder-test.cpp \
token-test.cpp \ token-test.cpp \
translationunitupdater-test.cpp \ translationunitupdater-test.cpp \
unsavedfiles-test.cpp \ unsavedfiles-test.cpp \
unsavedfile-test.cpp \ unsavedfile-test.cpp \
utf8positionfromlinecolumn-test.cpp utf8positionfromlinecolumn-test.cpp \
readexporteddiagnostics-test.cpp
} }
!isEmpty(LIBTOOLING_LIBS) { !isEmpty(LIBTOOLING_LIBS) {