Merge "Merge remote-tracking branch 'origin/4.14'"

This commit is contained in:
The Qt Project
2021-01-07 15:30:19 +00:00
90 changed files with 17798 additions and 12611 deletions

View File

@@ -37,35 +37,36 @@ if (APPLE)
set(_IDE_OUTPUT_PATH "${_IDE_APP_PATH}/${_IDE_APP_TARGET}.app/Contents") 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_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_LIBEXEC_PATH "${_IDE_OUTPUT_PATH}/Resources/libexec")
set(_IDE_DATA_PATH "${_IDE_OUTPUT_PATH}/Resources") set(_IDE_DATA_PATH "${_IDE_OUTPUT_PATH}/Resources")
set(_IDE_DOC_PATH "${_IDE_OUTPUT_PATH}/Resources/doc") set(_IDE_DOC_PATH "${_IDE_OUTPUT_PATH}/Resources/doc")
set(_IDE_BIN_PATH "${_IDE_OUTPUT_PATH}/MacOS") set(_IDE_BIN_PATH "${_IDE_OUTPUT_PATH}/MacOS")
elseif(WIN32)
set(QT_DEST_PLUGIN_PATH "${_IDE_PLUGIN_PATH}")
set(QT_DEST_QML_PATH "${_IDE_DATA_PATH}/../Imports/qtquick2")
else ()
set(_IDE_APP_PATH "bin") set(_IDE_APP_PATH "bin")
set(_IDE_APP_TARGET "${IDE_ID}") set(_IDE_APP_TARGET "${IDE_ID}")
set(_IDE_LIBRARY_BASE_PATH "lib") set(_IDE_LIBRARY_BASE_PATH "lib")
set(_IDE_LIBRARY_PATH "lib/qtcreator") set(_IDE_LIBRARY_PATH "${_IDE_LIBRARY_BASE_PATH}/qtcreator")
set(_IDE_PLUGIN_PATH "lib/qtcreator/plugins") set(_IDE_PLUGIN_PATH "${_IDE_LIBRARY_BASE_PATH}/qtcreator/plugins")
if (WIN32) set(_IDE_LIBEXEC_PATH "bin")
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_DATA_PATH "share/qtcreator") set(_IDE_DATA_PATH "share/qtcreator")
set(_IDE_DOC_PATH "share/doc/qtcreator") set(_IDE_DOC_PATH "share/doc/qtcreator")
set(_IDE_BIN_PATH "bin") 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 () endif ()
file(RELATIVE_PATH _PLUGIN_TO_LIB "/${_IDE_PLUGIN_PATH}" "/${_IDE_LIBRARY_PATH}") file(RELATIVE_PATH _PLUGIN_TO_LIB "/${_IDE_PLUGIN_PATH}" "/${_IDE_LIBRARY_PATH}")

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -166,7 +166,7 @@
system to the Clang code model for displaying annotations in the system to the Clang code model for displaying annotations in the
code editor. 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 \li In the \uicontrol {Clang-Tidy Checks} tab, select
\uicontrol {Select Checks} to select the checks to perform. \uicontrol {Select Checks} to select the checks to perform.

View File

@@ -138,7 +138,10 @@
edit the value for the \uicontrol {Do not index files greater than} edit the value for the \uicontrol {Do not index files greater than}
check box. To index all files, deselect the check box. 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 \image qtcreator-diagnostics-configuration.png
@@ -146,26 +149,18 @@
\section1 Clang Checks \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 \uicontrol {Checks for questionable constructs} combines the \c -Wall and
option that performs checks as required by strict ISO C and ISO C++. \c -Wextra checks for easily avoidable questionable constructions and some
additional issues.
\li \uicontrol {Clang-only checks for questionable constructs} combines Clang checks begin with \c -W. Each check also has a negative version that
the \c -Wall and \c -Wextra checks for easily avoidable questionable begins with \c -Wno.
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.
Keep in mind that some options turn on other options. For more information, Keep in mind that some options turn on other options. For more information,
see \l{https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html} see \l{https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html}

View File

@@ -293,6 +293,13 @@
\image qtquickcontrols2-button-flat.gif "Flat button" \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 \section2 Delay Button
\image qtquickcontrols2-delaybutton.gif "Delay button" \image qtquickcontrols2-delaybutton.gif "Delay button"

View File

@@ -125,6 +125,7 @@
\li \l {Lists and Other Data Models} \li \l {Lists and Other Data Models}
\if defined(qtdesignstudio) \if defined(qtdesignstudio)
\li \l {2D Effects} \li \l {2D Effects}
\li \l {Logic Helpers}
\endif \endif
\endlist \endlist

Binary file not shown.

After

Width:  |  Height:  |  Size: 238 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 241 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 291 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 257 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 351 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@@ -92,6 +92,7 @@
\li \l{User Interaction Methods} \li \l{User Interaction Methods}
\li \l{Lists and Other Data Models} \li \l{Lists and Other Data Models}
\li \l{2D Effects} \li \l{2D Effects}
\li \l{Logic Helpers}
\li \l{Creating Buttons} \li \l{Creating Buttons}
\li \l{Creating Scalable Buttons and Borders} \li \l{Creating Scalable Buttons and Borders}
\endlist \endlist

View File

@@ -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
*/

View File

