Merge "Merge remote-tracking branch 'origin/4.14'"
@@ -37,35 +37,36 @@ if (APPLE)
|
||||
|
||||
set(_IDE_OUTPUT_PATH "${_IDE_APP_PATH}/${_IDE_APP_TARGET}.app/Contents")
|
||||
|
||||
set(_IDE_PLUGIN_PATH "${_IDE_OUTPUT_PATH}/PlugIns")
|
||||
set(_IDE_LIBRARY_BASE_PATH "Frameworks")
|
||||
set(_IDE_LIBRARY_PATH "${_IDE_OUTPUT_PATH}/Frameworks")
|
||||
set(_IDE_LIBRARY_PATH "${_IDE_OUTPUT_PATH}/${_IDE_LIBRARY_BASE_PATH}")
|
||||
set(_IDE_PLUGIN_PATH "${_IDE_OUTPUT_PATH}/PlugIns")
|
||||
set(_IDE_LIBEXEC_PATH "${_IDE_OUTPUT_PATH}/Resources/libexec")
|
||||
set(_IDE_DATA_PATH "${_IDE_OUTPUT_PATH}/Resources")
|
||||
set(_IDE_DOC_PATH "${_IDE_OUTPUT_PATH}/Resources/doc")
|
||||
set(_IDE_BIN_PATH "${_IDE_OUTPUT_PATH}/MacOS")
|
||||
|
||||
set(QT_DEST_PLUGIN_PATH "${_IDE_PLUGIN_PATH}")
|
||||
set(QT_DEST_QML_PATH "${_IDE_DATA_PATH}/../Imports/qtquick2")
|
||||
else ()
|
||||
elseif(WIN32)
|
||||
set(_IDE_APP_PATH "bin")
|
||||
set(_IDE_APP_TARGET "${IDE_ID}")
|
||||
|
||||
set(_IDE_LIBRARY_BASE_PATH "lib")
|
||||
set(_IDE_LIBRARY_PATH "lib/qtcreator")
|
||||
set(_IDE_PLUGIN_PATH "lib/qtcreator/plugins")
|
||||
if (WIN32)
|
||||
set(_IDE_LIBEXEC_PATH "bin")
|
||||
set(QT_DEST_PLUGIN_PATH "bin/plugins")
|
||||
set(QT_DEST_QML_PATH "bin/qml")
|
||||
else ()
|
||||
set(_IDE_LIBEXEC_PATH "libexec/qtcreator")
|
||||
set(QT_DEST_PLUGIN_PATH "lib/Qt/plugins")
|
||||
set(QT_DEST_QML_PATH "lib/Qt/qml")
|
||||
endif ()
|
||||
set(_IDE_LIBRARY_PATH "${_IDE_LIBRARY_BASE_PATH}/qtcreator")
|
||||
set(_IDE_PLUGIN_PATH "${_IDE_LIBRARY_BASE_PATH}/qtcreator/plugins")
|
||||
set(_IDE_LIBEXEC_PATH "bin")
|
||||
set(_IDE_DATA_PATH "share/qtcreator")
|
||||
set(_IDE_DOC_PATH "share/doc/qtcreator")
|
||||
set(_IDE_BIN_PATH "bin")
|
||||
else ()
|
||||
include(GNUInstallDirs)
|
||||
set(_IDE_APP_PATH "${CMAKE_INSTALL_BINDIR}")
|
||||
set(_IDE_APP_TARGET "${IDE_ID}")
|
||||
|
||||
set(_IDE_LIBRARY_BASE_PATH "${CMAKE_INSTALL_LIBDIR}")
|
||||
set(_IDE_LIBRARY_PATH "${_IDE_LIBRARY_BASE_PATH}/qtcreator")
|
||||
set(_IDE_PLUGIN_PATH "${_IDE_LIBRARY_BASE_PATH}/qtcreator/plugins")
|
||||
set(_IDE_LIBEXEC_PATH "${CMAKE_INSTALL_LIBEXECDIR}/qtcreator")
|
||||
set(_IDE_DATA_PATH "${CMAKE_INSTALL_DATAROOTDIR}/qtcreator")
|
||||
set(_IDE_DOC_PATH "${CMAKE_INSTALL_DATAROOTDIR}/doc/qtcreator")
|
||||
set(_IDE_BIN_PATH "${CMAKE_INSTALL_BINDIR}")
|
||||
endif ()
|
||||
|
||||
file(RELATIVE_PATH _PLUGIN_TO_LIB "/${_IDE_PLUGIN_PATH}" "/${_IDE_LIBRARY_PATH}")
|
||||
|
||||
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 7.7 KiB After Width: | Height: | Size: 7.1 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 11 KiB |
@@ -166,7 +166,7 @@
|
||||
system to the Clang code model for displaying annotations in the
|
||||
code editor.
|
||||
|
||||
\image qtcreator-diagnostics-configuration.png "Diagnostics Configuration dialog"
|
||||
\image qtcreator-clang-tools-diagnostics-configuration.png "Diagnostics Configuration dialog"
|
||||
|
||||
\li In the \uicontrol {Clang-Tidy Checks} tab, select
|
||||
\uicontrol {Select Checks} to select the checks to perform.
|
||||
|
||||
@@ -138,7 +138,10 @@
|
||||
edit the value for the \uicontrol {Do not index files greater than}
|
||||
check box. To index all files, deselect the check box.
|
||||
|
||||
\li Select \uicontrol Manage to specify the Clang checks to perform.
|
||||
\li The \uicontrol {Diagnostic Configuration} field shows the Clang
|
||||
checks to perform. Click the value of the field to open the
|
||||
\uicontrol {Diagnostic Configurations} dialog, where you can
|
||||
select and edit the checks to perform.
|
||||
|
||||
\image qtcreator-diagnostics-configuration.png
|
||||
|
||||
@@ -146,26 +149,18 @@
|
||||
|
||||
\section1 Clang Checks
|
||||
|
||||
The predefined configurations perform the following Clang checks:
|
||||
In addition to using the built-in checks, you can select \uicontrol Copy to
|
||||
create copies of them and edit the copies to fit your needs.
|
||||
|
||||
\list
|
||||
\uicontrol {Build-system warnings} displays warnings as specified
|
||||
by the build system.
|
||||
|
||||
\li \uicontrol {Clang-only pedantic checks} uses the \c -Wpendantic
|
||||
option that performs checks as required by strict ISO C and ISO C++.
|
||||
\uicontrol {Checks for questionable constructs} combines the \c -Wall and
|
||||
\c -Wextra checks for easily avoidable questionable constructions and some
|
||||
additional issues.
|
||||
|
||||
\li \uicontrol {Clang-only checks for questionable constructs} combines
|
||||
the \c -Wall and \c -Wextra checks for easily avoidable questionable
|
||||
constructions and some additional issues.
|
||||
|
||||
\li \uicontrol {Clang-only checks for almost everything} uses the
|
||||
\c -Weverything option with negative options to suppress some
|
||||
warnings.
|
||||
|
||||
\endlist
|
||||
|
||||
You can edit the predefined configurations to perform particular checks
|
||||
beginning with \c -W. Each of these checks also has a negative version
|
||||
that begins with \c -Wno.
|
||||
Clang checks begin with \c -W. Each check also has a negative version that
|
||||
begins with \c -Wno.
|
||||
|
||||
Keep in mind that some options turn on other options. For more information,
|
||||
see \l{https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html}
|
||||
|
||||
@@ -293,6 +293,13 @@
|
||||
|
||||
\image qtquickcontrols2-button-flat.gif "Flat button"
|
||||
|
||||
\if definded(qtdesignstudio)
|
||||
To create a button that contains an icon, use the wizard template to
|
||||
\l{Creating Custom Controls}{create a custom button} and drag-and-drop
|
||||
the icon to the button background item. For an example of using the
|
||||
wizard template, see \l{Creating a Push Button}.
|
||||
\endif
|
||||
|
||||
\section2 Delay Button
|
||||
|
||||
\image qtquickcontrols2-delaybutton.gif "Delay button"
|
||||
|
||||
@@ -125,6 +125,7 @@
|
||||
\li \l {Lists and Other Data Models}
|
||||
\if defined(qtdesignstudio)
|
||||
\li \l {2D Effects}
|
||||
\li \l {Logic Helpers}
|
||||
\endif
|
||||
\endlist
|
||||
|
||||
|
||||
BIN
doc/qtdesignstudio/images/icons/lc-and-operator-16px.png
Normal file
|
After Width: | Height: | Size: 238 B |
|
After Width: | Height: | Size: 241 B |
BIN
doc/qtdesignstudio/images/icons/lc-min-max-16px.png
Normal file
|
After Width: | Height: | Size: 291 B |
BIN
doc/qtdesignstudio/images/icons/lc-not-operator-16px.png
Normal file
|
After Width: | Height: | Size: 257 B |
BIN
doc/qtdesignstudio/images/icons/lc-or-operator-16px.png
Normal file
|
After Width: | Height: | Size: 351 B |
BIN
doc/qtdesignstudio/images/icons/lc-range-mapper-16px.png
Normal file
|
After Width: | Height: | Size: 163 B |
BIN
doc/qtdesignstudio/images/icons/lc-string-mapper-16px.png
Normal file
|
After Width: | Height: | Size: 149 B |
BIN
doc/qtdesignstudio/images/studio-bidirectional-binding.gif
Normal file
|
After Width: | Height: | Size: 66 KiB |
BIN
doc/qtdesignstudio/images/studio-logic-helper-and-checkbox3.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 107 KiB |
BIN
doc/qtdesignstudio/images/studio-logic-helper-and-operator.gif
Normal file
|
After Width: | Height: | Size: 99 KiB |
BIN
doc/qtdesignstudio/images/studio-logic-helper-and.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 17 KiB |
BIN
doc/qtdesignstudio/images/studio-logic-helper-minmax-mapper.gif
Normal file
|
After Width: | Height: | Size: 47 KiB |
BIN
doc/qtdesignstudio/images/studio-logic-helper-not-check-box.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
doc/qtdesignstudio/images/studio-logic-helper-not-operator.gif
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
doc/qtdesignstudio/images/studio-logic-helper-not.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 16 KiB |
BIN
doc/qtdesignstudio/images/studio-logic-helper-range-mapper.gif
Normal file
|
After Width: | Height: | Size: 60 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 18 KiB |
BIN
doc/qtdesignstudio/images/studio-logic-helper-string-mapper.gif
Normal file
|
After Width: | Height: | Size: 47 KiB |
BIN
doc/qtdesignstudio/images/studio-logic-helpers.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
@@ -92,6 +92,7 @@
|
||||
\li \l{User Interaction Methods}
|
||||
\li \l{Lists and Other Data Models}
|
||||
\li \l{2D Effects}
|
||||
\li \l{Logic Helpers}
|
||||
\li \l{Creating Buttons}
|
||||
\li \l{Creating Scalable Buttons and Borders}
|
||||
\endlist
|
||||
|
||||
@@ -0,0 +1,300 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2020 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the Qt Design Studio documentation.
|
||||
**
|
||||
** 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 Free Documentation License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Free
|
||||
** Documentation License version 1.3 as published by the Free Software
|
||||
** Foundation and appearing in the file included in the packaging of
|
||||
** this file. Please review the following information to ensure
|
||||
** the GNU Free Documentation License version 1.3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
/*!
|
||||
\page quick-logic-helpers.html
|
||||
\previouspage quick-2d-effects.html
|
||||
\nextpage quick-buttons.html
|
||||
|
||||
\title Logic Helpers
|
||||
|
||||
To have your UI perform certain operations, you might need to write
|
||||
JavaScript expressions for conditions or convert numbers to strings.
|
||||
\QDS attempts to make this easier by providing a set of components
|
||||
called \e {Qt Quick Studio Logic Helpers} that you can import to your
|
||||
project to make them available in the \uicontrol Library view.
|
||||
|
||||
\image studio-logic-helpers.png "Logic Helper types in Library"
|
||||
|
||||
Logic helpers are available for binding property values using the boolean
|
||||
AND, NOT, and OR operators, as well as for mapping numbers and numerical
|
||||
ranges. In addition, you can synchronize the property values of two
|
||||
components bi-directionally.
|
||||
|
||||
Logic helpers are invisible types that you can use in connection with
|
||||
Qt Quick Controls, such as a \l {slider-control}{Slider} or \l {Check Box}.
|
||||
To use a logic helper, drag-and-drop it from \uicontrol Library >
|
||||
\uicontrol {Studio Logic Helper} to \uicontrol Navigator. The following
|
||||
sections describe the different types of logic helpers in more detail.
|
||||
|
||||
\section1 Boolean Helpers
|
||||
|
||||
You can use logic helpers to bind property values using the boolean AND, OR,
|
||||
and NOT operators.
|
||||
|
||||
\section2 AND Operator
|
||||
|
||||
The \uicontrol {And Operator} type evaluates two boolean inputs.
|
||||
The output is evaluated as \c true if both inputs are \c true.
|
||||
|
||||
For example, we could use the checked state of two check boxes to determine
|
||||
the checked state of a third one. First we drag-and-drop three
|
||||
\uicontrol {Check Box} types and an \uicontrol {And Operator} to
|
||||
\uicontrol Navigator (1). Then we select the \uicontrol {And Operator}
|
||||
component (2) and set its properties in \uicontrol Properties (3).
|
||||
|
||||
We select \inlineimage icons/action-icon.png
|
||||
next to the \uicontrol Input01 field to display the \uicontrol Actions
|
||||
menu, and then \uicontrol {Set Binding} (4) to open the
|
||||
\uicontrol {Binding Editor} (5). There we bind the value of the \c input01
|
||||
property of the AND operator to the value of the \c checked property of the
|
||||
first check box. Then, we do the same in the \uicontrol Input02 field, where
|
||||
we bind the \c input02 property to the \c checked property of the second
|
||||
check box.
|
||||
|
||||
\image studio-logic-helper-and.png "AND operator properties"
|
||||
|
||||
Then, we select the first and second check box, and set their
|
||||
\uicontrol Checked property to \c true in \uicontrol Properties.
|
||||
We can multiselect the controls and make the change simultaneously
|
||||
for both of them.
|
||||
|
||||
\image studio-logic-helper-and-operator-multiselect.gif "Multiselecting check boxes and changing Checked property"
|
||||
|
||||
Finally, we select the third check box and bind its \uicontrol Checked
|
||||
property to the \uicontrol Output property of the AND operator.
|
||||
|
||||
\image studio-logic-helper-and-checkbox3.png "Binding Checked property to Output property."
|
||||
|
||||
When we \l{Previewing on Desktop}{preview} our UI, all the check boxes are
|
||||
initially unchecked. However, when we select the first and second check box,
|
||||
the third one also becomes checked.
|
||||
|
||||
\image studio-logic-helper-and-operator.gif "Previewing AND operator"
|
||||
|
||||
\section2 OR Operator
|
||||
|
||||
The \uicontrol {Or Operator} type does the same as the AND operator, but
|
||||
the output is \c true if one or both inputs are \c true.
|
||||
|
||||
\section2 NOT Operator
|
||||
|
||||
The \uicontrol {Not Operator} type is evaluated to \c true if the condition
|
||||
is not met.
|
||||
|
||||
For example, we could specify that if one check box is checked, another
|
||||
one cannot be checked. First we drag-and-drop two \uicontrol {Check Box}
|
||||
types and a \uicontrol {Not Operator} to \uicontrol Navigator. Then we
|
||||
select \uicontrol {Not Operator} and set its properties in
|
||||
\uicontrol Properties. In the \uicontrol {Binding Editor}, we bind the
|
||||
value of the \c input property of the NOT operator to the value of the
|
||||
\c checked property of the check box.
|
||||
|
||||
\image studio-logic-helper-not.png "NOT operator properties"
|
||||
|
||||
We then select the second check box and bind the value of its
|
||||
\uicontrol Checked field to the value of of \uicontrol Output
|
||||
field of the \uicontrol {Not Operator} component.
|
||||
|
||||
\image studio-logic-helper-not-check-box.png "Check box checked property bound to NOT operator output"
|
||||
|
||||
When we preview our UI, the second check box is initially checked. However,
|
||||
when we select the first check box, the second one is automatically cleared.
|
||||
|
||||
\image studio-logic-helper-not-operator.gif "Previewing two check boxes bound with a NOT operator"
|
||||
|
||||
\section1 Bi-directional Binding
|
||||
|
||||
The \uicontrol {Bi Direct. Binding} type binds the values of two controls
|
||||
together, so that when one value is changed, the other one follows it.
|
||||
This type could be used to synchronize two sliders or a slider and checkbox.
|
||||
Typically, it is used to bind a backend value to a control, such as a
|
||||
slider.
|
||||
|
||||
For example, to synchronize the values of two sliders, drag and drop two
|
||||
\uicontrol Slider components and one \uicontrol {Bi Direct. Binding}
|
||||
component to the same parent component in \uicontrol Navigator. Then select
|
||||
the bi-directional binding and set its properties in \uicontrol Properties.
|
||||
|
||||
\image studio-logic-helper-bidirectional-binding.png "Bi-directional binding properties"
|
||||
|
||||
In the \uicontrol {Target 01} and \uicontrol {Target 02} fields, enter
|
||||
the ids of the components that you want to bind together. In the
|
||||
\uicontrol {Property 01} and \uicontrol {Property 02} fields, enter the
|
||||
names of the properties to synchronize. In our example, we bind the
|
||||
\c value property of two slider components together, so that when we move
|
||||
one slider handle in the preview, the other one moves along with it.
|
||||
|
||||
\image studio-bidirectional-binding.gif "Previewing a bi-directional binding of two sliders"
|
||||
|
||||
If you want to add a text field that displays the value of the slider, you
|
||||
can use a \l {String Mapper} component.
|
||||
|
||||
\section1 String Mapper
|
||||
|
||||
The \uicontrol {String Mapper} type maps numbers to strings. First you
|
||||
\l{Adding Bindings Between Properties}{add a binding} between the string
|
||||
mapper \c input property and the \c value property of the control that you
|
||||
want to fetch the values from. Then, you add a binding between the \c text
|
||||
property of the string mapper and that of the component that will display
|
||||
the string.
|
||||
|
||||
For example, to use a \l Text component to display the value of a
|
||||
slider, we drag and drop \uicontrol Text, \uicontrol Slider, and
|
||||
\uicontrol {String Mapper} components to the same parent item. Then
|
||||
we select \uicontrol {String Mapper} in \uicontrol Navigator to display
|
||||
its properties in \uicontrol Properties. There we bind the value of the
|
||||
\c input property of the string mapper to the value of the \c value
|
||||
property of the slider.
|
||||
|
||||
\image studio-logic-helper-string-mapper-input.png "Binding slider value property to string mapper"
|
||||
|
||||
Next, we bind the value of the \uicontrol Text field of the
|
||||
\uicontrol Text component to the value of the \uicontrol Text
|
||||
field of the \uicontrol {String Mapper} component.
|
||||
|
||||
\image studio-logic-helper-string-mapper-text.png "Binding text property value to string mapper"
|
||||
|
||||
When we move the slider handle in the preview, the value displayed in the
|
||||
text component changes accordingly.
|
||||
|
||||
\image studio-logic-helper-string-mapper.gif "Previewing text property binding to string mapper"
|
||||
|
||||
The value of the \uicontrol Decimal field determines the number of digits
|
||||
after the decimal separator.
|
||||
|
||||
\section1 Minimum-Maximum Mapper
|
||||
|
||||
The \uicontrol {Min Max Mapper} type has output values even if the input
|
||||
value is out of range or too small or big. This enables you to apply
|
||||
actions to values even if they are out of range, such as changing a color
|
||||
in a state.
|
||||
|
||||
To access the values of a control, bind the \c input property of the
|
||||
minimum-maximum mapper to that of the \c value property of the control.
|
||||
|
||||
For example, to restrict the maximum value of a slider to 0.60,
|
||||
regardless of the maximum value set in the slider properties,
|
||||
we drag and drop a \uicontrol {Min Max Mapper} to our example
|
||||
above. We select it to display its properties in \uicontrol Properties.
|
||||
Then, we bind the value of the \c input property of the mapper to
|
||||
the value of the \c value property of the slider and set the value
|
||||
of the \uicontrol Max field to 0.60.
|
||||
|
||||
\image studio-logic-helper-minmax-mapper-input.png "Binding slider value property to string mapper"
|
||||
|
||||
To have the maximum value displayed by the \l Text component, we select
|
||||
the \uicontrol {String Mapper} component and change the binding we set
|
||||
as the value of the \uicontrol Input field from \c slider.value to
|
||||
\c minMaxMapper.value.
|
||||
|
||||
\image studio-logic-helper-minmax-mapper-string-mapper-input.png "Binding string mapper input to min max mapper"
|
||||
|
||||
When we move the slider handle in the preview, it only moves up to the
|
||||
value 0.60.
|
||||
|
||||
\image studio-logic-helper-minmax-mapper.gif "Previewing a minimum-maximum mapper"
|
||||
|
||||
The \uicontrol OutOfRange, \uicontrol MaxClipped and \uicontrol MinClipped
|
||||
check boxes are set to \c true if the value of the \uicontrol Input field
|
||||
is out of range.
|
||||
|
||||
For example, in the context of speed, \uicontrol MaxClipped being \c true
|
||||
would mean \e {too fast}, whereas \uicontrol MinClipped being \c true, would
|
||||
mean \e {too slow}, and \uicontrol OutOfRange being \c true would mean
|
||||
\e {either too fast or too slow}.
|
||||
|
||||
\section1 Range Mapper
|
||||
|
||||
The \uicontrol {Range Mapper} type maps a numerical range to another range,
|
||||
so that the output value of the second range follows the input value of the
|
||||
original range. This is useful when remapping the current frame on the
|
||||
timeline, for example.
|
||||
|
||||
\image studio-logic-helper-range-mapper-properties.png "Range Mapper properties"
|
||||
|
||||
Specify the minimum and maximum input and output values in the
|
||||
\uicontrol InputMin, \uicontrol InputMax, \uicontrol OutputMin,
|
||||
and \uicontrol OutputMax fields and the original value in the
|
||||
\uicontrol Value field.
|
||||
|
||||
For example, we can specify that the values of a slider range from -1 to 1.
|
||||
If we want to display values from 10 to 1000, instead, we can bind the
|
||||
values of the \uicontrol From and \uicontrol To fields of the \l Slider
|
||||
type to the values of the \uicontrol InputMin and \uicontrol InputMax
|
||||
fields of a \uicontrol {Range Mapper} type. We then set the value of the
|
||||
\uicontrol OutputMin field to 10 and the value of the \uicontrol OutputMax
|
||||
field to 1000.
|
||||
|
||||
\image studio-logic-helper-range-mapper-inputmin.png "Binding range mapper minimum input to slider.from property"
|
||||
|
||||
When we move the slider handle in the preview, so that the input value
|
||||
from the \l Slider type changes from -1 to 1, the output value changes
|
||||
from 10 to 1000.
|
||||
|
||||
\image studio-logic-helper-range-mapper.gif "Previewing a range mapper"
|
||||
|
||||
\section1 Summary of Logic Helpers
|
||||
|
||||
The following table summarizes the available effects and contains links to
|
||||
the documentation of the inherited QML type.
|
||||
|
||||
\table
|
||||
\header
|
||||
\li Icon
|
||||
\li Qt Quick Studio Effect
|
||||
\li Description
|
||||
\row
|
||||
\li \inlineimage icons/lc-and-operator-16px.png
|
||||
\li And Operator
|
||||
\li Boolean AND.
|
||||
\row
|
||||
\li \inlineimage icons/lc-bidirectional-binding-16px.png
|
||||
\li Bi Direct. Binding
|
||||
\li A bi-directional binding that binds two values in both directions
|
||||
and keeps them in sync.
|
||||
\row
|
||||
\li \inlineimage icons/lc-min-max-16px.png
|
||||
\li Min Max Mapper
|
||||
\li Maps a number to another number with a minimum and maximum value.
|
||||
\row
|
||||
\li \inlineimage icons/lc-not-operator-16px.png
|
||||
\li Not Operator
|
||||
\li Boolean NOT.
|
||||
\row
|
||||
\li \inlineimage icons/lc-or-operator-16px.png
|
||||
\li Or Operator
|
||||
\li Boolean OR.
|
||||
\row
|
||||
\li \inlineimage icons/lc-range-mapper-16px.png
|
||||
\li Range Mapper
|
||||
\li Maps a numerical range to another range, so that the output value
|
||||
of the second range follows the input value of the original range.
|
||||
\row
|
||||
\li \inlineimage icons/lc-string-mapper-16px.png
|
||||
\li String Mapper
|
||||
\li Maps a number to a string with the defined precision.
|
||||
\endtable
|
||||
*/
|
||||
@@ -26,7 +26,7 @@
|
||||
/*!
|
||||
\page quick-2d-effects.html
|
||||
\previouspage quick-data-models.html
|
||||
\nextpage quick-buttons.html
|
||||
\nextpage quick-logic-helpers.html
|
||||
|
||||
\title 2D Effects
|
||||
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
|
||||
NOTE:
|
||||
|
||||
While the primary intention of this pretty printing implementation is
|
||||
to provide what Qt Creator needs, it can be used in a plain GDB and LLDB
|
||||
session, too.
|
||||
to provide what Qt Creator needs, it can sometimes be used in plain
|
||||
GDB and LLDB sessions, too.
|
||||
|
||||
This features is provided as-is. There is no guarantee this works in any
|
||||
way outside Qt Creator, this setup is not officially supported.
|
||||
Bugreports or (better!) patches are welcome.
|
||||
|
||||
|
||||
|
||||
With
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<!DOCTYPE TS><TS>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="hu">
|
||||
<context>
|
||||
<name>Application</name>
|
||||
<message>
|
||||
|
||||
@@ -41,7 +41,7 @@ list(APPEND CMAKE_MODULE_PATH \${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
include(CMakeFindDependencyMacro)
|
||||
find_dependency(Qt5 ${IDE_QT_VERSION_MIN}
|
||||
COMPONENTS Concurrent Core Network PrintSupport Qml Quick QuickWidgets Sql REQUIRED
|
||||
COMPONENTS Concurrent Core Gui Widgets Core5Compat Network PrintSupport Qml Quick QuickWidgets Sql REQUIRED
|
||||
)
|
||||
|
||||
if (NOT IDE_VERSION)
|
||||
|
||||
234
src/libs/3rdparty/sqlite/carray.c
vendored
@@ -57,21 +57,32 @@ SQLITE_EXTENSION_INIT1
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Allowed values for the mFlags parameter to sqlite3_carray_bind().
|
||||
** Must exactly match the definitions in carray.h.
|
||||
*/
|
||||
#define CARRAY_INT32 0 /* Data is 32-bit signed integers */
|
||||
#define CARRAY_INT64 1 /* Data is 64-bit signed integers */
|
||||
#define CARRAY_DOUBLE 2 /* Data is doubles */
|
||||
#define CARRAY_TEXT 3 /* Data is char* */
|
||||
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
|
||||
/*
|
||||
** Allowed datatypes
|
||||
*/
|
||||
#define CARRAY_INT32 0
|
||||
#define CARRAY_INT64 1
|
||||
#define CARRAY_DOUBLE 2
|
||||
#define CARRAY_TEXT 3
|
||||
|
||||
/*
|
||||
** Names of types
|
||||
** Names of allowed datatypes
|
||||
*/
|
||||
static const char *azType[] = { "int32", "int64", "double", "char*" };
|
||||
|
||||
/*
|
||||
** Structure used to hold the sqlite3_carray_bind() information
|
||||
*/
|
||||
typedef struct carray_bind carray_bind;
|
||||
struct carray_bind {
|
||||
void *aData; /* The data */
|
||||
int nData; /* Number of elements */
|
||||
int mFlags; /* Control flags */
|
||||
void (*xDel)(void*); /* Destructor for aData */
|
||||
};
|
||||
|
||||
|
||||
/* carray_cursor is a subclass of sqlite3_vtab_cursor which will
|
||||
** serve as the underlying representation of a cursor that scans
|
||||
@@ -136,16 +147,13 @@ static int carrayDisconnect(sqlite3_vtab *pVtab){
|
||||
/*
|
||||
** Constructor for a new carray_cursor object.
|
||||
*/
|
||||
static int carrayOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor)
|
||||
{
|
||||
carray_cursor *pCur;
|
||||
|
||||
pCur = sqlite3_malloc(sizeof(*pCur));
|
||||
if (pCur == 0)
|
||||
return SQLITE_NOMEM;
|
||||
memset(pCur, 0, sizeof(*pCur));
|
||||
*ppCursor = &pCur->base;
|
||||
return SQLITE_OK;
|
||||
static int carrayOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
|
||||
carray_cursor *pCur;
|
||||
pCur = sqlite3_malloc( sizeof(*pCur) );
|
||||
if( pCur==0 ) return SQLITE_NOMEM;
|
||||
memset(pCur, 0, sizeof(*pCur));
|
||||
*ppCursor = &pCur->base;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -242,28 +250,39 @@ static int carrayFilter(
|
||||
int argc, sqlite3_value **argv
|
||||
){
|
||||
carray_cursor *pCur = (carray_cursor *)pVtabCursor;
|
||||
if( idxNum ){
|
||||
pCur->pPtr = sqlite3_value_pointer(argv[0], "carray");
|
||||
pCur->iCnt = pCur->pPtr ? sqlite3_value_int64(argv[1]) : 0;
|
||||
if( idxNum<3 ){
|
||||
pCur->eType = CARRAY_INT32;
|
||||
}else{
|
||||
unsigned char i;
|
||||
const char *zType = (const char*)sqlite3_value_text(argv[2]);
|
||||
for(i=0; i<sizeof(azType)/sizeof(azType[0]); i++){
|
||||
if( sqlite3_stricmp(zType, azType[i])==0 ) break;
|
||||
}
|
||||
if( i>=sizeof(azType)/sizeof(azType[0]) ){
|
||||
pVtabCursor->pVtab->zErrMsg = sqlite3_mprintf(
|
||||
"unknown datatype: %Q", zType);
|
||||
return SQLITE_ERROR;
|
||||
}else{
|
||||
pCur->eType = i;
|
||||
}
|
||||
pCur->pPtr = 0;
|
||||
pCur->iCnt = 0;
|
||||
switch( idxNum ){
|
||||
case 1: {
|
||||
carray_bind *pBind = sqlite3_value_pointer(argv[0], "carray-bind");
|
||||
if( pBind==0 ) break;
|
||||
pCur->pPtr = pBind->aData;
|
||||
pCur->iCnt = pBind->nData;
|
||||
pCur->eType = pBind->mFlags & 0x03;
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
case 3: {
|
||||
pCur->pPtr = sqlite3_value_pointer(argv[0], "carray");
|
||||
pCur->iCnt = pCur->pPtr ? sqlite3_value_int64(argv[1]) : 0;
|
||||
if( idxNum<3 ){
|
||||
pCur->eType = CARRAY_INT32;
|
||||
}else{
|
||||
unsigned char i;
|
||||
const char *zType = (const char*)sqlite3_value_text(argv[2]);
|
||||
for(i=0; i<sizeof(azType)/sizeof(azType[0]); i++){
|
||||
if( sqlite3_stricmp(zType, azType[i])==0 ) break;
|
||||
}
|
||||
if( i>=sizeof(azType)/sizeof(azType[0]) ){
|
||||
pVtabCursor->pVtab->zErrMsg = sqlite3_mprintf(
|
||||
"unknown datatype: %Q", zType);
|
||||
return SQLITE_ERROR;
|
||||
}else{
|
||||
pCur->eType = i;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}else{
|
||||
pCur->pPtr = 0;
|
||||
pCur->iCnt = 0;
|
||||
}
|
||||
pCur->iRowid = 1;
|
||||
return SQLITE_OK;
|
||||
@@ -278,9 +297,16 @@ static int carrayFilter(
|
||||
** In this implementation idxNum is used to represent the
|
||||
** query plan. idxStr is unused.
|
||||
**
|
||||
** idxNum is 2 if the pointer= and count= constraints exist,
|
||||
** 3 if the ctype= constraint also exists, and is 0 otherwise.
|
||||
** If idxNum is 0, then carray becomes an empty table.
|
||||
** idxNum is:
|
||||
**
|
||||
** 1 If only the pointer= constraint exists. In this case, the
|
||||
** parameter must be bound using sqlite3_carray_bind().
|
||||
**
|
||||
** 2 if the pointer= and count= constraints exist.
|
||||
**
|
||||
** 3 if the ctype= constraint also exists.
|
||||
**
|
||||
** idxNum is 0 otherwise and carray becomes an empty table.
|
||||
*/
|
||||
static int carrayBestIndex(
|
||||
sqlite3_vtab *tab,
|
||||
@@ -308,18 +334,21 @@ static int carrayBestIndex(
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( ptrIdx>=0 && cntIdx>=0 ){
|
||||
if( ptrIdx>=0 ){
|
||||
pIdxInfo->aConstraintUsage[ptrIdx].argvIndex = 1;
|
||||
pIdxInfo->aConstraintUsage[ptrIdx].omit = 1;
|
||||
pIdxInfo->aConstraintUsage[cntIdx].argvIndex = 2;
|
||||
pIdxInfo->aConstraintUsage[cntIdx].omit = 1;
|
||||
pIdxInfo->estimatedCost = (double)1;
|
||||
pIdxInfo->estimatedRows = 100;
|
||||
pIdxInfo->idxNum = 2;
|
||||
if( ctypeIdx>=0 ){
|
||||
pIdxInfo->aConstraintUsage[ctypeIdx].argvIndex = 3;
|
||||
pIdxInfo->aConstraintUsage[ctypeIdx].omit = 1;
|
||||
pIdxInfo->idxNum = 3;
|
||||
pIdxInfo->idxNum = 1;
|
||||
if( cntIdx>=0 ){
|
||||
pIdxInfo->aConstraintUsage[cntIdx].argvIndex = 2;
|
||||
pIdxInfo->aConstraintUsage[cntIdx].omit = 1;
|
||||
pIdxInfo->idxNum = 2;
|
||||
if( ctypeIdx>=0 ){
|
||||
pIdxInfo->aConstraintUsage[ctypeIdx].argvIndex = 3;
|
||||
pIdxInfo->aConstraintUsage[ctypeIdx].omit = 1;
|
||||
pIdxInfo->idxNum = 3;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
pIdxInfo->estimatedCost = (double)2147483647;
|
||||
@@ -356,6 +385,89 @@ static sqlite3_module carrayModule = {
|
||||
0, /* xRename */
|
||||
};
|
||||
|
||||
/*
|
||||
** Destructor for the carray_bind object
|
||||
*/
|
||||
static void carrayBindDel(void *pPtr){
|
||||
carray_bind *p = (carray_bind*)pPtr;
|
||||
if( p->xDel!=SQLITE_STATIC ){
|
||||
p->xDel(p->aData);
|
||||
}
|
||||
sqlite3_free(p);
|
||||
}
|
||||
|
||||
/*
|
||||
** Invoke this interface in order to bind to the single-argument
|
||||
** version of CARRAY().
|
||||
*/
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_carray_bind(
|
||||
sqlite3_stmt *pStmt,
|
||||
int idx,
|
||||
void *aData,
|
||||
int nData,
|
||||
int mFlags,
|
||||
void (*xDestroy)(void*)
|
||||
){
|
||||
carray_bind *pNew;
|
||||
int i;
|
||||
pNew = sqlite3_malloc64(sizeof(*pNew));
|
||||
if( pNew==0 ){
|
||||
if( xDestroy!=SQLITE_STATIC && xDestroy!=SQLITE_TRANSIENT ){
|
||||
xDestroy(aData);
|
||||
}
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
pNew->nData = nData;
|
||||
pNew->mFlags = mFlags;
|
||||
if( xDestroy==SQLITE_TRANSIENT ){
|
||||
sqlite3_int64 sz = nData;
|
||||
switch( mFlags & 0x03 ){
|
||||
case CARRAY_INT32: sz *= 4; break;
|
||||
case CARRAY_INT64: sz *= 8; break;
|
||||
case CARRAY_DOUBLE: sz *= 8; break;
|
||||
case CARRAY_TEXT: sz *= sizeof(char*); break;
|
||||
}
|
||||
if( (mFlags & 0x03)==CARRAY_TEXT ){
|
||||
for(i=0; i<nData; i++){
|
||||
const char *z = ((char**)aData)[i];
|
||||
if( z ) sz += strlen(z) + 1;
|
||||
}
|
||||
}
|
||||
pNew->aData = sqlite3_malloc64( sz );
|
||||
if( pNew->aData==0 ){
|
||||
sqlite3_free(pNew);
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
if( (mFlags & 0x03)==CARRAY_TEXT ){
|
||||
char **az = (char**)pNew->aData;
|
||||
char *z = (char*)&az[nData];
|
||||
for(i=0; i<nData; i++){
|
||||
const char *zData = ((char**)aData)[i];
|
||||
sqlite3_int64 n;
|
||||
if( zData==0 ){
|
||||
az[i] = 0;
|
||||
continue;
|
||||
}
|
||||
az[i] = z;
|
||||
n = strlen(zData);
|
||||
memcpy(z, zData, n+1);
|
||||
z += n+1;
|
||||
}
|
||||
}else{
|
||||
memcpy(pNew->aData, aData, sz*nData);
|
||||
}
|
||||
pNew->xDel = sqlite3_free;
|
||||
}else{
|
||||
pNew->aData = aData;
|
||||
pNew->xDel = xDestroy;
|
||||
}
|
||||
return sqlite3_bind_pointer(pStmt, idx, pNew, "carray-bind", carrayBindDel);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** For testing purpose in the TCL test harness, we need a method for
|
||||
** setting the pointer value. The inttoptr(X) SQL function accomplishes
|
||||
@@ -386,16 +498,22 @@ static void inttoptrFunc(
|
||||
|
||||
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
||||
|
||||
int sqlite3_carray_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi)
|
||||
{
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_carray_init(
|
||||
sqlite3 *db,
|
||||
char **pzErrMsg,
|
||||
const sqlite3_api_routines *pApi
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
rc = sqlite3_create_module(db, "carray", &carrayModule, 0);
|
||||
|
||||
#ifdef SQLITE_TEST
|
||||
if (rc == SQLITE_OK) {
|
||||
rc = sqlite3_create_function(db, "inttoptr", 1, SQLITE_UTF8, 0, inttoptrFunc, 0, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "inttoptr", 1, SQLITE_UTF8, 0,
|
||||
inttoptrFunc, 0, 0);
|
||||
}
|
||||
#endif /* SQLITE_TEST */
|
||||
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
||||
|
||||
26555
src/libs/3rdparty/sqlite/sqlite3.c
vendored
1669
src/libs/3rdparty/sqlite/sqlite3.h
vendored
13
src/libs/3rdparty/sqlite/sqlite3ext.h
vendored
@@ -330,6 +330,13 @@ struct sqlite3_api_routines {
|
||||
const char *(*filename_database)(const char*);
|
||||
const char *(*filename_journal)(const char*);
|
||||
const char *(*filename_wal)(const char*);
|
||||
/* Version 3.32.0 and later */
|
||||
char *(*create_filename)(const char*,const char*,const char*,
|
||||
int,const char**);
|
||||
void (*free_filename)(char*);
|
||||
sqlite3_file *(*database_file_object)(const char*);
|
||||
/* Version 3.34.0 and later */
|
||||
int (*txn_state)(sqlite3*,const char*);
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -630,6 +637,12 @@ typedef int (*sqlite3_loadext_entry)(
|
||||
#define sqlite3_filename_database sqlite3_api->filename_database
|
||||
#define sqlite3_filename_journal sqlite3_api->filename_journal
|
||||
#define sqlite3_filename_wal sqlite3_api->filename_wal
|
||||
/* Version 3.32.0 and later */
|
||||
#define sqlite3_create_filename sqlite3_api->create_filename
|
||||
#define sqlite3_free_filename sqlite3_api->free_filename
|
||||
#define sqlite3_database_file_object sqlite3_api->database_file_object
|
||||
/* Version 3.34.0 and later */
|
||||
#define sqlite3_txn_state sqlite3_api->txn_state
|
||||
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
|
||||
|
||||
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
|
||||
|
||||
@@ -479,8 +479,8 @@ void Snapshot::insert(const Document::Ptr &document, bool allowInvalid)
|
||||
CoreImport cImport;
|
||||
cImport.importId = document->importId();
|
||||
cImport.language = document->language();
|
||||
cImport.possibleExports << Export(ImportKey(ImportType::File, fileName),
|
||||
QString(), true, QFileInfo(fileName).baseName());
|
||||
cImport.addPossibleExport(Export(ImportKey(ImportType::File, fileName),
|
||||
{}, true, QFileInfo(fileName).baseName()));
|
||||
cImport.fingerprint = document->fingerprint();
|
||||
_dependencies.addCoreImport(cImport);
|
||||
}
|
||||
@@ -526,13 +526,13 @@ void Snapshot::insertLibraryInfo(const QString &path, const LibraryInfo &info)
|
||||
break;
|
||||
ImportKey iKey(ImportType::Library, QStringList(myPath.mid(iPath)).join(QLatin1Char('.')),
|
||||
importKey.majorVersion, importKey.minorVersion);
|
||||
cImport.possibleExports.append(Export(iKey, (iPath == 1) ? QLatin1String("/") :
|
||||
cImport.addPossibleExport(Export(iKey, (iPath == 1) ? QLatin1String("/") :
|
||||
QStringList(myPath.mid(0, iPath)).join(QLatin1Char('/')), true));
|
||||
}
|
||||
} else {
|
||||
QString requiredPath = QStringList(splitPath.mid(0, splitPath.size() - importKey.splitPath.size()))
|
||||
.join(QLatin1String("/"));
|
||||
cImport.possibleExports << Export(importKey, requiredPath, true);
|
||||
cImport.addPossibleExport(Export(importKey, requiredPath, true));
|
||||
}
|
||||
}
|
||||
if (cImport.possibleExports.isEmpty() && splitPath.size() > 0) {
|
||||
@@ -567,7 +567,7 @@ void Snapshot::insertLibraryInfo(const QString &path, const LibraryInfo &info)
|
||||
break;
|
||||
ImportKey iKey(ImportType::Library, QStringList(splitPath.mid(iPath)).join(QLatin1Char('.')),
|
||||
majorVersion, minorVersion);
|
||||
cImport.possibleExports.append(Export(iKey, (iPath == 1) ? QLatin1String("/") :
|
||||
cImport.addPossibleExport(Export(iKey, (iPath == 1) ? QLatin1String("/") :
|
||||
QStringList(splitPath.mid(0, iPath)).join(QLatin1Char('/')), true));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,11 +32,35 @@
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QCryptographicHash>
|
||||
#include <QElapsedTimer>
|
||||
#include <QLoggingCategory>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
static Q_LOGGING_CATEGORY(importsLog, "qtc.qmljs.imports", QtWarningMsg)
|
||||
static Q_LOGGING_CATEGORY(importsBenchmark, "qtc.qmljs.imports.benchmark", QtDebugMsg)
|
||||
|
||||
|
||||
class ImportsBenchmarker
|
||||
{
|
||||
public:
|
||||
ImportsBenchmarker(const QString &functionName)
|
||||
: m_functionName(functionName)
|
||||
{
|
||||
m_timer.start();
|
||||
}
|
||||
|
||||
~ImportsBenchmarker()
|
||||
{
|
||||
if (importsBenchmark().isDebugEnabled()) {
|
||||
qCDebug(importsBenchmark).noquote().nospace() << m_functionName << " executed nPossibleExports: " << nPossibleExports << " in " << m_timer.elapsed() << "ms";
|
||||
}
|
||||
}
|
||||
int nPossibleExports = 0;
|
||||
|
||||
QElapsedTimer m_timer;
|
||||
QString m_functionName;
|
||||
};
|
||||
|
||||
namespace QmlJS {
|
||||
|
||||
@@ -304,7 +328,7 @@ ImportMatchStrength ImportKey::matchImport(const ImportKey &o, const ViewerConte
|
||||
return ImportMatchStrength();
|
||||
const QString p1 = splitPath.at(iPath1);
|
||||
if (iPath2 < lenPath2) {
|
||||
const QString p2 = splitPath.at(iPath2);
|
||||
const QString p2 = o.splitPath.at(iPath2);
|
||||
if (p1 == p2) {
|
||||
++iPath1;
|
||||
++iPath2;
|
||||
@@ -520,19 +544,6 @@ bool Export::visibleInVContext(const ViewerContext &vContext) const
|
||||
return pathRequired.isEmpty() || vContext.paths.contains(pathRequired);
|
||||
}
|
||||
|
||||
bool operator ==(const Export &i1, const Export &i2)
|
||||
{
|
||||
return i1.exportName == i2.exportName
|
||||
&& i1.pathRequired == i2.pathRequired
|
||||
&& i1.intrinsic == i2.intrinsic
|
||||
&& i1.typeName == i2.typeName;
|
||||
}
|
||||
|
||||
bool operator !=(const Export &i1, const Export &i2)
|
||||
{
|
||||
return !(i1 == i2);
|
||||
}
|
||||
|
||||
CoreImport::CoreImport() : language(Dialect::Qml) { }
|
||||
|
||||
CoreImport::CoreImport(const QString &importId, const QList<Export> &possibleExports,
|
||||
@@ -609,6 +620,7 @@ ImportDependencies::~ImportDependencies()
|
||||
|
||||
void ImportDependencies::filter(const ViewerContext &vContext)
|
||||
{
|
||||
ImportsBenchmarker benchMark("filter()");
|
||||
QMap<QString, CoreImport> newCoreImports;
|
||||
QMap<ImportKey, QStringList> newImportCache;
|
||||
bool hasChanges = false;
|
||||
@@ -617,6 +629,7 @@ void ImportDependencies::filter(const ViewerContext &vContext)
|
||||
if (languageIsCompatible(vContext.language, cImport.language)) {
|
||||
QList<Export> newExports;
|
||||
foreach (const Export &e, cImport.possibleExports) {
|
||||
++benchMark.nPossibleExports;
|
||||
if (e.visibleInVContext(vContext)) {
|
||||
newExports.append(e);
|
||||
QStringList &candidateImports = newImportCache[e.exportName];
|
||||
@@ -654,6 +667,7 @@ void ImportDependencies::iterateOnCandidateImports(
|
||||
std::function<bool (const ImportMatchStrength &,const Export &,const CoreImport &)>
|
||||
const &iterF) const
|
||||
{
|
||||
ImportsBenchmarker benchMark("iterateOnCandidateImports()");
|
||||
switch (key.type) {
|
||||
case ImportType::Directory:
|
||||
case ImportType::QrcDirectory:
|
||||
@@ -666,6 +680,7 @@ void ImportDependencies::iterateOnCandidateImports(
|
||||
CoreImport cImport = coreImport(cImportName);
|
||||
if (languageIsCompatible(vContext.language, cImport.language)) {
|
||||
foreach (const Export e, cImport.possibleExports) {
|
||||
++benchMark.nPossibleExports;
|
||||
if (e.visibleInVContext(vContext)) {
|
||||
ImportMatchStrength m = e.exportName.matchImport(key, vContext);
|
||||
if (m.hasMatch()) {
|
||||
@@ -688,6 +703,7 @@ void ImportDependencies::iterateOnCandidateImports(
|
||||
CoreImport cImport = coreImport(cImportName);
|
||||
if (languageIsCompatible(vContext.language, cImport.language)) {
|
||||
foreach (const Export e, cImport.possibleExports) {
|
||||
++benchMark.nPossibleExports;
|
||||
if (e.visibleInVContext(vContext)) {
|
||||
ImportMatchStrength m = e.exportName.matchImport(key, vContext);
|
||||
if (m.hasMatch()) {
|
||||
@@ -810,13 +826,13 @@ void ImportDependencies::addExport(const QString &importId, const ImportKey &imp
|
||||
if (!m_coreImports.contains(importId)) {
|
||||
CoreImport newImport(importId);
|
||||
newImport.language = Dialect::AnyLanguage;
|
||||
newImport.possibleExports.append(Export(importKey, requiredPath, false, typeName));
|
||||
newImport.addPossibleExport(Export(importKey, requiredPath, false, typeName));
|
||||
m_coreImports.insert(newImport.importId, newImport);
|
||||
m_importCache[importKey].append(importId);
|
||||
return;
|
||||
}
|
||||
CoreImport &importValue = m_coreImports[importId];
|
||||
importValue.possibleExports.append(Export(importKey, requiredPath, false, typeName));
|
||||
importValue.addPossibleExport(Export(importKey, requiredPath, false, typeName));
|
||||
m_importCache[importKey].append(importId);
|
||||
qCDebug(importsLog) << "added export "<< importKey.toString() << " for id " <<importId
|
||||
<< " (" << requiredPath << ")";
|
||||
@@ -853,6 +869,8 @@ void ImportDependencies::iterateOnLibraryImports(
|
||||
const Export &,
|
||||
const CoreImport &)> const &iterF) const
|
||||
{
|
||||
ImportsBenchmarker benchMark("iterateOnLibraryImports()");
|
||||
|
||||
typedef QMap<ImportKey, QStringList>::const_iterator iter_t;
|
||||
ImportKey firstLib;
|
||||
firstLib.type = ImportType::Library;
|
||||
@@ -864,6 +882,7 @@ void ImportDependencies::iterateOnLibraryImports(
|
||||
CoreImport cImport = coreImport(cImportName);
|
||||
if (languageIsCompatible(vContext.language, cImport.language)) {
|
||||
foreach (const Export &e, cImport.possibleExports) {
|
||||
++benchMark.nPossibleExports;
|
||||
if (e.visibleInVContext(vContext) && e.exportName.type == ImportType::Library) {
|
||||
ImportMatchStrength m = e.exportName.matchImport(i.key(), vContext);
|
||||
if (m.hasMatch()) {
|
||||
@@ -887,6 +906,7 @@ void ImportDependencies::iterateOnSubImports(
|
||||
const Export &,
|
||||
const CoreImport &)> const &iterF) const
|
||||
{
|
||||
ImportsBenchmarker benchMark("iterateOnSubImports()");
|
||||
typedef QMap<ImportKey, QStringList>::const_iterator iter_t;
|
||||
iter_t i = m_importCache.lowerBound(baseKey);
|
||||
iter_t end = m_importCache.constEnd();
|
||||
@@ -898,6 +918,7 @@ void ImportDependencies::iterateOnSubImports(
|
||||
CoreImport cImport = coreImport(cImportName);
|
||||
if (languageIsCompatible(vContext.language, cImport.language)) {
|
||||
foreach (const Export &e, cImport.possibleExports) {
|
||||
++benchMark.nPossibleExports;
|
||||
if (e.visibleInVContext(vContext)) {
|
||||
ImportMatchStrength m = e.exportName.matchImport(i.key(), vContext);
|
||||
if (m.hasMatch()) {
|
||||
|
||||
@@ -134,9 +134,27 @@ public:
|
||||
QString typeName;
|
||||
bool intrinsic;
|
||||
bool visibleInVContext(const ViewerContext &vContext) const;
|
||||
|
||||
|
||||
friend bool operator==(const Export &i1, const Export &i2)
|
||||
{
|
||||
return i1.exportName == i2.exportName
|
||||
&& i1.pathRequired == i2.pathRequired
|
||||
&& i1.intrinsic == i2.intrinsic
|
||||
&& i1.typeName == i2.typeName;
|
||||
}
|
||||
|
||||
friend bool operator!=(const Export &i1, const Export &i2)
|
||||
{
|
||||
return !(i1 == i2);
|
||||
}
|
||||
|
||||
friend bool operator<(const Export &i1, const Export &i2)
|
||||
{
|
||||
return std::tie(i1.intrinsic, i1.pathRequired, i1.typeName, i1.exportName)
|
||||
< std::tie(i2.intrinsic, i2.pathRequired, i2.typeName, i2.exportName);
|
||||
}
|
||||
};
|
||||
bool operator ==(const Export &i1, const Export &i2);
|
||||
bool operator !=(const Export &i1, const Export &i2);
|
||||
|
||||
class QMLJS_EXPORT CoreImport
|
||||
{
|
||||
@@ -144,6 +162,14 @@ public:
|
||||
CoreImport();
|
||||
CoreImport(const QString &importId, const QList<Export> &possibleExports = QList<Export>(),
|
||||
Dialect language = Dialect::Qml, const QByteArray &fingerprint = QByteArray());
|
||||
template<typename E>
|
||||
void addPossibleExport(E &&e)
|
||||
{
|
||||
auto found = std::lower_bound(possibleExports.begin(), possibleExports.end(), e);
|
||||
if (found == possibleExports.end() || e != *found)
|
||||
possibleExports.insert(found, std::forward<E>(e));
|
||||
}
|
||||
|
||||
QString importId;
|
||||
QList<Export> possibleExports;
|
||||
Dialect language;
|
||||
|
||||
@@ -446,12 +446,10 @@ std::string collectOutput()
|
||||
// Add a child to messages for every line.
|
||||
while (std::getline(pyStdout, line)) {
|
||||
// there are two kinds of messages we want to handle here:
|
||||
if (line.find("bridgemessage=") == 0) { // preformatted gdmi bridgemessages from warn()
|
||||
if (line.find("bridgemessage=") == 0) // preformatted gdmi bridgemessages from warn()
|
||||
ret << line << ',';
|
||||
} else { // and a line of "normal" python output
|
||||
replace(line, '"', '$'); // otherwise creators gdbmi parser would fail
|
||||
ret << "line=\"" << line << "\",";
|
||||
}
|
||||
else // and a line of "normal" python output
|
||||
ret << "line=\"" << gdbmiStringFormat(line) << "\",";
|
||||
}
|
||||
ret << "]," << results << "]";
|
||||
results.clear();
|
||||
|
||||
@@ -38,6 +38,14 @@
|
||||
# pragma GCC diagnostic ignored "-Wignored-qualifiers"
|
||||
#endif
|
||||
|
||||
#define CARRAY_INT32 0 /* Data is 32-bit signed integers */
|
||||
#define CARRAY_INT64 1 /* Data is 64-bit signed integers */
|
||||
#define CARRAY_DOUBLE 2 /* Data is doubles */
|
||||
#define CARRAY_TEXT 3 /* Data is char* */
|
||||
|
||||
extern "C" int sqlite3_carray_bind(
|
||||
sqlite3_stmt *pStmt, int idx, void *aData, int nData, int mFlags, void (*xDestroy)(void *));
|
||||
|
||||
namespace Sqlite {
|
||||
|
||||
BaseStatement::BaseStatement(Utils::SmallStringView sqlStatement, Database &database)
|
||||
@@ -180,6 +188,54 @@ void BaseStatement::bind(int index, void *pointer)
|
||||
checkForBindingError(resultCode);
|
||||
}
|
||||
|
||||
void BaseStatement::bind(int index, Utils::span<int> values)
|
||||
{
|
||||
int resultCode = sqlite3_carray_bind(m_compiledStatement.get(),
|
||||
index,
|
||||
values.data(),
|
||||
static_cast<int>(values.size()),
|
||||
CARRAY_INT32,
|
||||
SQLITE_STATIC);
|
||||
if (resultCode != SQLITE_OK)
|
||||
checkForBindingError(resultCode);
|
||||
}
|
||||
|
||||
void BaseStatement::bind(int index, Utils::span<long long> values)
|
||||
{
|
||||
int resultCode = sqlite3_carray_bind(m_compiledStatement.get(),
|
||||
index,
|
||||
values.data(),
|
||||
static_cast<int>(values.size()),
|
||||
CARRAY_INT64,
|
||||
SQLITE_STATIC);
|
||||
if (resultCode != SQLITE_OK)
|
||||
checkForBindingError(resultCode);
|
||||
}
|
||||
|
||||
void BaseStatement::bind(int index, Utils::span<double> values)
|
||||
{
|
||||
int resultCode = sqlite3_carray_bind(m_compiledStatement.get(),
|
||||
index,
|
||||
values.data(),
|
||||
static_cast<int>(values.size()),
|
||||
CARRAY_DOUBLE,
|
||||
SQLITE_STATIC);
|
||||
if (resultCode != SQLITE_OK)
|
||||
checkForBindingError(resultCode);
|
||||
}
|
||||
|
||||
void BaseStatement::bind(int index, Utils::span<const char *> values)
|
||||
{
|
||||
int resultCode = sqlite3_carray_bind(m_compiledStatement.get(),
|
||||
index,
|
||||
values.data(),
|
||||
static_cast<int>(values.size()),
|
||||
CARRAY_TEXT,
|
||||
SQLITE_STATIC);
|
||||
if (resultCode != SQLITE_OK)
|
||||
checkForBindingError(resultCode);
|
||||
}
|
||||
|
||||
void BaseStatement::bind(int index, Utils::SmallStringView text)
|
||||
{
|
||||
int resultCode = sqlite3_bind_text(m_compiledStatement.get(),
|
||||
|
||||
@@ -77,12 +77,16 @@ public:
|
||||
int columnCount() const;
|
||||
|
||||
void bind(int index, NullValue);
|
||||
void bind(int index, int fetchValue);
|
||||
void bind(int index, long long fetchValue);
|
||||
void bind(int index, double fetchValue);
|
||||
void bind(int index, int value);
|
||||
void bind(int index, long long value);
|
||||
void bind(int index, double value);
|
||||
void bind(int index, void *pointer);
|
||||
void bind(int index, Utils::SmallStringView fetchValue);
|
||||
void bind(int index, const Value &fetchValue);
|
||||
void bind(int index, Utils::span<int> values);
|
||||
void bind(int index, Utils::span<long long> values);
|
||||
void bind(int index, Utils::span<double> values);
|
||||
void bind(int index, Utils::span<const char *> values);
|
||||
void bind(int index, Utils::SmallStringView value);
|
||||
void bind(int index, const Value &value);
|
||||
void bind(int index, BlobView blobView);
|
||||
|
||||
void bind(int index, uint value) { bind(index, static_cast<long long>(value)); }
|
||||
|
||||
@@ -54,7 +54,7 @@ DatabaseBackend::~DatabaseBackend()
|
||||
closeWithoutException();
|
||||
}
|
||||
|
||||
void DatabaseBackend::setMmapSize(qint64 defaultSize, qint64 maximumSize)
|
||||
void DatabaseBackend::setRanslatorentriesapSize(qint64 defaultSize, qint64 maximumSize)
|
||||
{
|
||||
int resultCode = sqlite3_config(SQLITE_CONFIG_MMAP_SIZE, defaultSize, maximumSize);
|
||||
checkMmapSizeIsSet(resultCode);
|
||||
|
||||
@@ -50,7 +50,7 @@ public:
|
||||
DatabaseBackend(DatabaseBackend &&) = delete;
|
||||
DatabaseBackend &operator=(DatabaseBackend &&) = delete;
|
||||
|
||||
static void setMmapSize(qint64 defaultSize, qint64 maximumSize);
|
||||
static void setRanslatorentriesapSize(qint64 defaultSize, qint64 maximumSize);
|
||||
static void activateMultiThreading();
|
||||
static void activateLogging();
|
||||
static void initializeSqliteLibrary();
|
||||
|
||||
@@ -13,3 +13,8 @@ add_qtc_plugin(ClangFormat
|
||||
clangformatsettings.cpp clangformatsettings.h
|
||||
clangformatutils.cpp clangformatutils.h
|
||||
)
|
||||
|
||||
extend_qtc_plugin(ClangFormat
|
||||
CONDITION UNIX AND NOT APPLE
|
||||
PROPERTIES LINK_FLAGS "-Wl,--exclude-libs,ALL"
|
||||
)
|
||||
|
||||
@@ -247,7 +247,7 @@ void DocumentClangToolRunner::runNext()
|
||||
auto [clangIncludeDir, clangVersion] = getClangIncludeDirAndVersion(m_currentRunner.get());
|
||||
qCDebug(LOG) << Q_FUNC_INFO << m_currentRunner->executable() << clangIncludeDir
|
||||
<< clangVersion << m_fileInfo.file;
|
||||
if (clangIncludeDir.isEmpty() || clangVersion.isEmpty()
|
||||
if (m_currentRunner->executable().isEmpty() || clangIncludeDir.isEmpty() || clangVersion.isEmpty()
|
||||
|| (m_document->isModified() && !m_currentRunner->supportsVFSOverlay())) {
|
||||
runNext();
|
||||
} else {
|
||||
|
||||
@@ -4119,10 +4119,7 @@ void GdbEngine::setupInferior()
|
||||
if (symbolFile.isEmpty()) {
|
||||
showMessage(tr("No symbol file given."), StatusBar);
|
||||
callTargetRemote();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!symbolFile.isEmpty()) {
|
||||
} else {
|
||||
runCommand({"-file-exec-and-symbols \"" + symbolFile + '"',
|
||||
CB(handleFileExecAndSymbols)});
|
||||
}
|
||||
|
||||
@@ -60,14 +60,8 @@ extend_qtc_plugin(Help
|
||||
webenginehelpviewer.h
|
||||
)
|
||||
|
||||
if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/qlitehtml/litehtml/CMakeLists.txt)
|
||||
add_subdirectory(qlitehtml)
|
||||
else()
|
||||
find_package(litehtml QUIET)
|
||||
if (TARGET litehtml)
|
||||
add_subdirectory(qlitehtml)
|
||||
endif()
|
||||
endif()
|
||||
find_package(litehtml QUIET)
|
||||
add_subdirectory(qlitehtml)
|
||||
|
||||
extend_qtc_plugin(Help
|
||||
CONDITION TARGET litehtml AND TARGET qlitehtml
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/litehtml/CMakeLists.txt)
|
||||
find_package(litehtml QUIET)
|
||||
if(NOT TARGET litehtml AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/litehtml/CMakeLists.txt)
|
||||
set(ORIG_FPIC ${CMAKE_POSITION_INDEPENDENT_CODE})
|
||||
if (WIN32)
|
||||
set(LITEHTML_UTF8 ON CACHE BOOL "")
|
||||
@@ -16,11 +17,10 @@ if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/litehtml/CMakeLists.txt)
|
||||
target_compile_options(litehtml PRIVATE -O2)
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
find_package(litehtml REQUIRED)
|
||||
endif()
|
||||
|
||||
add_qtc_library(qlitehtml
|
||||
CONDITION TARGET litehtml
|
||||
PUBLIC_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
DEPENDS Qt5::Widgets litehtml
|
||||
PROPERTIES
|
||||
|
||||
@@ -417,6 +417,22 @@ QWidget *MakeStep::createConfigWidget()
|
||||
return widget;
|
||||
}
|
||||
|
||||
bool MakeStep::buildsTarget(const QString &target) const
|
||||
{
|
||||
return m_buildTargetsAspect->value().contains(target);
|
||||
}
|
||||
|
||||
void MakeStep::setBuildTarget(const QString &target, bool on)
|
||||
{
|
||||
QStringList old = m_buildTargetsAspect->value();
|
||||
if (on && !old.contains(target))
|
||||
old << target;
|
||||
else if (!on && old.contains(target))
|
||||
old.removeOne(target);
|
||||
|
||||
m_buildTargetsAspect->setValue(old);
|
||||
}
|
||||
|
||||
QStringList MakeStep::availableTargets() const
|
||||
{
|
||||
return m_buildTargetsAspect->allValues();
|
||||
|
||||
@@ -78,6 +78,11 @@ public:
|
||||
|
||||
Utils::Environment makeEnvironment() const;
|
||||
|
||||
// FIXME: All unused, remove in 4.15.
|
||||
void setBuildTarget(const QString &buildTarget) { setSelectedBuildTarget(buildTarget); }
|
||||
bool buildsTarget(const QString &target) const;
|
||||
void setBuildTarget(const QString &target, bool on);
|
||||
|
||||
protected:
|
||||
void supportDisablingForSubdirs() { m_disablingForSubDirsSupported = true; }
|
||||
virtual QStringList displayArguments() const;
|
||||
@@ -87,6 +92,7 @@ private:
|
||||
QStringList jobArguments() const;
|
||||
|
||||
Utils::MultiSelectionAspect *m_buildTargetsAspect = nullptr;
|
||||
QStringList m_availableTargets; // FIXME: Unused, remove in 4.15.
|
||||
Utils::StringAspect *m_makeCommandAspect = nullptr;
|
||||
Utils::StringAspect *m_userArgumentsAspect = nullptr;
|
||||
Utils::AspectContainer *m_jobCountContainer = nullptr;
|
||||
|
||||
@@ -497,6 +497,7 @@ extend_qtc_plugin(QmlDesigner
|
||||
include/qmlmodelnodefacade.h
|
||||
include/qmlobjectnode.h
|
||||
include/qmlstate.h
|
||||
include/qmlconnections.h
|
||||
include/qmltimeline.h
|
||||
include/qmltimelinekeyframegroup.h
|
||||
include/removebasestateexception.h
|
||||
@@ -578,6 +579,7 @@ extend_qtc_plugin(QmlDesigner
|
||||
model/qmlmodelnodefacade.cpp
|
||||
model/qmlobjectnode.cpp
|
||||
model/qmlstate.cpp
|
||||
model/qmlconnections.cpp
|
||||
model/qmltextgenerator.cpp model/qmltextgenerator.h
|
||||
model/qmltimeline.cpp
|
||||
model/qmltimelinekeyframegroup.cpp
|
||||
@@ -620,6 +622,9 @@ extend_qtc_plugin(QmlDesigner
|
||||
bindingeditordialog.cpp bindingeditordialog.h
|
||||
bindingeditorwidget.cpp bindingeditorwidget.h
|
||||
connectionvisitor.cpp connectionvisitor.h
|
||||
signallist.cpp signallist.h
|
||||
signallistdialog.cpp signallistdialog.h
|
||||
signallistdelegate.cpp signallistdelegate.h
|
||||
)
|
||||
|
||||
extend_qtc_plugin(QmlDesigner
|
||||
|
||||
@@ -5,6 +5,9 @@ HEADERS += $$PWD/actioneditordialog.h
|
||||
HEADERS += $$PWD/bindingeditordialog.h
|
||||
HEADERS += $$PWD/bindingeditorwidget.h
|
||||
HEADERS += $$PWD/connectionvisitor.h
|
||||
HEADERS += $$PWD/signallist.h
|
||||
HEADERS += $$PWD/signallistdialog.h
|
||||
HEADERS += $$PWD/signallistdelegate.h
|
||||
|
||||
SOURCES += $$PWD/bindingeditor.cpp
|
||||
SOURCES += $$PWD/actioneditor.cpp
|
||||
@@ -13,3 +16,6 @@ SOURCES += $$PWD/actioneditordialog.cpp
|
||||
SOURCES += $$PWD/bindingeditordialog.cpp
|
||||
SOURCES += $$PWD/bindingeditorwidget.cpp
|
||||
SOURCES += $$PWD/connectionvisitor.cpp
|
||||
SOURCES += $$PWD/signallist.cpp
|
||||
SOURCES += $$PWD/signallistdialog.cpp
|
||||
SOURCES += $$PWD/signallistdelegate.cpp
|
||||
|
||||
328
src/plugins/qmldesigner/components/bindingeditor/signallist.cpp
Normal file
@@ -0,0 +1,328 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** 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 "signallist.h"
|
||||
|
||||
#include "signallistdelegate.h"
|
||||
|
||||
#include <qmldesignerplugin.h>
|
||||
#include <coreplugin/icore.h>
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
|
||||
#include <metainfo.h>
|
||||
|
||||
#include <variantproperty.h>
|
||||
#include <bindingproperty.h>
|
||||
#include <signalhandlerproperty.h>
|
||||
#include <qmldesignerconstants.h>
|
||||
#include <qmlitemnode.h>
|
||||
#include <nodeabstractproperty.h>
|
||||
|
||||
#include <QStandardItemModel>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QTableView>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
SignalListModel::SignalListModel(QObject *parent)
|
||||
: QStandardItemModel(0, 3, parent)
|
||||
{
|
||||
setHeaderData(TargetColumn, Qt::Horizontal, tr("Item ID"));
|
||||
setHeaderData(SignalColumn, Qt::Horizontal, tr("Signal"));
|
||||
setHeaderData(ButtonColumn, Qt::Horizontal, "");
|
||||
}
|
||||
|
||||
void SignalListModel::setConnected(int row, bool connected)
|
||||
{
|
||||
for (int col = 0; col < columnCount(); ++col) {
|
||||
QModelIndex idx = index(row, col);
|
||||
setData(idx, connected, ConnectedRole);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SignalListFilterModel::SignalListFilterModel(QObject *parent)
|
||||
: QSortFilterProxyModel(parent)
|
||||
{
|
||||
}
|
||||
|
||||
bool SignalListFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
|
||||
{
|
||||
QModelIndex targetIndex = sourceModel()->index(sourceRow, SignalListModel::TargetColumn, sourceParent);
|
||||
QModelIndex signalIndex = sourceModel()->index(sourceRow, SignalListModel::SignalColumn, sourceParent);
|
||||
|
||||
return (sourceModel()->data(targetIndex).toString().contains(filterRegExp())
|
||||
|| sourceModel()->data(signalIndex).toString().contains(filterRegExp()));
|
||||
}
|
||||
|
||||
|
||||
PropertyNameList SignalList::st_mouseSignals = { "clicked", "doubleClicked", "pressAndHold",
|
||||
"pressed", "released", "wheel" };
|
||||
|
||||
SignalList::SignalList(QObject *)
|
||||
: m_dialog(QPointer<SignalListDialog>())
|
||||
, m_model(new SignalListModel(this))
|
||||
, m_modelNode()
|
||||
{
|
||||
}
|
||||
|
||||
SignalList::~SignalList()
|
||||
{
|
||||
hideWidget();
|
||||
}
|
||||
|
||||
void SignalList::prepareDialog()
|
||||
{
|
||||
m_dialog = new SignalListDialog(Core::ICore::dialogParent());
|
||||
m_dialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||
m_dialog->initialize(m_model);
|
||||
m_dialog->setWindowTitle(tr("Signal List for ") + m_modelNode.validId());
|
||||
|
||||
auto *delegate = static_cast<SignalListDelegate *>(m_dialog->tableView()->itemDelegate());
|
||||
connect(delegate, &SignalListDelegate::connectClicked, this, &SignalList::connectClicked);
|
||||
}
|
||||
|
||||
void SignalList::showWidget()
|
||||
{
|
||||
prepareDialog();
|
||||
m_dialog->show();
|
||||
m_dialog->raise();
|
||||
}
|
||||
|
||||
void SignalList::hideWidget()
|
||||
{
|
||||
if (m_dialog)
|
||||
m_dialog->close();
|
||||
|
||||
m_dialog = nullptr;
|
||||
}
|
||||
|
||||
SignalList* SignalList::showWidget(const ModelNode &modelNode)
|
||||
{
|
||||
auto signalList = new SignalList();
|
||||
signalList->setModelNode(modelNode);
|
||||
signalList->prepareSignals();
|
||||
signalList->showWidget();
|
||||
|
||||
connect(signalList->m_dialog, &QDialog::destroyed,
|
||||
[signalList]() { signalList->deleteLater(); } );
|
||||
|
||||
return signalList;
|
||||
}
|
||||
|
||||
void SignalList::setModelNode(const ModelNode &modelNode)
|
||||
{
|
||||
if (modelNode.isValid())
|
||||
m_modelNode = modelNode;
|
||||
}
|
||||
|
||||
void SignalList::prepareSignals()
|
||||
{
|
||||
if (!m_modelNode.isValid())
|
||||
return;
|
||||
|
||||
AbstractView *view = m_modelNode.view();
|
||||
QList<QmlConnections> connections = getAssociatedConnections(view->allModelNodes());
|
||||
|
||||
for (ModelNode &node : view->allModelNodes()) {
|
||||
// Collect all items which contain at least one of the specified signals
|
||||
const PropertyNameList signalNames = node.metaInfo().signalNames();
|
||||
// Put the signals into a QSet to avoid duplicates
|
||||
auto signalNamesSet = QSet<PropertyName>(signalNames.begin(), signalNames.end());
|
||||
for (const PropertyName &signal : signalNamesSet) {
|
||||
if (st_mouseSignals.contains(signal))
|
||||
appendSignalToModel(connections, node, signal);
|
||||
}
|
||||
|
||||
// Gather valid properties and aliases from components
|
||||
for (const PropertyName &property : node.metaInfo().propertyNames()) {
|
||||
const TypeName propertyType = node.metaInfo().propertyTypeName(property);
|
||||
const NodeMetaInfo info = m_modelNode.model()->metaInfo(propertyType);
|
||||
// Collect all items which contain at least one of the specified signals
|
||||
const PropertyNameList signalNames = info.signalNames();
|
||||
// Put the signals into a QSet to avoid duplicates
|
||||
auto signalNamesSet = QSet<PropertyName>(signalNames.begin(), signalNames.end());
|
||||
for (const PropertyName &signal : signalNamesSet) {
|
||||
if (st_mouseSignals.contains(signal))
|
||||
appendSignalToModel(connections, node, signal, property);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SignalList::connectClicked(const QModelIndex &modelIndex)
|
||||
{
|
||||
auto proxyModel = static_cast<const SignalListFilterModel *>(modelIndex.model());
|
||||
QModelIndex mappedModelIndex = proxyModel->mapToSource(modelIndex);
|
||||
bool connected = mappedModelIndex.data(SignalListModel::ConnectedRole).toBool();
|
||||
|
||||
if (!connected)
|
||||
addConnection(mappedModelIndex);
|
||||
else
|
||||
removeConnection(mappedModelIndex);
|
||||
}
|
||||
|
||||
void SignalList::appendSignalToModel(const QList<QmlConnections> &connections,
|
||||
ModelNode &node,
|
||||
const PropertyName &signal,
|
||||
const PropertyName &property)
|
||||
{
|
||||
QStandardItem *idItem = new QStandardItem();
|
||||
QString id(node.validId());
|
||||
if (!property.isEmpty())
|
||||
id += "." + QString::fromLatin1(property);
|
||||
|
||||
idItem->setData(id, Qt::DisplayRole);
|
||||
|
||||
QStandardItem *signalItem = new QStandardItem();
|
||||
signalItem->setData(signal, Qt::DisplayRole);
|
||||
|
||||
QStandardItem *buttonItem = new QStandardItem();
|
||||
|
||||
idItem->setData(false, SignalListModel::ConnectedRole);
|
||||
signalItem->setData(false, SignalListModel::ConnectedRole);
|
||||
buttonItem->setData(false, SignalListModel::ConnectedRole);
|
||||
|
||||
for (const QmlConnections &connection : connections) {
|
||||
if (connection.target() == id) {
|
||||
for (const SignalHandlerProperty &property : connection.signalProperties()) {
|
||||
auto signalWithoutPrefix = SignalHandlerProperty::prefixRemoved(property.name());
|
||||
if (signalWithoutPrefix == signal) {
|
||||
buttonItem->setData(connection.modelNode().internalId(),
|
||||
SignalListModel::ConnectionsInternalIdRole);
|
||||
|
||||
idItem->setData(true, SignalListModel::ConnectedRole);
|
||||
signalItem->setData(true, SignalListModel::ConnectedRole);
|
||||
buttonItem->setData(true, SignalListModel::ConnectedRole);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
m_model->appendRow({idItem, signalItem, buttonItem});
|
||||
}
|
||||
|
||||
void SignalList::addConnection(const QModelIndex &modelIndex)
|
||||
{
|
||||
const QModelIndex targetModelIndex = modelIndex.siblingAtColumn(SignalListModel::TargetColumn);
|
||||
const QModelIndex signalModelIndex = modelIndex.siblingAtColumn(SignalListModel::SignalColumn);
|
||||
const QModelIndex buttonModelIndex = modelIndex.siblingAtColumn(SignalListModel::ButtonColumn);
|
||||
const PropertyName signalName = m_model->data(signalModelIndex,
|
||||
Qt::DisplayRole).toByteArray();
|
||||
|
||||
QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_CONNECTION_ADDED);
|
||||
|
||||
AbstractView *view = m_modelNode.view();
|
||||
const ModelNode rootModelNode = view->rootModelNode();
|
||||
|
||||
if (rootModelNode.isValid() && rootModelNode.metaInfo().isValid()) {
|
||||
NodeMetaInfo nodeMetaInfo = view->model()->metaInfo("QtQuick.Connections");
|
||||
if (nodeMetaInfo.isValid()) {
|
||||
view->executeInTransaction("ConnectionModel::addConnection", [=, &rootModelNode](){
|
||||
ModelNode newNode = view->createModelNode("QtQuick.Connections",
|
||||
nodeMetaInfo.majorVersion(),
|
||||
nodeMetaInfo.minorVersion());
|
||||
const QString source = m_modelNode.validId() + ".trigger()";
|
||||
|
||||
if (QmlItemNode::isValidQmlItemNode(m_modelNode))
|
||||
m_modelNode.nodeAbstractProperty("data").reparentHere(newNode);
|
||||
else
|
||||
rootModelNode.nodeAbstractProperty(rootModelNode.metaInfo().defaultPropertyName()).reparentHere(newNode);
|
||||
|
||||
const QString expression = m_model->data(targetModelIndex, Qt::DisplayRole).toString();
|
||||
newNode.bindingProperty("target").setExpression(expression);
|
||||
newNode.signalHandlerProperty(SignalHandlerProperty::prefixAdded(signalName)).setSource(source);
|
||||
|
||||
m_model->setConnected(modelIndex.row(), true);
|
||||
m_model->setData(buttonModelIndex, newNode.internalId(), SignalListModel::ConnectionsInternalIdRole);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SignalList::removeConnection(const QModelIndex &modelIndex)
|
||||
{
|
||||
const QModelIndex signalModelIndex = modelIndex.siblingAtColumn(SignalListModel::SignalColumn);
|
||||
const QModelIndex buttonModelIndex = modelIndex.siblingAtColumn(SignalListModel::ButtonColumn);
|
||||
const PropertyName signalName = m_model->data(signalModelIndex,
|
||||
Qt::DisplayRole).toByteArray();
|
||||
const int connectionInternalId = m_model->data(buttonModelIndex,
|
||||
SignalListModel::ConnectionsInternalIdRole).toInt();
|
||||
|
||||
AbstractView *view = m_modelNode.view();
|
||||
const ModelNode connectionModelNode = view->modelNodeForInternalId(connectionInternalId);
|
||||
SignalHandlerProperty targetSignal;
|
||||
|
||||
if (connectionModelNode.isValid())
|
||||
targetSignal = connectionModelNode.signalHandlerProperty(signalName);
|
||||
|
||||
ModelNode node = targetSignal.parentModelNode();
|
||||
if (node.isValid()) {
|
||||
view->executeInTransaction("ConnectionModel::removeConnection", [=, &node](){
|
||||
QList<SignalHandlerProperty> allSignals = node.signalProperties();
|
||||
if (allSignals.size() > 1) {
|
||||
const auto targetSignalWithPrefix = SignalHandlerProperty::prefixAdded(targetSignal.name());
|
||||
for (const SignalHandlerProperty &signal : allSignals)
|
||||
if (signal.name() == targetSignalWithPrefix)
|
||||
node.removeProperty(targetSignalWithPrefix);
|
||||
} else {
|
||||
node.destroy();
|
||||
}
|
||||
m_model->setConnected(modelIndex.row(), false);
|
||||
m_model->setData(buttonModelIndex, QVariant(), SignalListModel::ConnectionsInternalIdRole);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
QList<QmlConnections> SignalList::getAssociatedConnections(const QList<ModelNode> &nodes)
|
||||
{
|
||||
return Utils::transform<QList<QmlConnections>>(Utils::filtered(nodes, [this](const ModelNode &node) {
|
||||
const QmlConnections connection(node);
|
||||
if (!connection.isValid())
|
||||
return false;
|
||||
|
||||
for (const SignalHandlerProperty &property : connection.signalProperties()) {
|
||||
auto signalWithoutPrefix = SignalHandlerProperty::prefixRemoved(property.name());
|
||||
const QStringList sourceComponents = property.source().split(".");
|
||||
QString sourceId;
|
||||
QString sourceProperty;
|
||||
if (sourceComponents.size() > 1) {
|
||||
sourceId = sourceComponents[0];
|
||||
sourceProperty = sourceComponents[1];
|
||||
}
|
||||
|
||||
if (st_mouseSignals.contains(signalWithoutPrefix)
|
||||
&& sourceId == m_modelNode.validId()
|
||||
&& sourceProperty == "trigger()")
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}), [](const ModelNode &node) {
|
||||
return QmlConnections(node);
|
||||
});
|
||||
}
|
||||
|
||||
} // QmlDesigner namespace
|
||||
108
src/plugins/qmldesigner/components/bindingeditor/signallist.h
Normal file
@@ -0,0 +1,108 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** 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 <bindingeditor/signallistdialog.h>
|
||||
#include <qmldesignercorelib_global.h>
|
||||
#include <modelnode.h>
|
||||
#include <qmlconnections.h>
|
||||
|
||||
#include <QtQml>
|
||||
#include <QObject>
|
||||
#include <QPointer>
|
||||
#include <QStandardItemModel>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
class SignalListModel : public QStandardItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum ColumnRoles : unsigned int {
|
||||
TargetColumn = 0,
|
||||
SignalColumn = 1,
|
||||
ButtonColumn = 2
|
||||
};
|
||||
enum UserRoles : unsigned int {
|
||||
ConnectionsInternalIdRole = Qt::UserRole + 1,
|
||||
ConnectedRole
|
||||
};
|
||||
|
||||
SignalListModel(QObject *parent = nullptr);
|
||||
|
||||
void setConnected(int row, bool connected);
|
||||
};
|
||||
|
||||
class SignalListFilterModel : public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SignalListFilterModel(QObject *parent = nullptr);
|
||||
|
||||
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
|
||||
};
|
||||
|
||||
class SignalList : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit SignalList(QObject *parent = nullptr);
|
||||
~SignalList();
|
||||
|
||||
static SignalList* showWidget(const ModelNode &modelNode);
|
||||
|
||||
void setModelNode(const ModelNode &modelNode);
|
||||
void connectClicked(const QModelIndex &modelIndex);
|
||||
|
||||
private:
|
||||
void prepareDialog();
|
||||
void showWidget();
|
||||
void hideWidget();
|
||||
|
||||
void prepareSignals();
|
||||
|
||||
void appendSignalToModel(const QList<QmlConnections> &connections,
|
||||
ModelNode &node,
|
||||
const PropertyName &signal,
|
||||
const PropertyName &property = "");
|
||||
|
||||
void addConnection(const QModelIndex &modelIndex);
|
||||
void removeConnection(const QModelIndex &modelIndex);
|
||||
|
||||
QList<QmlConnections> getAssociatedConnections(const QList<ModelNode> &nodes);
|
||||
|
||||
private:
|
||||
static PropertyNameList st_mouseSignals;
|
||||
|
||||
QPointer<SignalListDialog> m_dialog;
|
||||
SignalListModel *m_model;
|
||||
ModelNode m_modelNode;
|
||||
};
|
||||
|
||||
} // QmlDesigner namespace
|
||||
@@ -0,0 +1,95 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** 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 "signallistdelegate.h"
|
||||
|
||||
#include "signallist.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QMouseEvent>
|
||||
#include <QPainter>
|
||||
#include <QStyleOptionButton>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
SignalListDelegate::SignalListDelegate(QObject *parent)
|
||||
: QStyledItemDelegate(parent)
|
||||
{}
|
||||
|
||||
QWidget *SignalListDelegate::createEditor(QWidget *parent,
|
||||
const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const
|
||||
{
|
||||
if (index.column() == SignalListModel::ButtonColumn)
|
||||
return nullptr;
|
||||
|
||||
return QStyledItemDelegate::createEditor(parent, option, index);
|
||||
}
|
||||
|
||||
QRect connectButtonRect(const QStyleOptionViewItem &option)
|
||||
{
|
||||
return option.rect.adjusted(3, 3, -3, -3);
|
||||
}
|
||||
|
||||
void SignalListDelegate::paint(QPainter *painter,
|
||||
const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const
|
||||
{
|
||||
const bool connected = index.data(SignalListModel::ConnectedRole).toBool();
|
||||
if (connected) {
|
||||
QStyleOptionViewItem opt(option);
|
||||
opt.state = QStyle::State_Selected;
|
||||
QStyledItemDelegate::paint(painter, opt, index);
|
||||
if (index.column() != SignalListModel::ButtonColumn)
|
||||
return;
|
||||
}
|
||||
if (index.column() == SignalListModel::ButtonColumn) {
|
||||
QStyleOptionButton button;
|
||||
button.rect = connectButtonRect(option);
|
||||
button.text = connected ? tr("Release") : tr("Connect");
|
||||
button.state = QStyle::State_Enabled;
|
||||
QApplication::style()->drawControl(QStyle::CE_PushButton, &button, painter);
|
||||
return;
|
||||
}
|
||||
QStyledItemDelegate::paint(painter, option, index);
|
||||
}
|
||||
|
||||
bool SignalListDelegate::editorEvent(QEvent *event,
|
||||
QAbstractItemModel *model,
|
||||
const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index)
|
||||
{
|
||||
Q_UNUSED(model)
|
||||
|
||||
if (index.column() == SignalListModel::ButtonColumn
|
||||
&& event->type() == QEvent::MouseButtonRelease) {
|
||||
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
|
||||
if (connectButtonRect(option).contains(mouseEvent->pos()))
|
||||
emit connectClicked(index);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // QmlDesigner namespace
|
||||
@@ -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 <QStyledItemDelegate>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
class SignalListDelegate : public QStyledItemDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
signals:
|
||||
void connectClicked(const QModelIndex &modelIndex) const;
|
||||
|
||||
public:
|
||||
SignalListDelegate(QObject *parent = nullptr);
|
||||
|
||||
QWidget *createEditor(QWidget *parent,
|
||||
const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const override;
|
||||
void paint(QPainter *painter,
|
||||
const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const override;
|
||||
bool editorEvent(QEvent *event,
|
||||
QAbstractItemModel *model,
|
||||
const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) override;
|
||||
};
|
||||
|
||||
} // QmlDesigner namespace
|
||||
@@ -0,0 +1,132 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** 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 "signallistdialog.h"
|
||||
|
||||
#include "signallist.h"
|
||||
#include "signallistdelegate.h"
|
||||
|
||||
#include <qmldesignerplugin.h>
|
||||
|
||||
#include <theme.h>
|
||||
#include <utils/fancylineedit.h>
|
||||
#include <utils/stylehelper.h>
|
||||
#include <utils/utilsicons.h>
|
||||
|
||||
#include <QStandardItemModel>
|
||||
#include <QPainter>
|
||||
#include <QTableView>
|
||||
#include <QHeaderView>
|
||||
#include <QVBoxLayout>
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
QWidget *createFilterWidget(Utils::FancyLineEdit *lineEdit)
|
||||
{
|
||||
const QString unicode = Theme::getIconUnicode(Theme::Icon::search);
|
||||
const QString fontName = "qtds_propertyIconFont.ttf";
|
||||
QIcon icon = Utils::StyleHelper::getIconFromIconFont(fontName, unicode, 28, 28);
|
||||
auto *label = new QLabel;
|
||||
label->setPixmap(icon.pixmap(QSize(24, 24)));
|
||||
label->setAlignment(Qt::AlignCenter);
|
||||
lineEdit->setPlaceholderText(QObject::tr("<Filter>", "Library search input hint text"));
|
||||
lineEdit->setDragEnabled(false);
|
||||
lineEdit->setMinimumWidth(75);
|
||||
lineEdit->setTextMargins(0, 0, 20, 0);
|
||||
lineEdit->setFiltering(true);
|
||||
auto *box = new QHBoxLayout;
|
||||
box->addWidget(label);
|
||||
box->addWidget(lineEdit);
|
||||
auto *widget = new QWidget;
|
||||
widget->setLayout(box);
|
||||
return widget;
|
||||
}
|
||||
|
||||
void modifyPalette(QTableView *view, const QColor &selectionColor)
|
||||
{
|
||||
QPalette p = view->palette();
|
||||
p.setColor(QPalette::AlternateBase, p.color(QPalette::Base).lighter(120));
|
||||
p.setColor(QPalette::Highlight, selectionColor);
|
||||
view->setPalette(p);
|
||||
view->setAlternatingRowColors(true);
|
||||
}
|
||||
|
||||
|
||||
SignalListDialog::SignalListDialog(QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, m_table(new QTableView())
|
||||
, m_searchLine(new Utils::FancyLineEdit())
|
||||
{
|
||||
auto *signalListDelegate = new SignalListDelegate(m_table);
|
||||
m_table->setItemDelegate(signalListDelegate);
|
||||
m_table->setFocusPolicy(Qt::NoFocus);
|
||||
m_table->setSelectionMode(QAbstractItemView::NoSelection);
|
||||
m_table->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||
m_table->verticalHeader()->hide();
|
||||
|
||||
modifyPalette(m_table, QColor("#d87b00"));
|
||||
|
||||
auto *layout = new QVBoxLayout;
|
||||
layout->addWidget(createFilterWidget(m_searchLine));
|
||||
layout->addWidget(m_table);
|
||||
setLayout(layout);
|
||||
|
||||
setWindowFlag(Qt::Tool, true);
|
||||
setModal(true);
|
||||
resize(600, 480);
|
||||
}
|
||||
|
||||
SignalListDialog::~SignalListDialog()
|
||||
{
|
||||
}
|
||||
|
||||
void SignalListDialog::initialize(QStandardItemModel *model)
|
||||
{
|
||||
m_searchLine->clear();
|
||||
|
||||
auto *proxyModel = new SignalListFilterModel(this);
|
||||
proxyModel->setSourceModel(model);
|
||||
m_table->setModel(proxyModel);
|
||||
|
||||
QHeaderView *header = m_table->horizontalHeader();
|
||||
header->setSectionResizeMode(SignalListModel::TargetColumn, QHeaderView::Stretch);
|
||||
header->setSectionResizeMode(SignalListModel::SignalColumn, QHeaderView::Stretch);
|
||||
header->resizeSection(SignalListModel::ButtonColumn, 120);
|
||||
header->setStretchLastSection(false);
|
||||
|
||||
auto eventFilterFun = [this](const QString &str) {
|
||||
if (auto *fm = qobject_cast<SignalListFilterModel *>(m_table->model()))
|
||||
fm->setFilterFixedString(str);
|
||||
};
|
||||
connect(m_searchLine, &Utils::FancyLineEdit::filterChanged, eventFilterFun);
|
||||
}
|
||||
|
||||
QTableView *SignalListDialog::tableView() const
|
||||
{
|
||||
return m_table;
|
||||
}
|
||||
|
||||
} // QmlDesigner namespace
|
||||
@@ -0,0 +1,58 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** 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>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QStandardItemModel;
|
||||
class QTableView;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace Utils {
|
||||
class FancyLineEdit;
|
||||
}
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
class SignalListDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SignalListDialog(QWidget *parent = nullptr);
|
||||
~SignalListDialog() override;
|
||||
|
||||
void initialize(QStandardItemModel *model);
|
||||
|
||||
QTableView *tableView() const;
|
||||
|
||||
private:
|
||||
QTableView *m_table;
|
||||
Utils::FancyLineEdit *m_searchLine;
|
||||
};
|
||||
|
||||
} // QmlDesigner namespace
|
||||
@@ -53,6 +53,11 @@ public:
|
||||
LowestPriority = ComponentCoreConstants::priorityLast
|
||||
};
|
||||
|
||||
enum class TargetView {
|
||||
Undefined,
|
||||
ConnectionEditor
|
||||
};
|
||||
|
||||
virtual ~ActionInterface() = default;
|
||||
|
||||
virtual QAction *action() const = 0;
|
||||
@@ -61,6 +66,7 @@ public:
|
||||
virtual int priority() const = 0;
|
||||
virtual Type type() const = 0;
|
||||
virtual void currentContextChanged(const SelectionContext &selectionState) = 0;
|
||||
virtual TargetView targetView() const { return TargetView::Undefined; }
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -89,6 +89,8 @@ const char fitRootToScreenCommandId[] = "FitRootToScreen";
|
||||
const char fitSelectionToScreenCommandId[] = "FitSelectionToScreen";
|
||||
const char editAnnotationCommandId[] = "EditAnnotation";
|
||||
|
||||
const char openSignalDialogCommandId[] = "OpenSignalDialog";
|
||||
|
||||
const char selectionCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Selection");
|
||||
const char flowConnectionCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Connect");
|
||||
const char selectEffectDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Select Effect");
|
||||
@@ -128,6 +130,8 @@ const char addSignalHandlerDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContext
|
||||
const char moveToComponentDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Move Component into Separate File");
|
||||
const char editAnnotationDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Edit Annotation");
|
||||
|
||||
const char openSignalDialogDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Open Signal Dialog");
|
||||
|
||||
const char setIdDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Set Id");
|
||||
|
||||
const char resetZDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Reset z Property");
|
||||
|
||||
@@ -564,6 +564,7 @@ const char yProperty[] = "y";
|
||||
const char zProperty[] = "z";
|
||||
const char widthProperty[] = "width";
|
||||
const char heightProperty[] = "height";
|
||||
const char triggerSlot[] = "trigger";
|
||||
|
||||
using namespace SelectionContextFunctors;
|
||||
|
||||
@@ -644,6 +645,14 @@ bool selectionNotEmptyAndHasXorYProperty(const SelectionContext &context)
|
||||
&& selectionHasProperty1or2(context, xProperty, yProperty);
|
||||
}
|
||||
|
||||
bool singleSelectionAndHasSlotTrigger(const SelectionContext &context)
|
||||
{
|
||||
if (!singleSelection(context))
|
||||
return false;
|
||||
|
||||
return selectionHasSlot(context, triggerSlot);
|
||||
}
|
||||
|
||||
bool singleSelectionAndInQtQuickLayout(const SelectionContext &context)
|
||||
{
|
||||
if (!singleSelection(context))
|
||||
@@ -1384,6 +1393,16 @@ void DesignerActionManager::createDefaultDesignerActions()
|
||||
addDesignerAction(new ChangeStyleAction());
|
||||
|
||||
addDesignerAction(new EditListModelAction);
|
||||
|
||||
addDesignerAction(new ModelNodeContextMenuAction(
|
||||
openSignalDialogCommandId,
|
||||
openSignalDialogDisplayName,
|
||||
{},
|
||||
rootCategory,
|
||||
QKeySequence(),
|
||||
66,
|
||||
&openSignalDialog,
|
||||
&singleSelectionAndHasSlotTrigger));
|
||||
}
|
||||
|
||||
void DesignerActionManager::createDefaultAddResourceHandler()
|
||||
@@ -1459,6 +1478,16 @@ void DesignerActionManager::addCreatorCommand(Core::Command *command, const QByt
|
||||
addDesignerAction(new CommandAction(command, category, priority, overrideIcon));
|
||||
}
|
||||
|
||||
QList<QSharedPointer<ActionInterface> > DesignerActionManager::actionsForTargetView(const ActionInterface::TargetView &target)
|
||||
{
|
||||
QList<QSharedPointer<ActionInterface> > out;
|
||||
for (auto interface : m_designerActions)
|
||||
if (interface->targetView() == target)
|
||||
out << interface;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
QList<ActionInterface* > DesignerActionManager::designerActions() const
|
||||
{
|
||||
return Utils::transform(m_designerActions, [](const QSharedPointer<ActionInterface> &pointer) {
|
||||
|
||||
@@ -106,6 +106,9 @@ public:
|
||||
void addDesignerAction(ActionInterface *newAction);
|
||||
void addCreatorCommand(Core::Command *command, const QByteArray &category, int priority,
|
||||
const QIcon &overrideIcon = QIcon());
|
||||
|
||||
QList<QSharedPointer<ActionInterface>> actionsForTargetView(const ActionInterface::TargetView &target);
|
||||
|
||||
QList<ActionInterface* > designerActions() const;
|
||||
|
||||
void createDefaultDesignerActions();
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "abstractactiongroup.h"
|
||||
#include "qmlitemnode.h"
|
||||
#include <qmldesignerplugin.h>
|
||||
#include <nodemetainfo.h>
|
||||
|
||||
#include <coreplugin/actionmanager/command.h>
|
||||
|
||||
@@ -80,12 +81,24 @@ inline bool singleSelectionNotRoot(const SelectionContext &selectionState)
|
||||
|
||||
inline bool selectionHasProperty(const SelectionContext &selectionState, const char *property)
|
||||
{
|
||||
foreach (const ModelNode &modelNode, selectionState.selectedModelNodes())
|
||||
for (const ModelNode &modelNode : selectionState.selectedModelNodes())
|
||||
if (modelNode.hasProperty(PropertyName(property)))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool selectionHasSlot(const SelectionContext &selectionState, const char *property)
|
||||
{
|
||||
for (const ModelNode &modelNode : selectionState.selectedModelNodes()) {
|
||||
for (const PropertyName &slotName : modelNode.metaInfo().slotNames()) {
|
||||
if (slotName == property)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool singleSelectedItem(const SelectionContext &selectionState)
|
||||
{
|
||||
QmlItemNode itemNode(selectionState.currentSingleSelectedNode());
|
||||
@@ -94,7 +107,6 @@ inline bool singleSelectedItem(const SelectionContext &selectionState)
|
||||
|
||||
bool selectionHasSameParent(const SelectionContext &selectionState);
|
||||
bool selectionIsComponent(const SelectionContext &selectionState);
|
||||
bool selectionIsComponent(const SelectionContext &selectionState);
|
||||
bool singleSelectionItemIsAnchored(const SelectionContext &selectionState);
|
||||
bool singleSelectionItemIsNotAnchored(const SelectionContext &selectionState);
|
||||
|
||||
|
||||
@@ -87,6 +87,8 @@
|
||||
#include <functional>
|
||||
#include <cmath>
|
||||
|
||||
#include <bindingeditor/signallist.h>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
const PropertyName auxDataString("anchors_");
|
||||
@@ -1548,6 +1550,14 @@ QVariant previewImageDataForImageNode(const ModelNode &modelNode)
|
||||
return {};
|
||||
}
|
||||
|
||||
void openSignalDialog(const SelectionContext &selectionContext)
|
||||
{
|
||||
if (!selectionContext.view() || !selectionContext.hasSingleSelectedModelNode())
|
||||
return;
|
||||
|
||||
SignalList::showWidget(selectionContext.currentSingleSelectedNode());
|
||||
}
|
||||
|
||||
} // namespace ModelNodeOperations
|
||||
|
||||
} //QmlDesigner
|
||||
|
||||
@@ -88,6 +88,8 @@ void mergeWithTemplate(const SelectionContext &selectionContext);
|
||||
void removeGroup(const SelectionContext &selectionContext);
|
||||
void editAnnotation(const SelectionContext &selectionContext);
|
||||
|
||||
void openSignalDialog(const SelectionContext &selectionContext);
|
||||
|
||||
// ModelNodePreviewImageOperations
|
||||
QVariant previewImageDataForGenericNode(const ModelNode &modelNode);
|
||||
QVariant previewImageDataForImageNode(const ModelNode &modelNode);
|
||||
|
||||
@@ -49,9 +49,9 @@ namespace {
|
||||
QStringList propertyNameListToStringList(const QmlDesigner::PropertyNameList &propertyNameList)
|
||||
{
|
||||
QStringList stringList;
|
||||
for (const QmlDesigner::PropertyName &propertyName : propertyNameList) {
|
||||
for (const QmlDesigner::PropertyName &propertyName : propertyNameList)
|
||||
stringList << QString::fromUtf8(propertyName);
|
||||
}
|
||||
|
||||
stringList.removeDuplicates();
|
||||
return stringList;
|
||||
}
|
||||
|
||||
@@ -172,6 +172,19 @@ void ConnectionViewWidget::contextMenuEvent(QContextMenuEvent *event)
|
||||
m_connectionEditor->updateWindowName();
|
||||
});
|
||||
|
||||
QMap<QString, QVariant> data;
|
||||
data["ModelNode"] = index.siblingAtColumn(ConnectionModel::TargetModelNodeRow).data();
|
||||
data["Signal"] = index.siblingAtColumn(ConnectionModel::TargetPropertyNameRow).data();
|
||||
DesignerActionManager &designerActionManager = QmlDesignerPlugin::instance()->designerActionManager();
|
||||
const auto actions = designerActionManager.actionsForTargetView(
|
||||
ActionInterface::TargetView::ConnectionEditor);
|
||||
|
||||
for (auto actionInterface : actions) {
|
||||
auto *action = actionInterface->action();
|
||||
action->setData(data);
|
||||
menu.addAction(action);
|
||||
}
|
||||
|
||||
menu.exec(event->globalPos());
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -888,6 +888,7 @@ public:
|
||||
, labelFlags(Qt::AlignHCenter | Qt::AlignVCenter | Qt::TextDontClip)
|
||||
, labelFlipSide(false)
|
||||
, hitTesting(hitTest)
|
||||
, isSelected(false)
|
||||
, events()
|
||||
{
|
||||
// width
|
||||
@@ -1416,37 +1417,7 @@ void FormEditorTransitionItem::updateGeometry()
|
||||
overallBoundingRect = overallBoundingRect.united(connection.fromRect);
|
||||
overallBoundingRect = overallBoundingRect.united(connection.toRect);
|
||||
overallBoundingRect = overallBoundingRect.united(pathBoundingRect);
|
||||
|
||||
// Calculate bounding rect for label
|
||||
// TODO The calculation should be put into a separate function to avoid code duplication as this
|
||||
// can also be found in drawLabel()
|
||||
if (!connection.config.label.isEmpty()) {
|
||||
const qreal percent = connection.config.labelPosition / 100.0;
|
||||
const QPointF pos = connection.path.pointAtPercent(percent);
|
||||
const qreal angle = connection.path.angleAtPercent(percent);
|
||||
|
||||
QLineF tmp(pos, QPointF(10, 10));
|
||||
tmp.setLength(connection.config.labelOffset);
|
||||
tmp.setAngle(angle + (connection.config.labelFlipSide ? 270 : 90));
|
||||
|
||||
QRectF textRect(0, 0, 100, 50);
|
||||
textRect.moveCenter(tmp.p2());
|
||||
|
||||
QRectF labelRect;
|
||||
|
||||
QTransform transform;
|
||||
transform.translate(textRect.center().x(), textRect.center().y());
|
||||
transform.rotate(-normalizeAngle(angle));
|
||||
transform.translate(-textRect.center().x(), -textRect.center().y());
|
||||
|
||||
localPainter.setTransform(transform);
|
||||
localPainter.drawText(textRect,
|
||||
connection.config.labelFlags,
|
||||
connection.config.label,
|
||||
&labelRect);
|
||||
QRectF labelBoundingBox = transform.mapRect(labelRect);
|
||||
overallBoundingRect = overallBoundingRect.united(labelBoundingBox);
|
||||
}
|
||||
drawLabels(&localPainter, connection);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1461,7 +1432,7 @@ QPointF FormEditorTransitionItem::instancePosition() const
|
||||
return qmlItemNode().flowPosition();
|
||||
}
|
||||
|
||||
static void drawLabel(QPainter *painter, const Connection &connection)
|
||||
void FormEditorTransitionItem::drawLabels(QPainter *painter, const Connection &connection)
|
||||
{
|
||||
// draw label with event ids
|
||||
if (connection.config.isSelected && !connection.config.events.isEmpty())
|
||||
@@ -1469,27 +1440,23 @@ static void drawLabel(QPainter *painter, const Connection &connection)
|
||||
qreal offset = connection.config.labelOffset;
|
||||
QStringList events = connection.config.events.split(',');
|
||||
int fontSize = connection.config.fontSize;
|
||||
QString output = events[0].trimmed();
|
||||
qreal minWidth = offset * 12;
|
||||
int letterWidth = fontSize * 0.6; // assumption on max letter length
|
||||
if (minWidth < output.size() * letterWidth) minWidth = output.size() * letterWidth;
|
||||
QString outputText;
|
||||
qreal minWidth = offset * 12.0;
|
||||
qreal letterWidth = fontSize * 0.6; // assumption on max letter width
|
||||
int eventCount = events.size();
|
||||
for (int i = 1; i < eventCount; ++i)
|
||||
{
|
||||
output.append('\n');
|
||||
QString id = events[i].trimmed();
|
||||
output.append(id);
|
||||
if (minWidth < id.size() * letterWidth) minWidth = id.size() * letterWidth;
|
||||
}
|
||||
std::for_each(events.begin(), events.end(), [&](auto id) {
|
||||
outputText.append(id.trimmed());
|
||||
outputText.append('\n');
|
||||
if (minWidth < id.size() * letterWidth) minWidth = id.size() * letterWidth;
|
||||
});
|
||||
const QPointF pos = connection.path.pointAtPercent(0.0);
|
||||
painter->save();
|
||||
painter->setBrush(QColor(70, 70, 70, 200));
|
||||
painter->setPen(Qt::lightGray);
|
||||
|
||||
painter->drawRoundedRect(pos.x(), pos.y() + offset, minWidth, 1.5 * fontSize * eventCount + offset * 4, offset / 2, offset / 2);
|
||||
painter->drawText(pos.x(), pos.y() + 2 * offset, minWidth, offset * 2, Qt::AlignHCenter, QObject::tr("Connected Events"));
|
||||
painter->drawLine(pos.x() + offset, pos.y() + 4 * offset, pos.x() + minWidth - offset, pos.y() + offset * 4);
|
||||
painter->drawText(pos.x() + offset, pos.y() + 4 * offset, minWidth - offset, 1.5 * fontSize * eventCount, Qt::AlignLeft, output);
|
||||
painter->drawRoundedRect(pos.x(), pos.y() + offset, minWidth, 1.5 * fontSize * eventCount + offset * 4.0, offset / 2.0, offset / 2.0);
|
||||
painter->drawText(pos.x(), pos.y() + 2.0 * offset, minWidth, offset * 2.0, Qt::AlignHCenter, QObject::tr("Connected Events"));
|
||||
painter->drawLine(pos.x() + offset, pos.y() + 4.0 * offset, pos.x() + minWidth - offset, pos.y() + offset * 4.0);
|
||||
painter->drawText(pos.x() + offset, pos.y() + 4.0 * offset, minWidth - offset, 1.5 * fontSize * eventCount, Qt::AlignLeft, outputText);
|
||||
painter->restore();
|
||||
}
|
||||
if (connection.config.label.isEmpty())
|
||||
@@ -1534,7 +1501,7 @@ static void drawArrow(QPainter *painter,
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
static void paintConnection(QPainter *painter, const Connection &connection)
|
||||
void FormEditorTransitionItem::paintConnection(QPainter *painter, const Connection &connection)
|
||||
{
|
||||
const int arrowLength = 4 * connection.config.adjustedWidth;
|
||||
const int arrowWidth = 8 * connection.config.adjustedWidth;
|
||||
@@ -1586,8 +1553,8 @@ static void paintConnection(QPainter *painter, const Connection &connection)
|
||||
painter->drawEllipse(connection.start, arrowLength / 3, arrowLength / 3);
|
||||
}
|
||||
|
||||
// Draw label
|
||||
drawLabel(painter, connection);
|
||||
// Draw labels
|
||||
drawLabels(painter, connection);
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ namespace QmlDesigner {
|
||||
class FormEditorScene;
|
||||
class FormEditorView;
|
||||
class AbstractFormEditorTool;
|
||||
class Connection;
|
||||
|
||||
namespace Internal {
|
||||
class GraphicItemResizer;
|
||||
@@ -197,11 +198,12 @@ public:
|
||||
QPointF instancePosition() const override;
|
||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;
|
||||
bool flowHitTest(const QPointF &point) const override;
|
||||
|
||||
protected:
|
||||
FormEditorTransitionItem(const QmlItemNode &qmlItemNode, FormEditorScene *scene)
|
||||
: FormEditorItem(qmlItemNode, scene)
|
||||
{}
|
||||
void paintConnection(QPainter *painter, const Connection &connection);
|
||||
void drawLabels(QPainter *painter, const Connection &connection);
|
||||
private:
|
||||
mutable bool m_hitTest = false;
|
||||
};
|
||||
|
||||
@@ -133,8 +133,6 @@ static QRect drawText(QPainter *painter,
|
||||
int iconOffset)
|
||||
{
|
||||
QString displayString = modelIndex.data(Qt::DisplayRole).toString();
|
||||
QPoint displayStringOffset;
|
||||
int width = 0;
|
||||
|
||||
// Check text length does not exceed available space
|
||||
const int extraSpace = 12 + iconOffset;
|
||||
@@ -142,10 +140,8 @@ static QRect drawText(QPainter *painter,
|
||||
displayString = styleOption.fontMetrics.elidedText(displayString,
|
||||
Qt::ElideMiddle,
|
||||
styleOption.rect.width() - extraSpace);
|
||||
displayStringOffset = QPoint(5 + iconOffset, -5 - delegateMargin);
|
||||
|
||||
width = styleOption.fontMetrics.horizontalAdvance(displayString);
|
||||
|
||||
const QPoint displayStringOffset = QPoint(5 + iconOffset, -5 - delegateMargin);
|
||||
const int width = styleOption.fontMetrics.horizontalAdvance(displayString);
|
||||
const QPoint textPosition = styleOption.rect.bottomLeft() + displayStringOffset;
|
||||
painter->drawText(textPosition, displayString);
|
||||
|
||||
|
||||
@@ -69,6 +69,7 @@ SOURCES += $$PWD/model/abstractview.cpp \
|
||||
$$PWD/model/qmlmodelnodefacade.cpp \
|
||||
$$PWD/model/qmlobjectnode.cpp \
|
||||
$$PWD/model/qmlanchors.cpp \
|
||||
$$PWD/model/qmlconnections.cpp \
|
||||
$$PWD/rewritertransaction.cpp \
|
||||
$$PWD/model/rewriteaction.cpp \
|
||||
$$PWD/model/modelnodepositionstorage.cpp \
|
||||
@@ -151,6 +152,7 @@ HEADERS += $$PWD/include/qmldesignercorelib_global.h \
|
||||
$$PWD/include/forwardview.h \
|
||||
$$PWD/include/qmlobjectnode.h \
|
||||
$$PWD/include/qmlanchors.h \
|
||||
$$PWD/include/qmlconnections.h \
|
||||
$$PWD/rewritertransaction.h \
|
||||
$$PWD/model/rewriteaction.h \
|
||||
$$PWD/include/modelnodepositionstorage.h \
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** 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 <qmldesignercorelib_global.h>
|
||||
#include "qmlmodelnodefacade.h"
|
||||
|
||||
#include <signalhandlerproperty.h>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
class QMLDESIGNERCORE_EXPORT QmlConnections : public QmlModelNodeFacade
|
||||
{
|
||||
friend class StatesEditorView;
|
||||
|
||||
public:
|
||||
QmlConnections();
|
||||
QmlConnections(const ModelNode &modelNode);
|
||||
|
||||
bool isValid() const override;
|
||||
static bool isValidQmlConnections(const ModelNode &modelNode);
|
||||
void destroy();
|
||||
|
||||
QString target() const;
|
||||
void setTarget(const QString &target);
|
||||
|
||||
ModelNode getTargetNode() const;
|
||||
|
||||
QList<SignalHandlerProperty> signalProperties() const;
|
||||
|
||||
static ModelNode createQmlConnections(AbstractView *view);
|
||||
};
|
||||
|
||||
} //QmlDesigner
|
||||
@@ -43,6 +43,9 @@ public:
|
||||
SignalHandlerProperty();
|
||||
SignalHandlerProperty(const SignalHandlerProperty &property, AbstractView *view);
|
||||
|
||||
static PropertyName prefixAdded(const PropertyName &propertyName);
|
||||
static PropertyName prefixRemoved(const PropertyName &propertyName);
|
||||
|
||||
protected:
|
||||
SignalHandlerProperty(const PropertyName &propertyName, const Internal::InternalNodePointer &internalNode, Model* model, AbstractView *view);
|
||||
};
|
||||
|
||||
@@ -82,7 +82,7 @@ using PropertyInfo = QPair<PropertyName, TypeName>;
|
||||
|
||||
QVector<PropertyInfo> getObjectTypes(const ObjectValue *ov, const ContextPtr &context, bool local = false, int rec = 0);
|
||||
|
||||
static TypeName resolveTypeName(const ASTPropertyReference *ref, const ContextPtr &context, QVector<PropertyInfo> &dotProperties)
|
||||
static TypeName resolveTypeName(const ASTPropertyReference *ref, const ContextPtr &context, QVector<PropertyInfo> &dotProperties)
|
||||
{
|
||||
TypeName type = "unknown";
|
||||
|
||||
@@ -295,7 +295,7 @@ public:
|
||||
const TypeName type = resolveTypeName(ref, m_context, dotProperties);
|
||||
m_properties.append({propertyName, type});
|
||||
if (!dotProperties.isEmpty()) {
|
||||
foreach (const PropertyInfo &propertyInfo, dotProperties) {
|
||||
for (const PropertyInfo &propertyInfo : qAsConst(dotProperties)) {
|
||||
PropertyName dotName = propertyInfo.first;
|
||||
TypeName type = propertyInfo.second;
|
||||
dotName = propertyName + '.' + dotName;
|
||||
@@ -303,7 +303,6 @@ public:
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
if (const CppComponentValue * cppComponentValue = value_cast<CppComponentValue>(value)) {
|
||||
TypeName qualifiedTypeName = qualifiedTypeNameForContext(cppComponentValue,
|
||||
m_context->viewerContext(), *m_context->snapshot().importDependencies()).toUtf8();
|
||||
@@ -311,13 +310,13 @@ public:
|
||||
} else {
|
||||
TypeId typeId;
|
||||
TypeName typeName = typeId(value).toUtf8();
|
||||
if (typeName == "number") {
|
||||
if (value->asIntValue()) {
|
||||
typeName = "int";
|
||||
} else {
|
||||
typeName = "real";
|
||||
}
|
||||
}
|
||||
|
||||
if (typeName == "Function")
|
||||
return processSlot(name, value);
|
||||
|
||||
if (typeName == "number")
|
||||
typeName = value->asIntValue() ? "int" : "real";
|
||||
|
||||
m_properties.append({propertyName, typeName});
|
||||
}
|
||||
}
|
||||
@@ -488,7 +487,7 @@ PropertyNameList getSignals(const ObjectValue *objectValue, const ContextPtr &co
|
||||
QList<const ObjectValue *> objects = prototypeIterator.all();
|
||||
|
||||
if (!local) {
|
||||
foreach (const ObjectValue *prototype, objects)
|
||||
for (const ObjectValue *prototype : objects)
|
||||
signalList.append(getSignals(prototype, context, true));
|
||||
}
|
||||
|
||||
@@ -507,6 +506,9 @@ PropertyNameList getSlots(const ObjectValue *objectValue, const ContextPtr &cont
|
||||
PropertyMemberProcessor processor(context);
|
||||
objectValue->processMembers(&processor);
|
||||
|
||||
if (const ASTObjectValue *astObjectValue = objectValue->asAstObjectValue())
|
||||
astObjectValue->processMembers(&processor);
|
||||
|
||||
slotList.append(processor.slotList());
|
||||
|
||||
PrototypeIterator prototypeIterator(objectValue, context);
|
||||
@@ -534,6 +536,7 @@ QVector<PropertyInfo> getObjectTypes(const ObjectValue *objectValue, const Conte
|
||||
|
||||
PropertyMemberProcessor processor(context);
|
||||
objectValue->processMembers(&processor);
|
||||
|
||||
const auto props = processor.properties();
|
||||
|
||||
for (const PropertyInfo &property : props) {
|
||||
|
||||
130
src/plugins/qmldesigner/designercore/model/qmlconnections.cpp
Normal 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.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qmlconnections.h"
|
||||
|
||||
#include <metainfo.h>
|
||||
#include <abstractview.h>
|
||||
#include <bindingproperty.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
QmlConnections::QmlConnections()
|
||||
{
|
||||
}
|
||||
|
||||
QmlConnections::QmlConnections(const ModelNode &modelNode)
|
||||
: QmlModelNodeFacade(modelNode)
|
||||
{
|
||||
}
|
||||
|
||||
bool QmlConnections::isValid() const
|
||||
{
|
||||
return isValidQmlConnections(modelNode());
|
||||
}
|
||||
|
||||
bool QmlConnections::isValidQmlConnections(const ModelNode &modelNode)
|
||||
{
|
||||
return isValidQmlModelNodeFacade(modelNode)
|
||||
&& modelNode.metaInfo().isValid()
|
||||
&& (modelNode.type() == "Connections"
|
||||
|| modelNode.type() == "QtQuick.Connections"
|
||||
|| modelNode.type() == "Qt.Connections"
|
||||
|| modelNode.type() == "QtQml.Connections");
|
||||
}
|
||||
|
||||
/*!
|
||||
Removes connections node.
|
||||
*/
|
||||
void QmlConnections::destroy()
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
modelNode().destroy();
|
||||
}
|
||||
|
||||
QString QmlConnections::target() const
|
||||
{
|
||||
if (modelNode().isValid()) {
|
||||
const BindingProperty bindingproperty = modelNode().bindingProperty("target");
|
||||
if (bindingproperty.isValid())
|
||||
return bindingproperty.expression();
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
void QmlConnections::setTarget(const QString &target)
|
||||
{
|
||||
modelNode().bindingProperty("target").setExpression(target);
|
||||
}
|
||||
|
||||
ModelNode QmlConnections::getTargetNode() const
|
||||
{
|
||||
ModelNode result;
|
||||
|
||||
if (!modelNode().isValid())
|
||||
return result;
|
||||
|
||||
const BindingProperty bindingProperty = modelNode().bindingProperty("target");
|
||||
const QString bindExpression = bindingProperty.expression();
|
||||
|
||||
if (bindingProperty.isValid()) {
|
||||
AbstractView *view = modelNode().view();
|
||||
if (bindExpression.contains(".")) {
|
||||
QStringList substr = bindExpression.split(".");
|
||||
const QString itemId = substr.constFirst();
|
||||
if (substr.size() > 1) {
|
||||
const ModelNode aliasParent = view->modelNodeForId(itemId);
|
||||
substr.removeFirst(); // remove id, only alias pieces left
|
||||
const QString aliasBody = substr.join(".");
|
||||
if (aliasParent.isValid() && aliasParent.hasBindingProperty(aliasBody.toUtf8())) {
|
||||
const BindingProperty binding = aliasParent.bindingProperty(aliasBody.toUtf8());
|
||||
if (binding.isValid() && view->hasId(binding.expression()))
|
||||
result = view->modelNodeForId(binding.expression());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result = view->modelNodeForId(bindExpression);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QList<SignalHandlerProperty> QmlConnections::signalProperties() const
|
||||
{
|
||||
return modelNode().signalProperties();
|
||||
}
|
||||
|
||||
ModelNode QmlConnections::createQmlConnections(AbstractView *view)
|
||||
{
|
||||
NodeMetaInfo nodeMetaInfo = view->model()->metaInfo("QtQuick.Connections");
|
||||
return view->createModelNode("QtQuick.Connections",
|
||||
nodeMetaInfo.majorVersion(),
|
||||
nodeMetaInfo.minorVersion());
|
||||
}
|
||||
|
||||
} // QmlDesigner
|
||||
@@ -40,13 +40,11 @@ SignalHandlerProperty::SignalHandlerProperty(const SignalHandlerProperty &proper
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
SignalHandlerProperty::SignalHandlerProperty(const PropertyName &propertyName, const Internal::InternalNodePointer &internalNode, Model* model, AbstractView *view)
|
||||
: AbstractProperty(propertyName, internalNode, model, view)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void SignalHandlerProperty::setSource(const QString &source)
|
||||
{
|
||||
Internal::WriteLocker locker(model());
|
||||
@@ -83,4 +81,30 @@ QString SignalHandlerProperty::source() const
|
||||
return QString();
|
||||
}
|
||||
|
||||
PropertyName SignalHandlerProperty::prefixAdded(const PropertyName &propertyName)
|
||||
{
|
||||
QString nameAsString = QString::fromUtf8(propertyName);
|
||||
if (nameAsString.startsWith("on"))
|
||||
return propertyName;
|
||||
|
||||
QChar firstChar = nameAsString.at(0).toUpper();
|
||||
nameAsString[0] = firstChar;
|
||||
nameAsString.prepend("on");
|
||||
|
||||
return nameAsString.toLatin1();
|
||||
}
|
||||
|
||||
PropertyName SignalHandlerProperty::prefixRemoved(const PropertyName &propertyName)
|
||||
{
|
||||
QString nameAsString = QString::fromUtf8(propertyName);
|
||||
if (!nameAsString.startsWith("on"))
|
||||
return propertyName;
|
||||
|
||||
nameAsString.remove(0, 2);
|
||||
QChar firstChar = nameAsString.at(0).toLower();
|
||||
nameAsString[0] = firstChar;
|
||||
|
||||
return nameAsString.toLatin1();
|
||||
}
|
||||
|
||||
} // namespace QmlDesigner
|
||||
|
||||
@@ -302,6 +302,7 @@ Project {
|
||||
"include/qmlmodelnodefacade.h",
|
||||
"include/qmlobjectnode.h",
|
||||
"include/qmlstate.h",
|
||||
"include/qmlconnections.h",
|
||||
"include/removebasestateexception.h",
|
||||
"include/documentmessage.h",
|
||||
"include/rewriterview.h",
|
||||
@@ -391,6 +392,7 @@ Project {
|
||||
"model/qmlmodelnodefacade.cpp",
|
||||
"model/qmlobjectnode.cpp",
|
||||
"model/qmlstate.cpp",
|
||||
"model/qmlconnections.cpp",
|
||||
"model/qmltextgenerator.cpp",
|
||||
"model/qmltextgenerator.h",
|
||||
"model/rewriteaction.cpp",
|
||||
@@ -739,6 +741,12 @@ Project {
|
||||
"bindingeditor/bindingeditorwidget.h",
|
||||
"bindingeditor/connectionvisitor.cpp",
|
||||
"bindingeditor/connectionvisitor.h",
|
||||
"bindingeditor/signallist.cpp",
|
||||
"bindingeditor/signallist.h",
|
||||
"bindingeditor/signallistdialog.cpp",
|
||||
"bindingeditor/signallistdialog.h",
|
||||
"bindingeditor/signallistdelegate.cpp",
|
||||
"bindingeditor/signallistdelegate.h",
|
||||
"colortool/colortool.cpp",
|
||||
"colortool/colortool.h",
|
||||
"connectioneditor/addnewbackenddialog.h",
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
#include <texteditor/texteditoractionhandler.h>
|
||||
#include <texteditor/textmark.h>
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/delegates.h>
|
||||
#include <utils/changeset.h>
|
||||
#include <utils/qtcassert.h>
|
||||
@@ -373,8 +374,13 @@ void QmlJSEditorWidget::updateUses()
|
||||
return;
|
||||
|
||||
QList<QTextEdit::ExtraSelection> selections;
|
||||
foreach (const SourceLocation &loc,
|
||||
m_qmlJsEditorDocument->semanticInfo().idLocations.value(wordUnderCursor())) {
|
||||
QList<SourceLocation> locations
|
||||
= m_qmlJsEditorDocument->semanticInfo().idLocations.value(wordUnderCursor());
|
||||
// code model may present the locations not in a document order
|
||||
Utils::sort(locations, [](const SourceLocation &lhs, const SourceLocation &rhs) {
|
||||
return lhs.begin() < rhs.begin();
|
||||
});
|
||||
for (const SourceLocation &loc : qAsConst(locations)) {
|
||||
if (! loc.isValid())
|
||||
continue;
|
||||
|
||||
|
||||
@@ -258,6 +258,62 @@ TEST_F(SqliteStatement, BindPointer)
|
||||
ASSERT_THAT(statement.fetchIntValue(0), 1);
|
||||
}
|
||||
|
||||
TEST_F(SqliteStatement, BindIntCarray)
|
||||
{
|
||||
SqliteTestStatement statement("SELECT value FROM carray(?)", database);
|
||||
std::vector<int> values{3, 10, 20, 33, 55};
|
||||
|
||||
statement.bind(1, values);
|
||||
statement.next();
|
||||
statement.next();
|
||||
statement.next();
|
||||
statement.next();
|
||||
|
||||
ASSERT_THAT(statement.fetchIntValue(0), 33);
|
||||
}
|
||||
|
||||
TEST_F(SqliteStatement, BindLongLongCarray)
|
||||
{
|
||||
SqliteTestStatement statement("SELECT value FROM carray(?)", database);
|
||||
std::vector<long long> values{3, 10, 20, 33, 55};
|
||||
|
||||
statement.bind(1, values);
|
||||
statement.next();
|
||||
statement.next();
|
||||
statement.next();
|
||||
statement.next();
|
||||
|
||||
ASSERT_THAT(statement.fetchLongLongValue(0), 33);
|
||||
}
|
||||
|
||||
TEST_F(SqliteStatement, BindDoubleCarray)
|
||||
{
|
||||
SqliteTestStatement statement("SELECT value FROM carray(?)", database);
|
||||
std::vector<double> values{3.3, 10.2, 20.54, 33.21, 55};
|
||||
|
||||
statement.bind(1, values);
|
||||
statement.next();
|
||||
statement.next();
|
||||
statement.next();
|
||||
statement.next();
|
||||
|
||||
ASSERT_THAT(statement.fetchDoubleValue(0), 33.21);
|
||||
}
|
||||
|
||||
TEST_F(SqliteStatement, BindTextCarray)
|
||||
{
|
||||
SqliteTestStatement statement("SELECT value FROM carray(?)", database);
|
||||
std::vector<const char *> values{"yi", "er", "san", "se", "wu"};
|
||||
|
||||
statement.bind(1, values);
|
||||
statement.next();
|
||||
statement.next();
|
||||
statement.next();
|
||||
statement.next();
|
||||
|
||||
ASSERT_THAT(statement.fetchSmallStringViewValue(0), Eq("se"));
|
||||
}
|
||||
|
||||
TEST_F(SqliteStatement, BindBlob)
|
||||
{
|
||||
SqliteTestStatement statement("WITH T(blob) AS (VALUES (?)) SELECT blob FROM T", database);
|
||||
@@ -378,6 +434,47 @@ TEST_F(SqliteStatement, WritePointerValues)
|
||||
ASSERT_THAT(statement.template values<int>(5), ElementsAre(1, 1, 2, 3, 5));
|
||||
}
|
||||
|
||||
TEST_F(SqliteStatement, WriteIntCarrayValues)
|
||||
{
|
||||
SqliteTestStatement statement("SELECT value FROM carray(?)", database);
|
||||
std::vector<int> values{3, 10, 20, 33, 55};
|
||||
|
||||
statement.write(Utils::span(values));
|
||||
|
||||
ASSERT_THAT(statement.template values<int>(5), ElementsAre(3, 10, 20, 33, 55));
|
||||
}
|
||||
|
||||
TEST_F(SqliteStatement, WriteLongLongCarrayValues)
|
||||
{
|
||||
SqliteTestStatement statement("SELECT value FROM carray(?)", database);
|
||||
std::vector<long long> values{3, 10, 20, 33, 55};
|
||||
|
||||
statement.write(Utils::span(values));
|
||||
|
||||
ASSERT_THAT(statement.template values<long long>(5), ElementsAre(3, 10, 20, 33, 55));
|
||||
}
|
||||
|
||||
TEST_F(SqliteStatement, WriteDoubleCarrayValues)
|
||||
{
|
||||
SqliteTestStatement statement("SELECT value FROM carray(?)", database);
|
||||
std::vector<double> values{3.3, 10.2, 20.54, 33.21, 55};
|
||||
|
||||
statement.write(Utils::span(values));
|
||||
|
||||
ASSERT_THAT(statement.template values<double>(5), ElementsAre(3.3, 10.2, 20.54, 33.21, 55));
|
||||
}
|
||||
|
||||
TEST_F(SqliteStatement, WriteTextCarrayValues)
|
||||
{
|
||||
SqliteTestStatement statement("SELECT value FROM carray(?)", database);
|
||||
std::vector<const char *> values{"yi", "er", "san", "se", "wu"};
|
||||
|
||||
statement.write(Utils::span(values));
|
||||
|
||||
ASSERT_THAT(statement.template values<Utils::SmallString>(5),
|
||||
ElementsAre("yi", "er", "san", "se", "wu"));
|
||||
}
|
||||
|
||||
TEST_F(SqliteStatement, WriteNullValues)
|
||||
{
|
||||
WriteStatement statement("UPDATE test SET name=?, number=? WHERE rowid=?", database);
|
||||
|
||||