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_PLUGIN_PATH "${_IDE_OUTPUT_PATH}/PlugIns")
set(_IDE_LIBRARY_BASE_PATH "Frameworks")
set(_IDE_LIBRARY_PATH "${_IDE_OUTPUT_PATH}/Frameworks")
set(_IDE_LIBRARY_PATH "${_IDE_OUTPUT_PATH}/${_IDE_LIBRARY_BASE_PATH}")
set(_IDE_PLUGIN_PATH "${_IDE_OUTPUT_PATH}/PlugIns")
set(_IDE_LIBEXEC_PATH "${_IDE_OUTPUT_PATH}/Resources/libexec")
set(_IDE_DATA_PATH "${_IDE_OUTPUT_PATH}/Resources")
set(_IDE_DOC_PATH "${_IDE_OUTPUT_PATH}/Resources/doc")
set(_IDE_BIN_PATH "${_IDE_OUTPUT_PATH}/MacOS")
set(QT_DEST_PLUGIN_PATH "${_IDE_PLUGIN_PATH}")
set(QT_DEST_QML_PATH "${_IDE_DATA_PATH}/../Imports/qtquick2")
else ()
elseif(WIN32)
set(_IDE_APP_PATH "bin")
set(_IDE_APP_TARGET "${IDE_ID}")
set(_IDE_LIBRARY_BASE_PATH "lib")
set(_IDE_LIBRARY_PATH "lib/qtcreator")
set(_IDE_PLUGIN_PATH "lib/qtcreator/plugins")
if (WIN32)
set(_IDE_LIBEXEC_PATH "bin")
set(QT_DEST_PLUGIN_PATH "bin/plugins")
set(QT_DEST_QML_PATH "bin/qml")
else ()
set(_IDE_LIBEXEC_PATH "libexec/qtcreator")
set(QT_DEST_PLUGIN_PATH "lib/Qt/plugins")
set(QT_DEST_QML_PATH "lib/Qt/qml")
endif ()
set(_IDE_LIBRARY_PATH "${_IDE_LIBRARY_BASE_PATH}/qtcreator")
set(_IDE_PLUGIN_PATH "${_IDE_LIBRARY_BASE_PATH}/qtcreator/plugins")
set(_IDE_LIBEXEC_PATH "bin")
set(_IDE_DATA_PATH "share/qtcreator")
set(_IDE_DOC_PATH "share/doc/qtcreator")
set(_IDE_BIN_PATH "bin")
else ()
include(GNUInstallDirs)
set(_IDE_APP_PATH "${CMAKE_INSTALL_BINDIR}")
set(_IDE_APP_TARGET "${IDE_ID}")
set(_IDE_LIBRARY_BASE_PATH "${CMAKE_INSTALL_LIBDIR}")
set(_IDE_LIBRARY_PATH "${_IDE_LIBRARY_BASE_PATH}/qtcreator")
set(_IDE_PLUGIN_PATH "${_IDE_LIBRARY_BASE_PATH}/qtcreator/plugins")
set(_IDE_LIBEXEC_PATH "${CMAKE_INSTALL_LIBEXECDIR}/qtcreator")
set(_IDE_DATA_PATH "${CMAKE_INSTALL_DATAROOTDIR}/qtcreator")
set(_IDE_DOC_PATH "${CMAKE_INSTALL_DATAROOTDIR}/doc/qtcreator")
set(_IDE_BIN_PATH "${CMAKE_INSTALL_BINDIR}")
endif ()
file(RELATIVE_PATH _PLUGIN_TO_LIB "/${_IDE_PLUGIN_PATH}" "/${_IDE_LIBRARY_PATH}")

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
code editor.
\image qtcreator-diagnostics-configuration.png "Diagnostics Configuration dialog"
\image qtcreator-clang-tools-diagnostics-configuration.png "Diagnostics Configuration dialog"
\li In the \uicontrol {Clang-Tidy Checks} tab, select
\uicontrol {Select Checks} to select the checks to perform.

View File

@@ -138,7 +138,10 @@
edit the value for the \uicontrol {Do not index files greater than}
check box. To index all files, deselect the check box.
\li Select \uicontrol Manage to specify the Clang checks to perform.
\li The \uicontrol {Diagnostic Configuration} field shows the Clang
checks to perform. Click the value of the field to open the
\uicontrol {Diagnostic Configurations} dialog, where you can
select and edit the checks to perform.
\image qtcreator-diagnostics-configuration.png
@@ -146,26 +149,18 @@
\section1 Clang Checks
The predefined configurations perform the following Clang checks:
In addition to using the built-in checks, you can select \uicontrol Copy to
create copies of them and edit the copies to fit your needs.
\list
\uicontrol {Build-system warnings} displays warnings as specified
by the build system.
\li \uicontrol {Clang-only pedantic checks} uses the \c -Wpendantic
option that performs checks as required by strict ISO C and ISO C++.
\uicontrol {Checks for questionable constructs} combines the \c -Wall and
\c -Wextra checks for easily avoidable questionable constructions and some
additional issues.
\li \uicontrol {Clang-only checks for questionable constructs} combines
the \c -Wall and \c -Wextra checks for easily avoidable questionable
constructions and some additional issues.
\li \uicontrol {Clang-only checks for almost everything} uses the
\c -Weverything option with negative options to suppress some
warnings.
\endlist
You can edit the predefined configurations to perform particular checks
beginning with \c -W. Each of these checks also has a negative version
that begins with \c -Wno.
Clang checks begin with \c -W. Each check also has a negative version that
begins with \c -Wno.
Keep in mind that some options turn on other options. For more information,
see \l{https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html}