@@ -26,7 +26,7 @@
/*! /*!
\page quick-2d-effects.html \page quick-2d-effects.html
\previouspage quick-data-models.html \previouspage quick-data-models.html
\nextpage quick-buttons.html \nextpage quick-logic-helpers.html
\title 2D Effects \title 2D Effects

View File

@@ -1,7 +1,15 @@
NOTE:
While the primary intention of this pretty printing implementation is 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 to provide what Qt Creator needs, it can sometimes be used in plain
session, too. 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 With

View File

@@ -1,4 +1,6 @@
<!DOCTYPE TS><TS> <?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="hu">
<context> <context>
<name>Application</name> <name>Application</name>
<message> <message>

View File

@@ -41,7 +41,7 @@ list(APPEND CMAKE_MODULE_PATH \${CMAKE_CURRENT_LIST_DIR})
include(CMakeFindDependencyMacro) include(CMakeFindDependencyMacro)
find_dependency(Qt5 ${IDE_QT_VERSION_MIN} 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) if (NOT IDE_VERSION)

View File

@@ -57,21 +57,32 @@ SQLITE_EXTENSION_INIT1
#include <assert.h> #include <assert.h>
#include <string.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 #ifndef SQLITE_OMIT_VIRTUALTABLE
/* /*
** Allowed datatypes ** Names of allowed datatypes
*/
#define CARRAY_INT32 0
#define CARRAY_INT64 1
#define CARRAY_DOUBLE 2
#define CARRAY_TEXT 3
/*
** Names of types
*/ */
static const char *azType[] = { "int32", "int64", "double", "char*" }; 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 /* carray_cursor is a subclass of sqlite3_vtab_cursor which will
** serve as the underlying representation of a cursor that scans ** 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. ** Constructor for a new carray_cursor object.
*/ */
static int carrayOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor) static int carrayOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
{ carray_cursor *pCur;
carray_cursor *pCur; pCur = sqlite3_malloc( sizeof(*pCur) );
if( pCur==0 ) return SQLITE_NOMEM;
pCur = sqlite3_malloc(sizeof(*pCur)); memset(pCur, 0, sizeof(*pCur));
if (pCur == 0) *ppCursor = &pCur->base;
return SQLITE_NOMEM; return SQLITE_OK;
memset(pCur, 0, sizeof(*pCur));
*ppCursor = &pCur->base;
return SQLITE_OK;
} }
/* /*
@@ -242,28 +250,39 @@ static int carrayFilter(
int argc, sqlite3_value **argv int argc, sqlite3_value **argv
){ ){
carray_cursor *pCur = (carray_cursor *)pVtabCursor; carray_cursor *pCur = (carray_cursor *)pVtabCursor;
if( idxNum ){ pCur->pPtr = 0;
pCur->pPtr = sqlite3_value_pointer(argv[0], "carray"); pCur->iCnt = 0;
pCur->iCnt = pCur->pPtr ? sqlite3_value_int64(argv[1]) : 0; switch( idxNum ){
if( idxNum<3 ){ case 1: {
pCur->eType = CARRAY_INT32; carray_bind *pBind = sqlite3_value_pointer(argv[0], "carray-bind");
}else{ if( pBind==0 ) break;
unsigned char i; pCur->pPtr = pBind->aData;
const char *zType = (const char*)sqlite3_value_text(argv[2]); pCur->iCnt = pBind->nData;
for(i=0; i<sizeof(azType)/sizeof(azType[0]); i++){ pCur->eType = pBind->mFlags & 0x03;
if( sqlite3_stricmp(zType, azType[i])==0 ) break; break;
} }
if( i>=sizeof(azType)/sizeof(azType[0]) ){ case 2:
pVtabCursor->pVtab->zErrMsg = sqlite3_mprintf( case 3: {
"unknown datatype: %Q", zType); pCur->pPtr = sqlite3_value_pointer(argv[0], "carray");
return SQLITE_ERROR; pCur->iCnt = pCur->pPtr ? sqlite3_value_int64(argv[1]) : 0;
}else{ if( idxNum<3 ){
pCur->eType = i; 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; pCur->iRowid = 1;
return SQLITE_OK; return SQLITE_OK;
@@ -278,9 +297,16 @@ static int carrayFilter(
** In this implementation idxNum is used to represent the ** In this implementation idxNum is used to represent the
** query plan. idxStr is unused. ** query plan. idxStr is unused.
** **
** idxNum is 2 if the pointer= and count= constraints exist, ** idxNum is:
** 3 if the ctype= constraint also exists, and is 0 otherwise. **
** If idxNum is 0, then carray becomes an empty table. ** 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( static int carrayBestIndex(
sqlite3_vtab *tab, sqlite3_vtab *tab,
@@ -308,18 +334,21 @@ static int carrayBestIndex(
break; break;
} }
} }
if( ptrIdx>=0 && cntIdx>=0 ){ if( ptrIdx>=0 ){
pIdxInfo->aConstraintUsage[ptrIdx].argvIndex = 1; pIdxInfo->aConstraintUsage[ptrIdx].argvIndex = 1;
pIdxInfo->aConstraintUsage[ptrIdx].omit = 1; pIdxInfo->aConstraintUsage[ptrIdx].omit = 1;
pIdxInfo->aConstraintUsage[cntIdx].argvIndex = 2;
pIdxInfo->aConstraintUsage[cntIdx].omit = 1;
pIdxInfo->estimatedCost = (double)1; pIdxInfo->estimatedCost = (double)1;
pIdxInfo->estimatedRows = 100; pIdxInfo->estimatedRows = 100;
pIdxInfo->idxNum = 2; pIdxInfo->idxNum = 1;
if( ctypeIdx>=0 ){ if( cntIdx>=0 ){
pIdxInfo->aConstraintUsage[ctypeIdx].argvIndex = 3; pIdxInfo->aConstraintUsage[cntIdx].argvIndex = 2;
pIdxInfo->aConstraintUsage[ctypeIdx].omit = 1; pIdxInfo->aConstraintUsage[cntIdx].omit = 1;
pIdxInfo->idxNum = 3; pIdxInfo->idxNum = 2;
if( ctypeIdx>=0 ){
pIdxInfo->aConstraintUsage[ctypeIdx].argvIndex = 3;
pIdxInfo->aConstraintUsage[ctypeIdx].omit = 1;
pIdxInfo->idxNum = 3;
}
} }
}else{ }else{
pIdxInfo->estimatedCost = (double)2147483647; pIdxInfo->estimatedCost = (double)2147483647;
@@ -356,6 +385,89 @@ static sqlite3_module carrayModule = {
0, /* xRename */ 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 ** For testing purpose in the TCL test harness, we need a method for
** setting the pointer value. The inttoptr(X) SQL function accomplishes ** setting the pointer value. The inttoptr(X) SQL function accomplishes
@@ -386,16 +498,22 @@ static void inttoptrFunc(
#endif /* SQLITE_OMIT_VIRTUALTABLE */ #endif /* SQLITE_OMIT_VIRTUALTABLE */
int sqlite3_carray_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi) #ifdef _WIN32
{ __declspec(dllexport)
int rc = SQLITE_OK; #endif
SQLITE_EXTENSION_INIT2(pApi); 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 #ifndef SQLITE_OMIT_VIRTUALTABLE
rc = sqlite3_create_module(db, "carray", &carrayModule, 0); rc = sqlite3_create_module(db, "carray", &carrayModule, 0);
#ifdef SQLITE_TEST #ifdef SQLITE_TEST
if (rc == SQLITE_OK) { if( rc==SQLITE_OK ){
rc = sqlite3_create_function(db, "inttoptr", 1, SQLITE_UTF8, 0, inttoptrFunc, 0, 0); rc = sqlite3_create_function(db, "inttoptr", 1, SQLITE_UTF8, 0,
inttoptrFunc, 0, 0);
} }
#endif /* SQLITE_TEST */ #endif /* SQLITE_TEST */
#endif /* SQLITE_OMIT_VIRTUALTABLE */ #endif /* SQLITE_OMIT_VIRTUALTABLE */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -330,6 +330,13 @@ struct sqlite3_api_routines {
const char *(*filename_database)(const char*); const char *(*filename_database)(const char*);
const char *(*filename_journal)(const char*); const char *(*filename_journal)(const char*);
const char *(*filename_wal)(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_database sqlite3_api->filename_database
#define sqlite3_filename_journal sqlite3_api->filename_journal #define sqlite3_filename_journal sqlite3_api->filename_journal
#define sqlite3_filename_wal sqlite3_api->filename_wal #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) */ #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)

View File

@@ -479,8 +479,8 @@ void Snapshot::insert(const Document::Ptr &document, bool allowInvalid)
CoreImport cImport; CoreImport cImport;
cImport.importId = document->importId(); cImport.importId = document->importId();
cImport.language = document->language(); cImport.language = document->language();
cImport.possibleExports << Export(ImportKey(ImportType::File, fileName), cImport.addPossibleExport(Export(ImportKey(ImportType::File, fileName),
QString(), true, QFileInfo(fileName).baseName()); {}, true, QFileInfo(fileName).baseName()));
cImport.fingerprint = document->fingerprint(); cImport.fingerprint = document->fingerprint();
_dependencies.addCoreImport(cImport); _dependencies.addCoreImport(cImport);
} }
@@ -526,13 +526,13 @@ void Snapshot::insertLibraryInfo(const QString &path, const LibraryInfo &info)
break; break;
ImportKey iKey(ImportType::Library, QStringList(myPath.mid(iPath)).join(QLatin1Char('.')), ImportKey iKey(ImportType::Library, QStringList(myPath.mid(iPath)).join(QLatin1Char('.')),
importKey.majorVersion, importKey.minorVersion); 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)); QStringList(myPath.mid(0, iPath)).join(QLatin1Char('/')), true));
} }
} else { } else {
QString requiredPath = QStringList(splitPath.mid(0, splitPath.size() - importKey.splitPath.size())) QString requiredPath = QStringList(splitPath.mid(0, splitPath.size() - importKey.splitPath.size()))
.join(QLatin1String("/")); .join(QLatin1String("/"));
cImport.possibleExports << Export(importKey, requiredPath, true); cImport.addPossibleExport(Export(importKey, requiredPath, true));
} }
} }
if (cImport.possibleExports.isEmpty() && splitPath.size() > 0) { if (cImport.possibleExports.isEmpty() && splitPath.size() > 0) {
@@ -567,7 +567,7 @@ void Snapshot::insertLibraryInfo(const QString &path, const LibraryInfo &info)
break; break;
ImportKey iKey(ImportType::Library, QStringList(splitPath.mid(iPath)).join(QLatin1Char('.')), ImportKey iKey(ImportType::Library, QStringList(splitPath.mid(iPath)).join(QLatin1Char('.')),
majorVersion, minorVersion); 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)); QStringList(splitPath.mid(0, iPath)).join(QLatin1Char('/')), true));
} }
} }