View File

@@ -293,6 +293,13 @@
\image qtquickcontrols2-button-flat.gif "Flat button"
\if definded(qtdesignstudio)
To create a button that contains an icon, use the wizard template to
\l{Creating Custom Controls}{create a custom button} and drag-and-drop
the icon to the button background item. For an example of using the
wizard template, see \l{Creating a Push Button}.
\endif
\section2 Delay Button
\image qtquickcontrols2-delaybutton.gif "Delay button"

View File

@@ -125,6 +125,7 @@
\li \l {Lists and Other Data Models}
\if defined(qtdesignstudio)
\li \l {2D Effects}
\li \l {Logic Helpers}
\endif
\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{Lists and Other Data Models}
\li \l{2D Effects}
\li \l{Logic Helpers}
\li \l{Creating Buttons}
\li \l{Creating Scalable Buttons and Borders}
\endlist

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
\previouspage quick-data-models.html
\nextpage quick-buttons.html
\nextpage quick-logic-helpers.html
\title 2D Effects

View File

@@ -1,7 +1,15 @@
NOTE:
While the primary intention of this pretty printing implementation is
to provide what Qt Creator needs, it can be used in a plain GDB and LLDB
session, too.
to provide what Qt Creator needs, it can sometimes be used in plain
GDB and LLDB sessions, too.
This features is provided as-is. There is no guarantee this works in any
way outside Qt Creator, this setup is not officially supported.
Bugreports or (better!) patches are welcome.
With

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>
<name>Application</name>
<message>

View File

@@ -41,7 +41,7 @@ list(APPEND CMAKE_MODULE_PATH \${CMAKE_CURRENT_LIST_DIR})
include(CMakeFindDependencyMacro)
find_dependency(Qt5 ${IDE_QT_VERSION_MIN}
COMPONENTS Concurrent Core Network PrintSupport Qml Quick QuickWidgets Sql REQUIRED
COMPONENTS Concurrent Core Gui Widgets Core5Compat Network PrintSupport Qml Quick QuickWidgets Sql REQUIRED
)
if (NOT IDE_VERSION)

View File

@@ -57,21 +57,32 @@ SQLITE_EXTENSION_INIT1
#include <assert.h>
#include <string.h>
/* Allowed values for the mFlags parameter to sqlite3_carray_bind().
** Must exactly match the definitions in carray.h.
*/
#define CARRAY_INT32 0 /* Data is 32-bit signed integers */
#define CARRAY_INT64 1 /* Data is 64-bit signed integers */
#define CARRAY_DOUBLE 2 /* Data is doubles */
#define CARRAY_TEXT 3 /* Data is char* */
#ifndef SQLITE_OMIT_VIRTUALTABLE
/*
** Allowed datatypes
*/
#define CARRAY_INT32 0
#define CARRAY_INT64 1
#define CARRAY_DOUBLE 2
#define CARRAY_TEXT 3
/*
** Names of types
** Names of allowed datatypes
*/
static const char *azType[] = { "int32", "int64", "double", "char*" };
/*
** Structure used to hold the sqlite3_carray_bind() information
*/
typedef struct carray_bind carray_bind;
struct carray_bind {
void *aData; /* The data */
int nData; /* Number of elements */
int mFlags; /* Control flags */
void (*xDel)(void*); /* Destructor for aData */
};
/* carray_cursor is a subclass of sqlite3_vtab_cursor which will
** serve as the underlying representation of a cursor that scans
@@ -136,16 +147,13 @@ static int carrayDisconnect(sqlite3_vtab *pVtab){
/*
** Constructor for a new carray_cursor object.
*/
static int carrayOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor)
{
carray_cursor *pCur;
pCur = sqlite3_malloc(sizeof(*pCur));
if (pCur == 0)
return SQLITE_NOMEM;
memset(pCur, 0, sizeof(*pCur));
*ppCursor = &pCur->base;
return SQLITE_OK;
static int carrayOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
carray_cursor *pCur;
pCur = sqlite3_malloc( sizeof(*pCur) );
if( pCur==0 ) return SQLITE_NOMEM;
memset(pCur, 0, sizeof(*pCur));
*ppCursor = &pCur->base;
return SQLITE_OK;
}
/*
@@ -242,28 +250,39 @@ static int carrayFilter(
int argc, sqlite3_value **argv
){
carray_cursor *pCur = (carray_cursor *)pVtabCursor;
if( idxNum ){
pCur->pPtr = sqlite3_value_pointer(argv[0], "carray");
pCur->iCnt = pCur->pPtr ? sqlite3_value_int64(argv[1]) : 0;
if( idxNum<3 ){
pCur->eType = CARRAY_INT32;
}else{
unsigned char i;
const char *zType = (const char*)sqlite3_value_text(argv[2]);
for(i=0; i<sizeof(azType)/sizeof(azType[0]); i++){
if( sqlite3_stricmp(zType, azType[i])==0 ) break;
}
if( i>=sizeof(azType)/sizeof(azType[0]) ){
pVtabCursor->pVtab->zErrMsg = sqlite3_mprintf(
"unknown datatype: %Q", zType);
return SQLITE_ERROR;
}else{
pCur->eType = i;
}
pCur->pPtr = 0;
pCur->iCnt = 0;
switch( idxNum ){
case 1: {
carray_bind *pBind = sqlite3_value_pointer(argv[0], "carray-bind");
if( pBind==0 ) break;
pCur->pPtr = pBind->aData;
pCur->iCnt = pBind->nData;
pCur->eType = pBind->mFlags & 0x03;
break;
}
case 2:
case 3: {
pCur->pPtr = sqlite3_value_pointer(argv[0], "carray");
pCur->iCnt = pCur->pPtr ? sqlite3_value_int64(argv[1]) : 0;
if( idxNum<3 ){
pCur->eType = CARRAY_INT32;
}else{
unsigned char i;
const char *zType = (const char*)sqlite3_value_text(argv[2]);
for(i=0; i<sizeof(azType)/sizeof(azType[0]); i++){
if( sqlite3_stricmp(zType, azType[i])==0 ) break;
}
if( i>=sizeof(azType)/sizeof(azType[0]) ){
pVtabCursor->pVtab->zErrMsg = sqlite3_mprintf(
"unknown datatype: %Q", zType);
return SQLITE_ERROR;
}else{
pCur->eType = i;
}
}
break;
}
}else{
pCur->pPtr = 0;
pCur->iCnt = 0;
}
pCur->iRowid = 1;
return SQLITE_OK;
@@ -278,9 +297,16 @@ static int carrayFilter(
** In this implementation idxNum is used to represent the
** query plan. idxStr is unused.
**
** idxNum is 2 if the pointer= and count= constraints exist,
** 3 if the ctype= constraint also exists, and is 0 otherwise.
** If idxNum is 0, then carray becomes an empty table.
** idxNum is:
**
** 1 If only the pointer= constraint exists. In this case, the
** parameter must be bound using sqlite3_carray_bind().
**
** 2 if the pointer= and count= constraints exist.
**
** 3 if the ctype= constraint also exists.
**
** idxNum is 0 otherwise and carray becomes an empty table.
*/
static int carrayBestIndex(
sqlite3_vtab *tab,
@@ -308,18 +334,21 @@ static int carrayBestIndex(
break;
}
}
if( ptrIdx>=0 && cntIdx>=0 ){
if( ptrIdx>=0 ){
pIdxInfo->aConstraintUsage[ptrIdx].argvIndex = 1;
pIdxInfo->aConstraintUsage[ptrIdx].omit = 1;
pIdxInfo->aConstraintUsage[cntIdx].argvIndex = 2;
pIdxInfo->aConstraintUsage[cntIdx].omit = 1;
pIdxInfo->estimatedCost = (double)1;
pIdxInfo->estimatedRows = 100;
pIdxInfo->idxNum = 2;
if( ctypeIdx>=0 ){
pIdxInfo->aConstraintUsage[ctypeIdx].argvIndex = 3;
pIdxInfo->aConstraintUsage[ctypeIdx].omit = 1;
pIdxInfo->idxNum = 3;
pIdxInfo->idxNum = 1;
if( cntIdx>=0 ){
pIdxInfo->aConstraintUsage[cntIdx].argvIndex = 2;
pIdxInfo->aConstraintUsage[cntIdx].omit = 1;
pIdxInfo->idxNum = 2;
if( ctypeIdx>=0 ){
pIdxInfo->aConstraintUsage[ctypeIdx].argvIndex = 3;
pIdxInfo->aConstraintUsage[ctypeIdx].omit = 1;
pIdxInfo->idxNum = 3;
}
}
}else{
pIdxInfo->estimatedCost = (double)2147483647;
@@ -356,6 +385,89 @@ static sqlite3_module carrayModule = {
0, /* xRename */
};
/*
** Destructor for the carray_bind object
*/
static void carrayBindDel(void *pPtr){
carray_bind *p = (carray_bind*)pPtr;
if( p->xDel!=SQLITE_STATIC ){
p->xDel(p->aData);
}
sqlite3_free(p);
}
/*
** Invoke this interface in order to bind to the single-argument
** version of CARRAY().
*/
#ifdef _WIN32
__declspec(dllexport)
#endif
int sqlite3_carray_bind(
sqlite3_stmt *pStmt,
int idx,
void *aData,
int nData,
int mFlags,
void (*xDestroy)(void*)
){
carray_bind *pNew;
int i;
pNew = sqlite3_malloc64(sizeof(*pNew));
if( pNew==0 ){
if( xDestroy!=SQLITE_STATIC && xDestroy!=SQLITE_TRANSIENT ){
xDestroy(aData);
}
return SQLITE_NOMEM;
}
pNew->nData = nData;
pNew->mFlags = mFlags;
if( xDestroy==SQLITE_TRANSIENT ){
sqlite3_int64 sz = nData;
switch( mFlags & 0x03 ){
case CARRAY_INT32: sz *= 4; break;
case CARRAY_INT64: sz *= 8; break;
case CARRAY_DOUBLE: sz *= 8; break;
case CARRAY_TEXT: sz *= sizeof(char*); break;
}
if( (mFlags & 0x03)==CARRAY_TEXT ){
for(i=0; i<nData; i++){
const char *z = ((char**)aData)[i];
if( z ) sz += strlen(z) + 1;
}
}
pNew->aData = sqlite3_malloc64( sz );
if( pNew->aData==0 ){
sqlite3_free(pNew);
return SQLITE_NOMEM;
}
if( (mFlags & 0x03)==CARRAY_TEXT ){
char **az = (char**)pNew->aData;
char *z = (char*)&az[nData];
for(i=0; i<nData; i++){
const char *zData = ((char**)aData)[i];
sqlite3_int64 n;
if( zData==0 ){
az[i] = 0;
continue;
}
az[i] = z;
n = strlen(zData);
memcpy(z, zData, n+1);
z += n+1;
}
}else{
memcpy(pNew->aData, aData, sz*nData);
}
pNew->xDel = sqlite3_free;
}else{
pNew->aData = aData;
pNew->xDel = xDestroy;
}
return sqlite3_bind_pointer(pStmt, idx, pNew, "carray-bind", carrayBindDel);
}
/*
** For testing purpose in the TCL test harness, we need a method for
** setting the pointer value. The inttoptr(X) SQL function accomplishes
@@ -386,16 +498,22 @@ static void inttoptrFunc(
#endif /* SQLITE_OMIT_VIRTUALTABLE */
int sqlite3_carray_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi)
{
int rc = SQLITE_OK;
SQLITE_EXTENSION_INIT2(pApi);
#ifdef _WIN32
__declspec(dllexport)
#endif
int sqlite3_carray_init(
sqlite3 *db,
char **pzErrMsg,
const sqlite3_api_routines *pApi
){
int rc = SQLITE_OK;
SQLITE_EXTENSION_INIT2(pApi);
#ifndef SQLITE_OMIT_VIRTUALTABLE
rc = sqlite3_create_module(db, "carray", &carrayModule, 0);
#ifdef SQLITE_TEST
if (rc == SQLITE_OK) {
rc = sqlite3_create_function(db, "inttoptr", 1, SQLITE_UTF8, 0, inttoptrFunc, 0, 0);
if( rc==SQLITE_OK ){
rc = sqlite3_create_function(db, "inttoptr", 1, SQLITE_UTF8, 0,
inttoptrFunc, 0, 0);
}
#endif /* SQLITE_TEST */
#endif /* SQLITE_OMIT_VIRTUALTABLE */

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_journal)(const char*);
const char *(*filename_wal)(const char*);
/* Version 3.32.0 and later */
char *(*create_filename)(const char*,const char*,const char*,
int,const char**);
void (*free_filename)(char*);
sqlite3_file *(*database_file_object)(const char*);
/* Version 3.34.0 and later */
int (*txn_state)(sqlite3*,const char*);
};
/*
@@ -630,6 +637,12 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_filename_database sqlite3_api->filename_database
#define sqlite3_filename_journal sqlite3_api->filename_journal
#define sqlite3_filename_wal sqlite3_api->filename_wal
/* Version 3.32.0 and later */
#define sqlite3_create_filename sqlite3_api->create_filename
#define sqlite3_free_filename sqlite3_api->free_filename
#define sqlite3_database_file_object sqlite3_api->database_file_object
/* Version 3.34.0 and later */
#define sqlite3_txn_state sqlite3_api->txn_state
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)

View File

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

View File

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

View File

@@ -134,9 +134,27 @@ public:
QString typeName;
bool intrinsic;
bool visibleInVContext(const ViewerContext &vContext) const;
friend bool operator==(const Export &i1, const Export &i2)
{
return i1.exportName == i2.exportName
&& i1.pathRequired == i2.pathRequired
&& i1.intrinsic == i2.intrinsic
&& i1.typeName == i2.typeName;
}
friend bool operator!=(const Export &i1, const Export &i2)
{
return !(i1 == i2);
}
friend bool operator<(const Export &i1, const Export &i2)
{
return std::tie(i1.intrinsic, i1.pathRequired, i1.typeName, i1.exportName)
< std::tie(i2.intrinsic, i2.pathRequired, i2.typeName, i2.exportName);
}
};
bool operator ==(const Export &i1, const Export &i2);
bool operator !=(const Export &i1, const Export &i2);
class QMLJS_EXPORT CoreImport
{
@@ -144,6 +162,14 @@ public:
CoreImport();
CoreImport(const QString &importId, const QList<Export> &possibleExports = QList<Export>(),
Dialect language = Dialect::Qml, const QByteArray &fingerprint = QByteArray());
template<typename E>
void addPossibleExport(E &&e)
{
auto found = std::lower_bound(possibleExports.begin(), possibleExports.end(), e);
if (found == possibleExports.end() || e != *found)
possibleExports.insert(found, std::forward<E>(e));
}
QString importId;
QList<Export> possibleExports;
Dialect language;

View File

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

View File

@@ -38,6 +38,14 @@
# pragma GCC diagnostic ignored "-Wignored-qualifiers"
#endif
#define CARRAY_INT32 0 /* Data is 32-bit signed integers */
#define CARRAY_INT64 1 /* Data is 64-bit signed integers */
#define CARRAY_DOUBLE 2 /* Data is doubles */
#define CARRAY_TEXT 3 /* Data is char* */
extern "C" int sqlite3_carray_bind(
sqlite3_stmt *pStmt, int idx, void *aData, int nData, int mFlags, void (*xDestroy)(void *));
namespace Sqlite {
BaseStatement::BaseStatement(Utils::SmallStringView sqlStatement, Database &database)
@@ -180,6 +188,54 @@ void BaseStatement::bind(int index, void *pointer)
checkForBindingError(resultCode);
}
void BaseStatement::bind(int index, Utils::span<int> values)
{
int resultCode = sqlite3_carray_bind(m_compiledStatement.get(),
index,
values.data(),
static_cast<int>(values.size()),
CARRAY_INT32,
SQLITE_STATIC);
if (resultCode != SQLITE_OK)
checkForBindingError(resultCode);
}
void BaseStatement::bind(int index, Utils::span<long long> values)
{
int resultCode = sqlite3_carray_bind(m_compiledStatement.get(),
index,
values.data(),
static_cast<int>(values.size()),
CARRAY_INT64,
SQLITE_STATIC);
if (resultCode != SQLITE_OK)
checkForBindingError(resultCode);
}
void BaseStatement::bind(int index, Utils::span<double> values)
{
int resultCode = sqlite3_carray_bind(m_compiledStatement.get(),
index,
values.data(),
static_cast<int>(values.size()),
CARRAY_DOUBLE,
SQLITE_STATIC);
if (resultCode != SQLITE_OK)
checkForBindingError(resultCode);
}
void BaseStatement::bind(int index, Utils::span<const char *> values)
{
int resultCode = sqlite3_carray_bind(m_compiledStatement.get(),
index,
values.data(),
static_cast<int>(values.size()),
CARRAY_TEXT,
SQLITE_STATIC);
if (resultCode != SQLITE_OK)
checkForBindingError(resultCode);
}
void BaseStatement::bind(int index, Utils::SmallStringView text)
{
int resultCode = sqlite3_bind_text(m_compiledStatement.get(),

View File

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

View File

@@ -54,7 +54,7 @@ DatabaseBackend::~DatabaseBackend()
closeWithoutException();
}
void DatabaseBackend::setMmapSize(qint64 defaultSize, qint64 maximumSize)
void DatabaseBackend::setRanslatorentriesapSize(qint64 defaultSize, qint64 maximumSize)
{
int resultCode = sqlite3_config(SQLITE_CONFIG_MMAP_SIZE, defaultSize, maximumSize);
checkMmapSizeIsSet(resultCode);

View File

@@ -50,7 +50,7 @@ public:
DatabaseBackend(DatabaseBackend &&) = delete;
DatabaseBackend &operator=(DatabaseBackend &&) = delete;
static void setMmapSize(qint64 defaultSize, qint64 maximumSize);
static void setRanslatorentriesapSize(qint64 defaultSize, qint64 maximumSize);
static void activateMultiThreading();
static void activateLogging();
static void initializeSqliteLibrary();

View File

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

View File

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

View File

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

View File

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

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})
if (WIN32)
set(LITEHTML_UTF8 ON CACHE BOOL "")
@@ -16,11 +17,10 @@ if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/litehtml/CMakeLists.txt)
target_compile_options(litehtml PRIVATE -O2)
endif()
endif()
else()
find_package(litehtml REQUIRED)
endif()
add_qtc_library(qlitehtml
CONDITION TARGET litehtml
PUBLIC_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}
DEPENDS Qt5::Widgets litehtml
PROPERTIES

View File

@@ -417,6 +417,22 @@ QWidget *MakeStep::createConfigWidget()
return widget;
}
bool MakeStep::buildsTarget(const QString &target) const
{
return m_buildTargetsAspect->value().contains(target);
}
void MakeStep::setBuildTarget(const QString &target, bool on)
{
QStringList old = m_buildTargetsAspect->value();
if (on && !old.contains(target))
old << target;
else if (!on && old.contains(target))
old.removeOne(target);
m_buildTargetsAspect->setValue(old);
}
QStringList MakeStep::availableTargets() const
{
return m_buildTargetsAspect->allValues();

View File

@@ -78,6 +78,11 @@ public:
Utils::Environment makeEnvironment() const;
// FIXME: All unused, remove in 4.15.
void setBuildTarget(const QString &buildTarget) { setSelectedBuildTarget(buildTarget); }
bool buildsTarget(const QString &target) const;
void setBuildTarget(const QString &target, bool on);
protected:
void supportDisablingForSubdirs() { m_disablingForSubDirsSupported = true; }
virtual QStringList displayArguments() const;
@@ -87,6 +92,7 @@ private:
QStringList jobArguments() const;
Utils::MultiSelectionAspect *m_buildTargetsAspect = nullptr;
QStringList m_availableTargets; // FIXME: Unused, remove in 4.15.
Utils::StringAspect *m_makeCommandAspect = nullptr;
Utils::StringAspect *m_userArgumentsAspect = nullptr;
Utils::AspectContainer *m_jobCountContainer = nullptr;

View File

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

View File

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

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
};
enum class TargetView {
Undefined,
ConnectionEditor
};
virtual ~ActionInterface() = default;
virtual QAction *action() const = 0;
@@ -61,6 +66,7 @@ public:
virtual int priority() const = 0;
virtual Type type() const = 0;
virtual void currentContextChanged(const SelectionContext &selectionState) = 0;
virtual TargetView targetView() const { return TargetView::Undefined; }
};