View File

@@ -32,11 +32,35 @@
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <QCryptographicHash> #include <QCryptographicHash>
#include <QElapsedTimer>
#include <QLoggingCategory> #include <QLoggingCategory>
#include <algorithm> #include <algorithm>
static Q_LOGGING_CATEGORY(importsLog, "qtc.qmljs.imports", QtWarningMsg) 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 { namespace QmlJS {
@@ -304,7 +328,7 @@ ImportMatchStrength ImportKey::matchImport(const ImportKey &o, const ViewerConte
return ImportMatchStrength(); return ImportMatchStrength();
const QString p1 = splitPath.at(iPath1); const QString p1 = splitPath.at(iPath1);
if (iPath2 < lenPath2) { if (iPath2 < lenPath2) {
const QString p2 = splitPath.at(iPath2); const QString p2 = o.splitPath.at(iPath2);
if (p1 == p2) { if (p1 == p2) {
++iPath1; ++iPath1;
++iPath2; ++iPath2;
@@ -520,19 +544,6 @@ bool Export::visibleInVContext(const ViewerContext &vContext) const
return pathRequired.isEmpty() || vContext.paths.contains(pathRequired); 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() : language(Dialect::Qml) { }
CoreImport::CoreImport(const QString &importId, const QList<Export> &possibleExports, CoreImport::CoreImport(const QString &importId, const QList<Export> &possibleExports,
@@ -609,6 +620,7 @@ ImportDependencies::~ImportDependencies()
void ImportDependencies::filter(const ViewerContext &vContext) void ImportDependencies::filter(const ViewerContext &vContext)
{ {
ImportsBenchmarker benchMark("filter()");
QMap<QString, CoreImport> newCoreImports; QMap<QString, CoreImport> newCoreImports;
QMap<ImportKey, QStringList> newImportCache; QMap<ImportKey, QStringList> newImportCache;
bool hasChanges = false; bool hasChanges = false;
@@ -617,6 +629,7 @@ void ImportDependencies::filter(const ViewerContext &vContext)
if (languageIsCompatible(vContext.language, cImport.language)) { if (languageIsCompatible(vContext.language, cImport.language)) {
QList<Export> newExports; QList<Export> newExports;
foreach (const Export &e, cImport.possibleExports) { foreach (const Export &e, cImport.possibleExports) {
++benchMark.nPossibleExports;
if (e.visibleInVContext(vContext)) { if (e.visibleInVContext(vContext)) {
newExports.append(e); newExports.append(e);
QStringList &candidateImports = newImportCache[e.exportName]; QStringList &candidateImports = newImportCache[e.exportName];
@@ -654,6 +667,7 @@ void ImportDependencies::iterateOnCandidateImports(
std::function<bool (const ImportMatchStrength &,const Export &,const CoreImport &)> std::function<bool (const ImportMatchStrength &,const Export &,const CoreImport &)>
const &iterF) const const &iterF) const
{ {
ImportsBenchmarker benchMark("iterateOnCandidateImports()");
switch (key.type) { switch (key.type) {
case ImportType::Directory: case ImportType::Directory:
case ImportType::QrcDirectory: case ImportType::QrcDirectory:
@@ -666,6 +680,7 @@ void ImportDependencies::iterateOnCandidateImports(
CoreImport cImport = coreImport(cImportName); CoreImport cImport = coreImport(cImportName);
if (languageIsCompatible(vContext.language, cImport.language)) { if (languageIsCompatible(vContext.language, cImport.language)) {
foreach (const Export e, cImport.possibleExports) { foreach (const Export e, cImport.possibleExports) {
++benchMark.nPossibleExports;
if (e.visibleInVContext(vContext)) { if (e.visibleInVContext(vContext)) {
ImportMatchStrength m = e.exportName.matchImport(key, vContext); ImportMatchStrength m = e.exportName.matchImport(key, vContext);
if (m.hasMatch()) { if (m.hasMatch()) {
@@ -688,6 +703,7 @@ void ImportDependencies::iterateOnCandidateImports(
CoreImport cImport = coreImport(cImportName); CoreImport cImport = coreImport(cImportName);
if (languageIsCompatible(vContext.language, cImport.language)) { if (languageIsCompatible(vContext.language, cImport.language)) {
foreach (const Export e, cImport.possibleExports) { foreach (const Export e, cImport.possibleExports) {
++benchMark.nPossibleExports;
if (e.visibleInVContext(vContext)) { if (e.visibleInVContext(vContext)) {
ImportMatchStrength m = e.exportName.matchImport(key, vContext); ImportMatchStrength m = e.exportName.matchImport(key, vContext);
if (m.hasMatch()) { if (m.hasMatch()) {
@@ -810,13 +826,13 @@ void ImportDependencies::addExport(const QString &importId, const ImportKey &imp
if (!m_coreImports.contains(importId)) { if (!m_coreImports.contains(importId)) {
CoreImport newImport(importId); CoreImport newImport(importId);
newImport.language = Dialect::AnyLanguage; 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_coreImports.insert(newImport.importId, newImport);
m_importCache[importKey].append(importId); m_importCache[importKey].append(importId);
return; return;
} }
CoreImport &importValue = m_coreImports[importId]; 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); m_importCache[importKey].append(importId);
qCDebug(importsLog) << "added export "<< importKey.toString() << " for id " <<importId qCDebug(importsLog) << "added export "<< importKey.toString() << " for id " <<importId
<< " (" << requiredPath << ")"; << " (" << requiredPath << ")";
@@ -853,6 +869,8 @@ void ImportDependencies::iterateOnLibraryImports(
const Export &, const Export &,
const CoreImport &)> const &iterF) const const CoreImport &)> const &iterF) const
{ {
ImportsBenchmarker benchMark("iterateOnLibraryImports()");
typedef QMap<ImportKey, QStringList>::const_iterator iter_t; typedef QMap<ImportKey, QStringList>::const_iterator iter_t;
ImportKey firstLib; ImportKey firstLib;
firstLib.type = ImportType::Library; firstLib.type = ImportType::Library;
@@ -864,6 +882,7 @@ void ImportDependencies::iterateOnLibraryImports(
CoreImport cImport = coreImport(cImportName); CoreImport cImport = coreImport(cImportName);
if (languageIsCompatible(vContext.language, cImport.language)) { if (languageIsCompatible(vContext.language, cImport.language)) {
foreach (const Export &e, cImport.possibleExports) { foreach (const Export &e, cImport.possibleExports) {
++benchMark.nPossibleExports;
if (e.visibleInVContext(vContext) && e.exportName.type == ImportType::Library) { if (e.visibleInVContext(vContext) && e.exportName.type == ImportType::Library) {
ImportMatchStrength m = e.exportName.matchImport(i.key(), vContext); ImportMatchStrength m = e.exportName.matchImport(i.key(), vContext);
if (m.hasMatch()) { if (m.hasMatch()) {
@@ -887,6 +906,7 @@ void ImportDependencies::iterateOnSubImports(
const Export &, const Export &,
const CoreImport &)> const &iterF) const const CoreImport &)> const &iterF) const
{ {
ImportsBenchmarker benchMark("iterateOnSubImports()");
typedef QMap<ImportKey, QStringList>::const_iterator iter_t; typedef QMap<ImportKey, QStringList>::const_iterator iter_t;
iter_t i = m_importCache.lowerBound(baseKey); iter_t i = m_importCache.lowerBound(baseKey);
iter_t end = m_importCache.constEnd(); iter_t end = m_importCache.constEnd();
@@ -898,6 +918,7 @@ void ImportDependencies::iterateOnSubImports(
CoreImport cImport = coreImport(cImportName); CoreImport cImport = coreImport(cImportName);
if (languageIsCompatible(vContext.language, cImport.language)) { if (languageIsCompatible(vContext.language, cImport.language)) {
foreach (const Export &e, cImport.possibleExports) { foreach (const Export &e, cImport.possibleExports) {
++benchMark.nPossibleExports;
if (e.visibleInVContext(vContext)) { if (e.visibleInVContext(vContext)) {
ImportMatchStrength m = e.exportName.matchImport(i.key(), vContext); ImportMatchStrength m = e.exportName.matchImport(i.key(), vContext);
if (m.hasMatch()) { if (m.hasMatch()) {

View File

@@ -134,9 +134,27 @@ public:
QString typeName; QString typeName;
bool intrinsic; bool intrinsic;
bool visibleInVContext(const ViewerContext &vContext) const; 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 class QMLJS_EXPORT CoreImport
{ {
@@ -144,6 +162,14 @@ public:
CoreImport(); CoreImport();
CoreImport(const QString &importId, const QList<Export> &possibleExports = QList<Export>(), CoreImport(const QString &importId, const QList<Export> &possibleExports = QList<Export>(),
Dialect language = Dialect::Qml, const QByteArray &fingerprint = QByteArray()); 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; QString importId;
QList<Export> possibleExports; QList<Export> possibleExports;
Dialect language; Dialect language;

View File

@@ -446,12 +446,10 @@ std::string collectOutput()
// Add a child to messages for every line. // Add a child to messages for every line.
while (std::getline(pyStdout, line)) { while (std::getline(pyStdout, line)) {
// there are two kinds of messages we want to handle here: // 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 << ','; ret << line << ',';
} else { // and a line of "normal" python output else // and a line of "normal" python output
replace(line, '"', '$'); // otherwise creators gdbmi parser would fail ret << "line=\"" << gdbmiStringFormat(line) << "\",";
ret << "line=\"" << line << "\",";
}
} }
ret << "]," << results << "]"; ret << "]," << results << "]";
results.clear(); results.clear();

View File

@@ -38,6 +38,14 @@
# pragma GCC diagnostic ignored "-Wignored-qualifiers" # pragma GCC diagnostic ignored "-Wignored-qualifiers"
#endif #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 { namespace Sqlite {
BaseStatement::BaseStatement(Utils::SmallStringView sqlStatement, Database &database) BaseStatement::BaseStatement(Utils::SmallStringView sqlStatement, Database &database)
@@ -180,6 +188,54 @@ void BaseStatement::bind(int index, void *pointer)
checkForBindingError(resultCode); 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) void BaseStatement::bind(int index, Utils::SmallStringView text)
{ {
int resultCode = sqlite3_bind_text(m_compiledStatement.get(), int resultCode = sqlite3_bind_text(m_compiledStatement.get(),

View File

@@ -77,12 +77,16 @@ public:
int columnCount() const; int columnCount() const;
void bind(int index, NullValue); void bind(int index, NullValue);
void bind(int index, int fetchValue); void bind(int index, int value);
void bind(int index, long long fetchValue); void bind(int index, long long value);
void bind(int index, double fetchValue); void bind(int index, double value);
void bind(int index, void *pointer); void bind(int index, void *pointer);
void bind(int index, Utils::SmallStringView fetchValue); void bind(int index, Utils::span<int> values);
void bind(int index, const Value &fetchValue); 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, BlobView blobView);
void bind(int index, uint value) { bind(index, static_cast<long long>(value)); } void bind(int index, uint value) { bind(index, static_cast<long long>(value)); }

View File

@@ -54,7 +54,7 @@ DatabaseBackend::~DatabaseBackend()
closeWithoutException(); 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); int resultCode = sqlite3_config(SQLITE_CONFIG_MMAP_SIZE, defaultSize, maximumSize);
checkMmapSizeIsSet(resultCode); checkMmapSizeIsSet(resultCode);

View File

@@ -50,7 +50,7 @@ public:
DatabaseBackend(DatabaseBackend &&) = delete; DatabaseBackend(DatabaseBackend &&) = delete;
DatabaseBackend &operator=(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 activateMultiThreading();
static void activateLogging(); static void activateLogging();
static void initializeSqliteLibrary(); static void initializeSqliteLibrary();

View File

@@ -13,3 +13,8 @@ add_qtc_plugin(ClangFormat
clangformatsettings.cpp clangformatsettings.h clangformatsettings.cpp clangformatsettings.h
clangformatutils.cpp clangformatutils.h clangformatutils.cpp clangformatutils.h
) )
extend_qtc_plugin(ClangFormat
CONDITION UNIX AND NOT APPLE
PROPERTIES LINK_FLAGS "-Wl,--exclude-libs,ALL"
)

View File

@@ -247,7 +247,7 @@ void DocumentClangToolRunner::runNext()
auto [clangIncludeDir, clangVersion] = getClangIncludeDirAndVersion(m_currentRunner.get()); auto [clangIncludeDir, clangVersion] = getClangIncludeDirAndVersion(m_currentRunner.get());
qCDebug(LOG) << Q_FUNC_INFO << m_currentRunner->executable() << clangIncludeDir qCDebug(LOG) << Q_FUNC_INFO << m_currentRunner->executable() << clangIncludeDir
<< clangVersion << m_fileInfo.file; << clangVersion << m_fileInfo.file;
if (clangIncludeDir.isEmpty() || clangVersion.isEmpty() if (m_currentRunner->executable().isEmpty() || clangIncludeDir.isEmpty() || clangVersion.isEmpty()
|| (m_document->isModified() && !m_currentRunner->supportsVFSOverlay())) { || (m_document->isModified() && !m_currentRunner->supportsVFSOverlay())) {
runNext(); runNext();
} else { } else {

View File

@@ -4119,10 +4119,7 @@ void GdbEngine::setupInferior()
if (symbolFile.isEmpty()) { if (symbolFile.isEmpty()) {
showMessage(tr("No symbol file given."), StatusBar); showMessage(tr("No symbol file given."), StatusBar);
callTargetRemote(); callTargetRemote();
return; } else {
}
if (!symbolFile.isEmpty()) {
runCommand({"-file-exec-and-symbols \"" + symbolFile + '"', runCommand({"-file-exec-and-symbols \"" + symbolFile + '"',
CB(handleFileExecAndSymbols)}); CB(handleFileExecAndSymbols)});
} }

View File

@@ -60,14 +60,8 @@ extend_qtc_plugin(Help
webenginehelpviewer.h webenginehelpviewer.h
) )
if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/qlitehtml/litehtml/CMakeLists.txt) find_package(litehtml QUIET)
add_subdirectory(qlitehtml) add_subdirectory(qlitehtml)
else()
find_package(litehtml QUIET)
if (TARGET litehtml)
add_subdirectory(qlitehtml)
endif()
endif()
extend_qtc_plugin(Help extend_qtc_plugin(Help
CONDITION TARGET litehtml AND TARGET qlitehtml CONDITION TARGET litehtml AND TARGET qlitehtml

View File

@@ -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}) set(ORIG_FPIC ${CMAKE_POSITION_INDEPENDENT_CODE})
if (WIN32) if (WIN32)
set(LITEHTML_UTF8 ON CACHE BOOL "") 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) target_compile_options(litehtml PRIVATE -O2)
endif() endif()
endif() endif()
else()
find_package(litehtml REQUIRED)
endif() endif()
add_qtc_library(qlitehtml add_qtc_library(qlitehtml
CONDITION TARGET litehtml
PUBLIC_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR} PUBLIC_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}
DEPENDS Qt5::Widgets litehtml DEPENDS Qt5::Widgets litehtml
PROPERTIES PROPERTIES

View File

@@ -417,6 +417,22 @@ QWidget *MakeStep::createConfigWidget()
return widget; 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 QStringList MakeStep::availableTargets() const
{ {
return m_buildTargetsAspect->allValues(); return m_buildTargetsAspect->allValues();

View File

@@ -78,6 +78,11 @@ public:
Utils::Environment makeEnvironment() const; 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: protected:
void supportDisablingForSubdirs() { m_disablingForSubDirsSupported = true; } void supportDisablingForSubdirs() { m_disablingForSubDirsSupported = true; }
virtual QStringList displayArguments() const; virtual QStringList displayArguments() const;
@@ -87,6 +92,7 @@ private:
QStringList jobArguments() const; QStringList jobArguments() const;
Utils::MultiSelectionAspect *m_buildTargetsAspect = nullptr; Utils::MultiSelectionAspect *m_buildTargetsAspect = nullptr;
QStringList m_availableTargets; // FIXME: Unused, remove in 4.15.
Utils::StringAspect *m_makeCommandAspect = nullptr; Utils::StringAspect *m_makeCommandAspect = nullptr;
Utils::StringAspect *m_userArgumentsAspect = nullptr; Utils::StringAspect *m_userArgumentsAspect = nullptr;
Utils::AspectContainer *m_jobCountContainer = nullptr; Utils::AspectContainer *m_jobCountContainer = nullptr;

View File

@@ -497,6 +497,7 @@ extend_qtc_plugin(QmlDesigner
include/qmlmodelnodefacade.h include/qmlmodelnodefacade.h
include/qmlobjectnode.h include/qmlobjectnode.h
include/qmlstate.h include/qmlstate.h
include/qmlconnections.h
include/qmltimeline.h include/qmltimeline.h
include/qmltimelinekeyframegroup.h include/qmltimelinekeyframegroup.h
include/removebasestateexception.h include/removebasestateexception.h
@@ -578,6 +579,7 @@ extend_qtc_plugin(QmlDesigner
model/qmlmodelnodefacade.cpp model/qmlmodelnodefacade.cpp
model/qmlobjectnode.cpp model/qmlobjectnode.cpp
model/qmlstate.cpp model/qmlstate.cpp
model/qmlconnections.cpp
model/qmltextgenerator.cpp model/qmltextgenerator.h model/qmltextgenerator.cpp model/qmltextgenerator.h
model/qmltimeline.cpp model/qmltimeline.cpp
model/qmltimelinekeyframegroup.cpp model/qmltimelinekeyframegroup.cpp
@@ -620,6 +622,9 @@ extend_qtc_plugin(QmlDesigner
bindingeditordialog.cpp bindingeditordialog.h bindingeditordialog.cpp bindingeditordialog.h
bindingeditorwidget.cpp bindingeditorwidget.h bindingeditorwidget.cpp bindingeditorwidget.h
connectionvisitor.cpp connectionvisitor.h connectionvisitor.cpp connectionvisitor.h
signallist.cpp signallist.h
signallistdialog.cpp signallistdialog.h
signallistdelegate.cpp signallistdelegate.h
) )
extend_qtc_plugin(QmlDesigner extend_qtc_plugin(QmlDesigner

View File

@@ -5,6 +5,9 @@ HEADERS += $$PWD/actioneditordialog.h
HEADERS += $$PWD/bindingeditordialog.h HEADERS += $$PWD/bindingeditordialog.h
HEADERS += $$PWD/bindingeditorwidget.h HEADERS += $$PWD/bindingeditorwidget.h
HEADERS += $$PWD/connectionvisitor.h HEADERS += $$PWD/connectionvisitor.h
HEADERS += $$PWD/signallist.h
HEADERS += $$PWD/signallistdialog.h
HEADERS += $$PWD/signallistdelegate.h
SOURCES += $$PWD/bindingeditor.cpp SOURCES += $$PWD/bindingeditor.cpp
SOURCES += $$PWD/actioneditor.cpp SOURCES += $$PWD/actioneditor.cpp
@@ -13,3 +16,6 @@ SOURCES += $$PWD/actioneditordialog.cpp
SOURCES += $$PWD/bindingeditordialog.cpp SOURCES += $$PWD/bindingeditordialog.cpp
SOURCES += $$PWD/bindingeditorwidget.cpp SOURCES += $$PWD/bindingeditorwidget.cpp
SOURCES += $$PWD/connectionvisitor.cpp SOURCES += $$PWD/connectionvisitor.cpp
SOURCES += $$PWD/signallist.cpp
SOURCES += $$PWD/signallistdialog.cpp
SOURCES += $$PWD/signallistdelegate.cpp

View 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

View 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

View File

@@ -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

View File

@@ -0,0 +1,54 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <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

View File

@@ -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

View File

@@ -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

View File

@@ -53,6 +53,11 @@ public:
LowestPriority = ComponentCoreConstants::priorityLast LowestPriority = ComponentCoreConstants::priorityLast
}; };
enum class TargetView {
Undefined,
ConnectionEditor
};
virtual ~ActionInterface() = default; virtual ~ActionInterface() = default;
virtual QAction *action() const = 0; virtual QAction *action() const = 0;
@@ -61,6 +66,7 @@ public:
virtual int priority() const = 0; virtual int priority() const = 0;
virtual Type type() const = 0; virtual Type type() const = 0;
virtual void currentContextChanged(const SelectionContext &selectionState) = 0; virtual void currentContextChanged(const SelectionContext &selectionState) = 0;
virtual TargetView targetView() const { return TargetView::Undefined; }
}; };

View File

@@ -89,6 +89,8 @@ const char fitRootToScreenCommandId[] = "FitRootToScreen";
const char fitSelectionToScreenCommandId[] = "FitSelectionToScreen"; const char fitSelectionToScreenCommandId[] = "FitSelectionToScreen";
const char editAnnotationCommandId[] = "EditAnnotation"; const char editAnnotationCommandId[] = "EditAnnotation";
const char openSignalDialogCommandId[] = "OpenSignalDialog";
const char selectionCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Selection"); const char selectionCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Selection");
const char flowConnectionCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Connect"); const char flowConnectionCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Connect");
const char selectEffectDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Select Effect"); 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 moveToComponentDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Move Component into Separate File");
const char editAnnotationDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Edit Annotation"); 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 setIdDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Set Id");
const char resetZDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Reset z Property"); const char resetZDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Reset z Property");

View File

@@ -564,6 +564,7 @@ const char yProperty[] = "y";
const char zProperty[] = "z"; const char zProperty[] = "z";
const char widthProperty[] = "width"; const char widthProperty[] = "width";
const char heightProperty[] = "height"; const char heightProperty[] = "height";
const char triggerSlot[] = "trigger";
using namespace SelectionContextFunctors; using namespace SelectionContextFunctors;
@@ -644,6 +645,14 @@ bool selectionNotEmptyAndHasXorYProperty(const SelectionContext &context)
&& selectionHasProperty1or2(context, xProperty, yProperty); && selectionHasProperty1or2(context, xProperty, yProperty);
} }
bool singleSelectionAndHasSlotTrigger(const SelectionContext &context)
{
if (!singleSelection(context))
return false;
return selectionHasSlot(context, triggerSlot);
}
bool singleSelectionAndInQtQuickLayout(const SelectionContext &context) bool singleSelectionAndInQtQuickLayout(const SelectionContext &context)
{ {
if (!singleSelection(context)) if (!singleSelection(context))
@@ -1384,6 +1393,16 @@ void DesignerActionManager::createDefaultDesignerActions()
addDesignerAction(new ChangeStyleAction()); addDesignerAction(new ChangeStyleAction());
addDesignerAction(new EditListModelAction); addDesignerAction(new EditListModelAction);
addDesignerAction(new ModelNodeContextMenuAction(
openSignalDialogCommandId,
openSignalDialogDisplayName,
{},
rootCategory,
QKeySequence(),
66,
&openSignalDialog,
&singleSelectionAndHasSlotTrigger));
} }
void DesignerActionManager::createDefaultAddResourceHandler() void DesignerActionManager::createDefaultAddResourceHandler()
@@ -1459,6 +1478,16 @@ void DesignerActionManager::addCreatorCommand(Core::Command *command, const QByt
addDesignerAction(new CommandAction(command, category, priority, overrideIcon)); 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 QList<ActionInterface* > DesignerActionManager::designerActions() const
{ {
return Utils::transform(m_designerActions, [](const QSharedPointer<ActionInterface> &pointer) { return Utils::transform(m_designerActions, [](const QSharedPointer<ActionInterface> &pointer) {

View File

@@ -106,6 +106,9 @@ public:
void addDesignerAction(ActionInterface *newAction); void addDesignerAction(ActionInterface *newAction);
void addCreatorCommand(Core::Command *command, const QByteArray &category, int priority, void addCreatorCommand(Core::Command *command, const QByteArray &category, int priority,
const QIcon &overrideIcon = QIcon()); const QIcon &overrideIcon = QIcon());
QList<QSharedPointer<ActionInterface>> actionsForTargetView(const ActionInterface::TargetView &target);
QList<ActionInterface* > designerActions() const; QList<ActionInterface* > designerActions() const;
void createDefaultDesignerActions(); void createDefaultDesignerActions();

View File

@@ -30,6 +30,7 @@
#include "abstractactiongroup.h" #include "abstractactiongroup.h"
#include "qmlitemnode.h" #include "qmlitemnode.h"
#include <qmldesignerplugin.h> #include <qmldesignerplugin.h>
#include <nodemetainfo.h>
#include <coreplugin/actionmanager/command.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) 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))) if (modelNode.hasProperty(PropertyName(property)))
return true; return true;
return false; 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) inline bool singleSelectedItem(const SelectionContext &selectionState)
{ {
QmlItemNode itemNode(selectionState.currentSingleSelectedNode()); QmlItemNode itemNode(selectionState.currentSingleSelectedNode());
@@ -94,7 +107,6 @@ inline bool singleSelectedItem(const SelectionContext &selectionState)
bool selectionHasSameParent(const SelectionContext &selectionState); bool selectionHasSameParent(const SelectionContext &selectionState);
bool selectionIsComponent(const SelectionContext &selectionState); bool selectionIsComponent(const SelectionContext &selectionState);
bool selectionIsComponent(const SelectionContext &selectionState);
bool singleSelectionItemIsAnchored(const SelectionContext &selectionState); bool singleSelectionItemIsAnchored(const SelectionContext &selectionState);
bool singleSelectionItemIsNotAnchored(const SelectionContext &selectionState); bool singleSelectionItemIsNotAnchored(const SelectionContext &selectionState);

View File

@@ -87,6 +87,8 @@
#include <functional> #include <functional>
#include <cmath> #include <cmath>
#include <bindingeditor/signallist.h>
namespace QmlDesigner { namespace QmlDesigner {
const PropertyName auxDataString("anchors_"); const PropertyName auxDataString("anchors_");
@@ -1548,6 +1550,14 @@ QVariant previewImageDataForImageNode(const ModelNode &modelNode)
return {}; return {};
} }
void openSignalDialog(const SelectionContext &selectionContext)
{
if (!selectionContext.view() || !selectionContext.hasSingleSelectedModelNode())
return;
SignalList::showWidget(selectionContext.currentSingleSelectedNode());
}
} // namespace ModelNodeOperations } // namespace ModelNodeOperations
} //QmlDesigner } //QmlDesigner

View File

@@ -88,6 +88,8 @@ void mergeWithTemplate(const SelectionContext &selectionContext);
void removeGroup(const SelectionContext &selectionContext); void removeGroup(const SelectionContext &selectionContext);
void editAnnotation(const SelectionContext &selectionContext); void editAnnotation(const SelectionContext &selectionContext);
void openSignalDialog(const SelectionContext &selectionContext);
// ModelNodePreviewImageOperations // ModelNodePreviewImageOperations
QVariant previewImageDataForGenericNode(const ModelNode &modelNode); QVariant previewImageDataForGenericNode(const ModelNode &modelNode);
QVariant previewImageDataForImageNode(const ModelNode &modelNode); QVariant previewImageDataForImageNode(const ModelNode &modelNode);

View File

@@ -49,9 +49,9 @@ namespace {
QStringList propertyNameListToStringList(const QmlDesigner::PropertyNameList &propertyNameList) QStringList propertyNameListToStringList(const QmlDesigner::PropertyNameList &propertyNameList)
{ {
QStringList stringList; QStringList stringList;
for (const QmlDesigner::PropertyName &propertyName : propertyNameList) { for (const QmlDesigner::PropertyName &propertyName : propertyNameList)
stringList << QString::fromUtf8(propertyName); stringList << QString::fromUtf8(propertyName);
}
stringList.removeDuplicates(); stringList.removeDuplicates();
return stringList; return stringList;
} }

View File

@@ -172,6 +172,19 @@ void ConnectionViewWidget::contextMenuEvent(QContextMenuEvent *event)
m_connectionEditor->updateWindowName(); 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()); menu.exec(event->globalPos());
} }
break; break;

View File

@@ -888,6 +888,7 @@ public:
, labelFlags(Qt::AlignHCenter | Qt::AlignVCenter | Qt::TextDontClip) , labelFlags(Qt::AlignHCenter | Qt::AlignVCenter | Qt::TextDontClip)
, labelFlipSide(false) , labelFlipSide(false)
, hitTesting(hitTest) , hitTesting(hitTest)
, isSelected(false)
, events() , events()
{ {
// width // width
@@ -1416,37 +1417,7 @@ void FormEditorTransitionItem::updateGeometry()
overallBoundingRect = overallBoundingRect.united(connection.fromRect); overallBoundingRect = overallBoundingRect.united(connection.fromRect);
overallBoundingRect = overallBoundingRect.united(connection.toRect); overallBoundingRect = overallBoundingRect.united(connection.toRect);
overallBoundingRect = overallBoundingRect.united(pathBoundingRect); overallBoundingRect = overallBoundingRect.united(pathBoundingRect);
drawLabels(&localPainter, connection);
// 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);
}
} }
} }
@@ -1461,7 +1432,7 @@ QPointF FormEditorTransitionItem::instancePosition() const
return qmlItemNode().flowPosition(); return qmlItemNode().flowPosition();
} }
static void drawLabel(QPainter *painter, const Connection &connection) void FormEditorTransitionItem::drawLabels(QPainter *painter, const Connection &connection)
{ {
// draw label with event ids // draw label with event ids
if (connection.config.isSelected && !connection.config.events.isEmpty()) 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; qreal offset = connection.config.labelOffset;
QStringList events = connection.config.events.split(','); QStringList events = connection.config.events.split(',');
int fontSize = connection.config.fontSize; int fontSize = connection.config.fontSize;
QString output = events[0].trimmed(); QString outputText;
qreal minWidth = offset * 12; qreal minWidth = offset * 12.0;
int letterWidth = fontSize * 0.6; // assumption on max letter length qreal letterWidth = fontSize * 0.6; // assumption on max letter width
if (minWidth < output.size() * letterWidth) minWidth = output.size() * letterWidth;
int eventCount = events.size(); int eventCount = events.size();
for (int i = 1; i < eventCount; ++i) std::for_each(events.begin(), events.end(), [&](auto id) {
{ outputText.append(id.trimmed());
output.append('\n'); outputText.append('\n');
QString id = events[i].trimmed(); if (minWidth < id.size() * letterWidth) minWidth = id.size() * letterWidth;
output.append(id); });
if (minWidth < id.size() * letterWidth) minWidth = id.size() * letterWidth;
}
const QPointF pos = connection.path.pointAtPercent(0.0); const QPointF pos = connection.path.pointAtPercent(0.0);
painter->save(); painter->save();
painter->setBrush(QColor(70, 70, 70, 200)); painter->setBrush(QColor(70, 70, 70, 200));
painter->setPen(Qt::lightGray); painter->setPen(Qt::lightGray);
painter->drawRoundedRect(pos.x(), pos.y() + offset, minWidth, 1.5 * fontSize * eventCount + offset * 4.0, offset / 2.0, offset / 2.0);
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.0 * offset, minWidth, offset * 2.0, Qt::AlignHCenter, QObject::tr("Connected Events"));
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.0 * offset, pos.x() + minWidth - offset, pos.y() + offset * 4.0);
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.0 * offset, minWidth - offset, 1.5 * fontSize * eventCount, Qt::AlignLeft, outputText);
painter->drawText(pos.x() + offset, pos.y() + 4 * offset, minWidth - offset, 1.5 * fontSize * eventCount, Qt::AlignLeft, output);
painter->restore(); painter->restore();
} }
if (connection.config.label.isEmpty()) if (connection.config.label.isEmpty())
@@ -1534,7 +1501,7 @@ static void drawArrow(QPainter *painter,
painter->restore(); 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 arrowLength = 4 * connection.config.adjustedWidth;
const int arrowWidth = 8 * 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); painter->drawEllipse(connection.start, arrowLength / 3, arrowLength / 3);
} }
// Draw label // Draw labels
drawLabel(painter, connection); drawLabels(painter, connection);
painter->restore(); painter->restore();
} }

View File

@@ -40,6 +40,7 @@ namespace QmlDesigner {
class FormEditorScene; class FormEditorScene;
class FormEditorView; class FormEditorView;
class AbstractFormEditorTool; class AbstractFormEditorTool;
class Connection;
namespace Internal { namespace Internal {
class GraphicItemResizer; class GraphicItemResizer;
@@ -197,11 +198,12 @@ public:
QPointF instancePosition() const override; QPointF instancePosition() const override;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;
bool flowHitTest(const QPointF &point) const override; bool flowHitTest(const QPointF &point) const override;
protected: protected:
FormEditorTransitionItem(const QmlItemNode &qmlItemNode, FormEditorScene *scene) FormEditorTransitionItem(const QmlItemNode &qmlItemNode, FormEditorScene *scene)
: FormEditorItem(qmlItemNode, scene) : FormEditorItem(qmlItemNode, scene)
{} {}
void paintConnection(QPainter *painter, const Connection &connection);
void drawLabels(QPainter *painter, const Connection &connection);
private: private:
mutable bool m_hitTest = false; mutable bool m_hitTest = false;
}; };

View File

@@ -133,8 +133,6 @@ static QRect drawText(QPainter *painter,
int iconOffset) int iconOffset)
{ {
QString displayString = modelIndex.data(Qt::DisplayRole).toString(); QString displayString = modelIndex.data(Qt::DisplayRole).toString();
QPoint displayStringOffset;
int width = 0;
// Check text length does not exceed available space // Check text length does not exceed available space
const int extraSpace = 12 + iconOffset; const int extraSpace = 12 + iconOffset;
@@ -142,10 +140,8 @@ static QRect drawText(QPainter *painter,
displayString = styleOption.fontMetrics.elidedText(displayString, displayString = styleOption.fontMetrics.elidedText(displayString,
Qt::ElideMiddle, Qt::ElideMiddle,
styleOption.rect.width() - extraSpace); styleOption.rect.width() - extraSpace);
displayStringOffset = QPoint(5 + iconOffset, -5 - delegateMargin); const QPoint displayStringOffset = QPoint(5 + iconOffset, -5 - delegateMargin);
const int width = styleOption.fontMetrics.horizontalAdvance(displayString);
width = styleOption.fontMetrics.horizontalAdvance(displayString);
const QPoint textPosition = styleOption.rect.bottomLeft() + displayStringOffset; const QPoint textPosition = styleOption.rect.bottomLeft() + displayStringOffset;
painter->drawText(textPosition, displayString); painter->drawText(textPosition, displayString);

View File

@@ -69,6 +69,7 @@ SOURCES += $$PWD/model/abstractview.cpp \
$$PWD/model/qmlmodelnodefacade.cpp \ $$PWD/model/qmlmodelnodefacade.cpp \
$$PWD/model/qmlobjectnode.cpp \ $$PWD/model/qmlobjectnode.cpp \
$$PWD/model/qmlanchors.cpp \ $$PWD/model/qmlanchors.cpp \
$$PWD/model/qmlconnections.cpp \
$$PWD/rewritertransaction.cpp \ $$PWD/rewritertransaction.cpp \
$$PWD/model/rewriteaction.cpp \ $$PWD/model/rewriteaction.cpp \
$$PWD/model/modelnodepositionstorage.cpp \ $$PWD/model/modelnodepositionstorage.cpp \
@@ -151,6 +152,7 @@ HEADERS += $$PWD/include/qmldesignercorelib_global.h \
$$PWD/include/forwardview.h \ $$PWD/include/forwardview.h \
$$PWD/include/qmlobjectnode.h \ $$PWD/include/qmlobjectnode.h \
$$PWD/include/qmlanchors.h \ $$PWD/include/qmlanchors.h \
$$PWD/include/qmlconnections.h \
$$PWD/rewritertransaction.h \ $$PWD/rewritertransaction.h \
$$PWD/model/rewriteaction.h \ $$PWD/model/rewriteaction.h \
$$PWD/include/modelnodepositionstorage.h \ $$PWD/include/modelnodepositionstorage.h \

View File

@@ -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

View File

@@ -43,6 +43,9 @@ public:
SignalHandlerProperty(); SignalHandlerProperty();
SignalHandlerProperty(const SignalHandlerProperty &property, AbstractView *view); SignalHandlerProperty(const SignalHandlerProperty &property, AbstractView *view);
static PropertyName prefixAdded(const PropertyName &propertyName);
static PropertyName prefixRemoved(const PropertyName &propertyName);
protected: protected:
SignalHandlerProperty(const PropertyName &propertyName, const Internal::InternalNodePointer &internalNode, Model* model, AbstractView *view); SignalHandlerProperty(const PropertyName &propertyName, const Internal::InternalNodePointer &internalNode, Model* model, AbstractView *view);
}; };

View File

@@ -82,7 +82,7 @@ using PropertyInfo = QPair<PropertyName, TypeName>;
QVector<PropertyInfo> getObjectTypes(const ObjectValue *ov, const ContextPtr &context, bool local = false, int rec = 0); 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"; TypeName type = "unknown";
@@ -295,7 +295,7 @@ public:
const TypeName type = resolveTypeName(ref, m_context, dotProperties); const TypeName type = resolveTypeName(ref, m_context, dotProperties);
m_properties.append({propertyName, type}); m_properties.append({propertyName, type});
if (!dotProperties.isEmpty()) { if (!dotProperties.isEmpty()) {
foreach (const PropertyInfo &propertyInfo, dotProperties) { for (const PropertyInfo &propertyInfo : qAsConst(dotProperties)) {
PropertyName dotName = propertyInfo.first; PropertyName dotName = propertyInfo.first;
TypeName type = propertyInfo.second; TypeName type = propertyInfo.second;
dotName = propertyName + '.' + dotName; dotName = propertyName + '.' + dotName;
@@ -303,7 +303,6 @@ public:
} }
} }
} else { } else {
if (const CppComponentValue * cppComponentValue = value_cast<CppComponentValue>(value)) { if (const CppComponentValue * cppComponentValue = value_cast<CppComponentValue>(value)) {
TypeName qualifiedTypeName = qualifiedTypeNameForContext(cppComponentValue, TypeName qualifiedTypeName = qualifiedTypeNameForContext(cppComponentValue,
m_context->viewerContext(), *m_context->snapshot().importDependencies()).toUtf8(); m_context->viewerContext(), *m_context->snapshot().importDependencies()).toUtf8();
@@ -311,13 +310,13 @@ public:
} else { } else {
TypeId typeId; TypeId typeId;
TypeName typeName = typeId(value).toUtf8(); TypeName typeName = typeId(value).toUtf8();
if (typeName == "number") {
if (value->asIntValue()) { if (typeName == "Function")
typeName = "int"; return processSlot(name, value);
} else {
typeName = "real"; if (typeName == "number")
} typeName = value->asIntValue() ? "int" : "real";
}
m_properties.append({propertyName, typeName}); m_properties.append({propertyName, typeName});
} }
} }
@@ -488,7 +487,7 @@ PropertyNameList getSignals(const ObjectValue *objectValue, const ContextPtr &co
QList<const ObjectValue *> objects = prototypeIterator.all(); QList<const ObjectValue *> objects = prototypeIterator.all();
if (!local) { if (!local) {
foreach (const ObjectValue *prototype, objects) for (const ObjectValue *prototype : objects)
signalList.append(getSignals(prototype, context, true)); signalList.append(getSignals(prototype, context, true));
} }
@@ -507,6 +506,9 @@ PropertyNameList getSlots(const ObjectValue *objectValue, const ContextPtr &cont
PropertyMemberProcessor processor(context); PropertyMemberProcessor processor(context);
objectValue->processMembers(&processor); objectValue->processMembers(&processor);
if (const ASTObjectValue *astObjectValue = objectValue->asAstObjectValue())
astObjectValue->processMembers(&processor);
slotList.append(processor.slotList()); slotList.append(processor.slotList());
PrototypeIterator prototypeIterator(objectValue, context); PrototypeIterator prototypeIterator(objectValue, context);
@@ -534,6 +536,7 @@ QVector<PropertyInfo> getObjectTypes(const ObjectValue *objectValue, const Conte
PropertyMemberProcessor processor(context); PropertyMemberProcessor processor(context);
objectValue->processMembers(&processor); objectValue->processMembers(&processor);
const auto props = processor.properties(); const auto props = processor.properties();
for (const PropertyInfo &property : props) { for (const PropertyInfo &property : props) {

View File

@@ -0,0 +1,130 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#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

View File

@@ -40,13 +40,11 @@ SignalHandlerProperty::SignalHandlerProperty(const SignalHandlerProperty &proper
{ {
} }
SignalHandlerProperty::SignalHandlerProperty(const PropertyName &propertyName, const Internal::InternalNodePointer &internalNode, Model* model, AbstractView *view) SignalHandlerProperty::SignalHandlerProperty(const PropertyName &propertyName, const Internal::InternalNodePointer &internalNode, Model* model, AbstractView *view)
: AbstractProperty(propertyName, internalNode, model, view) : AbstractProperty(propertyName, internalNode, model, view)
{ {
} }
void SignalHandlerProperty::setSource(const QString &source) void SignalHandlerProperty::setSource(const QString &source)
{ {
Internal::WriteLocker locker(model()); Internal::WriteLocker locker(model());
@@ -83,4 +81,30 @@ QString SignalHandlerProperty::source() const
return QString(); 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 } // namespace QmlDesigner

View File

@@ -302,6 +302,7 @@ Project {
"include/qmlmodelnodefacade.h", "include/qmlmodelnodefacade.h",
"include/qmlobjectnode.h", "include/qmlobjectnode.h",
"include/qmlstate.h", "include/qmlstate.h",
"include/qmlconnections.h",
"include/removebasestateexception.h", "include/removebasestateexception.h",
"include/documentmessage.h", "include/documentmessage.h",
"include/rewriterview.h", "include/rewriterview.h",
@@ -391,6 +392,7 @@ Project {
"model/qmlmodelnodefacade.cpp", "model/qmlmodelnodefacade.cpp",
"model/qmlobjectnode.cpp", "model/qmlobjectnode.cpp",
"model/qmlstate.cpp", "model/qmlstate.cpp",
"model/qmlconnections.cpp",
"model/qmltextgenerator.cpp", "model/qmltextgenerator.cpp",
"model/qmltextgenerator.h", "model/qmltextgenerator.h",
"model/rewriteaction.cpp", "model/rewriteaction.cpp",
@@ -739,6 +741,12 @@ Project {
"bindingeditor/bindingeditorwidget.h", "bindingeditor/bindingeditorwidget.h",
"bindingeditor/connectionvisitor.cpp", "bindingeditor/connectionvisitor.cpp",
"bindingeditor/connectionvisitor.h", "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.cpp",
"colortool/colortool.h", "colortool/colortool.h",
"connectioneditor/addnewbackenddialog.h", "connectioneditor/addnewbackenddialog.h",

View File

@@ -70,6 +70,7 @@
#include <texteditor/texteditoractionhandler.h> #include <texteditor/texteditoractionhandler.h>
#include <texteditor/textmark.h> #include <texteditor/textmark.h>
#include <utils/algorithm.h>
#include <utils/delegates.h> #include <utils/delegates.h>
#include <utils/changeset.h> #include <utils/changeset.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
@@ -373,8 +374,13 @@ void QmlJSEditorWidget::updateUses()
return; return;
QList<QTextEdit::ExtraSelection> selections; QList<QTextEdit::ExtraSelection> selections;
foreach (const SourceLocation &loc, QList<SourceLocation> locations
m_qmlJsEditorDocument->semanticInfo().idLocations.value(wordUnderCursor())) { = 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()) if (! loc.isValid())
continue; continue;

View File

@@ -258,6 +258,62 @@ TEST_F(SqliteStatement, BindPointer)
ASSERT_THAT(statement.fetchIntValue(0), 1); 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) TEST_F(SqliteStatement, BindBlob)
{ {
SqliteTestStatement statement("WITH T(blob) AS (VALUES (?)) SELECT blob FROM T", database); 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)); 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) TEST_F(SqliteStatement, WriteNullValues)
{ {
WriteStatement statement("UPDATE test SET name=?, number=? WHERE rowid=?", database); WriteStatement statement("UPDATE test SET name=?, number=? WHERE rowid=?", database);