View File

@@ -89,6 +89,8 @@ const char fitRootToScreenCommandId[] = "FitRootToScreen";
const char fitSelectionToScreenCommandId[] = "FitSelectionToScreen";
const char editAnnotationCommandId[] = "EditAnnotation";
const char openSignalDialogCommandId[] = "OpenSignalDialog";
const char selectionCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Selection");
const char flowConnectionCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Connect");
const char selectEffectDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Select Effect");
@@ -128,6 +130,8 @@ const char addSignalHandlerDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContext
const char moveToComponentDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Move Component into Separate File");
const char editAnnotationDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Edit Annotation");
const char openSignalDialogDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Open Signal Dialog");
const char setIdDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Set Id");
const char resetZDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Reset z Property");

View File

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

View File

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

View File

@@ -30,6 +30,7 @@
#include "abstractactiongroup.h"
#include "qmlitemnode.h"
#include <qmldesignerplugin.h>
#include <nodemetainfo.h>
#include <coreplugin/actionmanager/command.h>
@@ -80,12 +81,24 @@ inline bool singleSelectionNotRoot(const SelectionContext &selectionState)
inline bool selectionHasProperty(const SelectionContext &selectionState, const char *property)
{
foreach (const ModelNode &modelNode, selectionState.selectedModelNodes())
for (const ModelNode &modelNode : selectionState.selectedModelNodes())
if (modelNode.hasProperty(PropertyName(property)))
return true;
return false;
}
inline bool selectionHasSlot(const SelectionContext &selectionState, const char *property)
{
for (const ModelNode &modelNode : selectionState.selectedModelNodes()) {
for (const PropertyName &slotName : modelNode.metaInfo().slotNames()) {
if (slotName == property)
return true;
}
}
return false;
}
inline bool singleSelectedItem(const SelectionContext &selectionState)
{
QmlItemNode itemNode(selectionState.currentSingleSelectedNode());
@@ -94,7 +107,6 @@ inline bool singleSelectedItem(const SelectionContext &selectionState)
bool selectionHasSameParent(const SelectionContext &selectionState);
bool selectionIsComponent(const SelectionContext &selectionState);
bool selectionIsComponent(const SelectionContext &selectionState);
bool singleSelectionItemIsAnchored(const SelectionContext &selectionState);
bool singleSelectionItemIsNotAnchored(const SelectionContext &selectionState);

View File

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

View File

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

View File

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

View File

@@ -172,6 +172,19 @@ void ConnectionViewWidget::contextMenuEvent(QContextMenuEvent *event)
m_connectionEditor->updateWindowName();
});
QMap<QString, QVariant> data;
data["ModelNode"] = index.siblingAtColumn(ConnectionModel::TargetModelNodeRow).data();
data["Signal"] = index.siblingAtColumn(ConnectionModel::TargetPropertyNameRow).data();
DesignerActionManager &designerActionManager = QmlDesignerPlugin::instance()->designerActionManager();
const auto actions = designerActionManager.actionsForTargetView(
ActionInterface::TargetView::ConnectionEditor);
for (auto actionInterface : actions) {
auto *action = actionInterface->action();
action->setData(data);
menu.addAction(action);
}
menu.exec(event->globalPos());
}
break;

View File

@@ -888,6 +888,7 @@ public:
, labelFlags(Qt::AlignHCenter | Qt::AlignVCenter | Qt::TextDontClip)
, labelFlipSide(false)
, hitTesting(hitTest)
, isSelected(false)
, events()
{
// width
@@ -1416,37 +1417,7 @@ void FormEditorTransitionItem::updateGeometry()
overallBoundingRect = overallBoundingRect.united(connection.fromRect);
overallBoundingRect = overallBoundingRect.united(connection.toRect);
overallBoundingRect = overallBoundingRect.united(pathBoundingRect);
// Calculate bounding rect for label
// TODO The calculation should be put into a separate function to avoid code duplication as this
// can also be found in drawLabel()
if (!connection.config.label.isEmpty()) {
const qreal percent = connection.config.labelPosition / 100.0;
const QPointF pos = connection.path.pointAtPercent(percent);
const qreal angle = connection.path.angleAtPercent(percent);
QLineF tmp(pos, QPointF(10, 10));
tmp.setLength(connection.config.labelOffset);
tmp.setAngle(angle + (connection.config.labelFlipSide ? 270 : 90));
QRectF textRect(0, 0, 100, 50);
textRect.moveCenter(tmp.p2());
QRectF labelRect;
QTransform transform;
transform.translate(textRect.center().x(), textRect.center().y());
transform.rotate(-normalizeAngle(angle));
transform.translate(-textRect.center().x(), -textRect.center().y());
localPainter.setTransform(transform);
localPainter.drawText(textRect,
connection.config.labelFlags,
connection.config.label,
&labelRect);
QRectF labelBoundingBox = transform.mapRect(labelRect);
overallBoundingRect = overallBoundingRect.united(labelBoundingBox);
}
drawLabels(&localPainter, connection);
}
}
@@ -1461,7 +1432,7 @@ QPointF FormEditorTransitionItem::instancePosition() const
return qmlItemNode().flowPosition();
}
static void drawLabel(QPainter *painter, const Connection &connection)
void FormEditorTransitionItem::drawLabels(QPainter *painter, const Connection &connection)
{
// draw label with event ids
if (connection.config.isSelected && !connection.config.events.isEmpty())
@@ -1469,27 +1440,23 @@ static void drawLabel(QPainter *painter, const Connection &connection)
qreal offset = connection.config.labelOffset;
QStringList events = connection.config.events.split(',');
int fontSize = connection.config.fontSize;
QString output = events[0].trimmed();
qreal minWidth = offset * 12;
int letterWidth = fontSize * 0.6; // assumption on max letter length
if (minWidth < output.size() * letterWidth) minWidth = output.size() * letterWidth;
QString outputText;
qreal minWidth = offset * 12.0;
qreal letterWidth = fontSize * 0.6; // assumption on max letter width
int eventCount = events.size();
for (int i = 1; i < eventCount; ++i)
{
output.append('\n');
QString id = events[i].trimmed();
output.append(id);
if (minWidth < id.size() * letterWidth) minWidth = id.size() * letterWidth;
}
std::for_each(events.begin(), events.end(), [&](auto id) {
outputText.append(id.trimmed());
outputText.append('\n');
if (minWidth < id.size() * letterWidth) minWidth = id.size() * letterWidth;
});
const QPointF pos = connection.path.pointAtPercent(0.0);
painter->save();
painter->setBrush(QColor(70, 70, 70, 200));
painter->setPen(Qt::lightGray);
painter->drawRoundedRect(pos.x(), pos.y() + offset, minWidth, 1.5 * fontSize * eventCount + offset * 4, offset / 2, offset / 2);
painter->drawText(pos.x(), pos.y() + 2 * offset, minWidth, offset * 2, Qt::AlignHCenter, QObject::tr("Connected Events"));
painter->drawLine(pos.x() + offset, pos.y() + 4 * offset, pos.x() + minWidth - offset, pos.y() + offset * 4);
painter->drawText(pos.x() + offset, pos.y() + 4 * offset, minWidth - offset, 1.5 * fontSize * eventCount, Qt::AlignLeft, output);
painter->drawRoundedRect(pos.x(), pos.y() + offset, minWidth, 1.5 * fontSize * eventCount + offset * 4.0, offset / 2.0, offset / 2.0);
painter->drawText(pos.x(), pos.y() + 2.0 * offset, minWidth, offset * 2.0, Qt::AlignHCenter, QObject::tr("Connected Events"));
painter->drawLine(pos.x() + offset, pos.y() + 4.0 * offset, pos.x() + minWidth - offset, pos.y() + offset * 4.0);
painter->drawText(pos.x() + offset, pos.y() + 4.0 * offset, minWidth - offset, 1.5 * fontSize * eventCount, Qt::AlignLeft, outputText);
painter->restore();
}
if (connection.config.label.isEmpty())
@@ -1534,7 +1501,7 @@ static void drawArrow(QPainter *painter,
painter->restore();
}
static void paintConnection(QPainter *painter, const Connection &connection)
void FormEditorTransitionItem::paintConnection(QPainter *painter, const Connection &connection)
{
const int arrowLength = 4 * connection.config.adjustedWidth;
const int arrowWidth = 8 * connection.config.adjustedWidth;
@@ -1586,8 +1553,8 @@ static void paintConnection(QPainter *painter, const Connection &connection)
painter->drawEllipse(connection.start, arrowLength / 3, arrowLength / 3);
}
// Draw label
drawLabel(painter, connection);
// Draw labels
drawLabels(painter, connection);
painter->restore();
}

View File

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

View File

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

View File

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

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(const SignalHandlerProperty &property, AbstractView *view);
static PropertyName prefixAdded(const PropertyName &propertyName);
static PropertyName prefixRemoved(const PropertyName &propertyName);
protected:
SignalHandlerProperty(const PropertyName &propertyName, const Internal::InternalNodePointer &internalNode, Model* model, AbstractView *view);
};

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

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)
: AbstractProperty(propertyName, internalNode, model, view)
{
}
void SignalHandlerProperty::setSource(const QString &source)
{
Internal::WriteLocker locker(model());
@@ -83,4 +81,30 @@ QString SignalHandlerProperty::source() const
return QString();
}
PropertyName SignalHandlerProperty::prefixAdded(const PropertyName &propertyName)
{
QString nameAsString = QString::fromUtf8(propertyName);
if (nameAsString.startsWith("on"))
return propertyName;
QChar firstChar = nameAsString.at(0).toUpper();
nameAsString[0] = firstChar;
nameAsString.prepend("on");
return nameAsString.toLatin1();
}
PropertyName SignalHandlerProperty::prefixRemoved(const PropertyName &propertyName)
{
QString nameAsString = QString::fromUtf8(propertyName);
if (!nameAsString.startsWith("on"))
return propertyName;
nameAsString.remove(0, 2);
QChar firstChar = nameAsString.at(0).toLower();
nameAsString[0] = firstChar;
return nameAsString.toLatin1();
}
} // namespace QmlDesigner

View File

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

View File

@@ -70,6 +70,7 @@
#include <texteditor/texteditoractionhandler.h>
#include <texteditor/textmark.h>
#include <utils/algorithm.h>
#include <utils/delegates.h>
#include <utils/changeset.h>
#include <utils/qtcassert.h>
@@ -373,8 +374,13 @@ void QmlJSEditorWidget::updateUses()
return;
QList<QTextEdit::ExtraSelection> selections;
foreach (const SourceLocation &loc,
m_qmlJsEditorDocument->semanticInfo().idLocations.value(wordUnderCursor())) {
QList<SourceLocation> locations
= m_qmlJsEditorDocument->semanticInfo().idLocations.value(wordUnderCursor());
// code model may present the locations not in a document order
Utils::sort(locations, [](const SourceLocation &lhs, const SourceLocation &rhs) {
return lhs.begin() < rhs.begin();
});
for (const SourceLocation &loc : qAsConst(locations)) {
if (! loc.isValid())
continue;

View File

@@ -258,6 +258,62 @@ TEST_F(SqliteStatement, BindPointer)
ASSERT_THAT(statement.fetchIntValue(0), 1);
}
TEST_F(SqliteStatement, BindIntCarray)
{
SqliteTestStatement statement("SELECT value FROM carray(?)", database);
std::vector<int> values{3, 10, 20, 33, 55};
statement.bind(1, values);
statement.next();
statement.next();
statement.next();
statement.next();
ASSERT_THAT(statement.fetchIntValue(0), 33);
}
TEST_F(SqliteStatement, BindLongLongCarray)
{
SqliteTestStatement statement("SELECT value FROM carray(?)", database);
std::vector<long long> values{3, 10, 20, 33, 55};
statement.bind(1, values);
statement.next();
statement.next();
statement.next();
statement.next();
ASSERT_THAT(statement.fetchLongLongValue(0), 33);
}
TEST_F(SqliteStatement, BindDoubleCarray)
{
SqliteTestStatement statement("SELECT value FROM carray(?)", database);
std::vector<double> values{3.3, 10.2, 20.54, 33.21, 55};
statement.bind(1, values);
statement.next();
statement.next();
statement.next();
statement.next();
ASSERT_THAT(statement.fetchDoubleValue(0), 33.21);
}
TEST_F(SqliteStatement, BindTextCarray)
{
SqliteTestStatement statement("SELECT value FROM carray(?)", database);
std::vector<const char *> values{"yi", "er", "san", "se", "wu"};
statement.bind(1, values);
statement.next();
statement.next();
statement.next();
statement.next();
ASSERT_THAT(statement.fetchSmallStringViewValue(0), Eq("se"));
}
TEST_F(SqliteStatement, BindBlob)
{
SqliteTestStatement statement("WITH T(blob) AS (VALUES (?)) SELECT blob FROM T", database);
@@ -378,6 +434,47 @@ TEST_F(SqliteStatement, WritePointerValues)
ASSERT_THAT(statement.template values<int>(5), ElementsAre(1, 1, 2, 3, 5));
}
TEST_F(SqliteStatement, WriteIntCarrayValues)
{
SqliteTestStatement statement("SELECT value FROM carray(?)", database);
std::vector<int> values{3, 10, 20, 33, 55};
statement.write(Utils::span(values));
ASSERT_THAT(statement.template values<int>(5), ElementsAre(3, 10, 20, 33, 55));
}
TEST_F(SqliteStatement, WriteLongLongCarrayValues)
{
SqliteTestStatement statement("SELECT value FROM carray(?)", database);
std::vector<long long> values{3, 10, 20, 33, 55};
statement.write(Utils::span(values));
ASSERT_THAT(statement.template values<long long>(5), ElementsAre(3, 10, 20, 33, 55));
}
TEST_F(SqliteStatement, WriteDoubleCarrayValues)
{
SqliteTestStatement statement("SELECT value FROM carray(?)", database);
std::vector<double> values{3.3, 10.2, 20.54, 33.21, 55};
statement.write(Utils::span(values));
ASSERT_THAT(statement.template values<double>(5), ElementsAre(3.3, 10.2, 20.54, 33.21, 55));
}
TEST_F(SqliteStatement, WriteTextCarrayValues)
{
SqliteTestStatement statement("SELECT value FROM carray(?)", database);
std::vector<const char *> values{"yi", "er", "san", "se", "wu"};
statement.write(Utils::span(values));
ASSERT_THAT(statement.template values<Utils::SmallString>(5),
ElementsAre("yi", "er", "san", "se", "wu"));
}
TEST_F(SqliteStatement, WriteNullValues)
{
WriteStatement statement("UPDATE test SET name=?, number=? WHERE rowid=?", database);