Merge remote-tracking branch 'origin/4.14'

Change-Id: I70504e096be620434f38cd990c593950da8b24ba
This commit is contained in:
Tim Jenssen
2021-01-07 15:20:42 +01: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_LIBRARY_PATH "${_IDE_LIBRARY_BASE_PATH}/qtcreator")
set(_IDE_PLUGIN_PATH "${_IDE_LIBRARY_BASE_PATH}/qtcreator/plugins")
set(_IDE_LIBEXEC_PATH "bin")
set(QT_DEST_PLUGIN_PATH "bin/plugins")
set(QT_DEST_QML_PATH "bin/qml")
else ()
set(_IDE_LIBEXEC_PATH "libexec/qtcreator")
set(QT_DEST_PLUGIN_PATH "lib/Qt/plugins")
set(QT_DEST_QML_PATH "lib/Qt/qml")
endif ()
set(_IDE_DATA_PATH "share/qtcreator")
set(_IDE_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,13 +147,10 @@ static int carrayDisconnect(sqlite3_vtab *pVtab){
/*
** Constructor for a new carray_cursor object.
*/
static int carrayOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor)
{
static int carrayOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
carray_cursor *pCur;
pCur = sqlite3_malloc(sizeof(*pCur));
if (pCur == 0)
return SQLITE_NOMEM;
pCur = sqlite3_malloc( sizeof(*pCur) );
if( pCur==0 ) return SQLITE_NOMEM;
memset(pCur, 0, sizeof(*pCur));
*ppCursor = &pCur->base;
return SQLITE_OK;
@@ -242,7 +250,19 @@ static int carrayFilter(
int argc, sqlite3_value **argv
){
carray_cursor *pCur = (carray_cursor *)pVtabCursor;
if( idxNum ){
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 ){
@@ -261,9 +281,8 @@ static int carrayFilter(
pCur->eType = i;
}
}
}else{
pCur->pPtr = 0;
pCur->iCnt = 0;
break;
}
}
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,19 +334,22 @@ 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 = 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;
pIdxInfo->estimatedRows = 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)
{
#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

View File

@@ -123,9 +123,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION "3.31.1"
#define SQLITE_VERSION_NUMBER 3031001
#define SQLITE_SOURCE_ID "2020-01-27 19:55:54 3bfa9cc97da10598521b342961df8f5f68c7388fa117345eeb516eaa837bb4d6"
#define SQLITE_VERSION "3.34.0"
#define SQLITE_VERSION_NUMBER 3034000
#define SQLITE_SOURCE_ID "2020-12-01 16:14:00 a26b6597e3ae272231b96f9982c3bcc17ddec2f2b6eb4df06a224b91089fed5b"
/*
** CAPI3REF: Run-Time Library Version Numbers
@@ -299,26 +299,22 @@ typedef sqlite_uint64 sqlite3_uint64;
** the [sqlite3] object is successfully destroyed and all associated
** resources are deallocated.
**
** ^If the database connection is associated with unfinalized prepared
** statements or unfinished sqlite3_backup objects then sqlite3_close()
** will leave the database connection open and return [SQLITE_BUSY].
** ^If sqlite3_close_v2() is called with unfinalized prepared statements
** and/or unfinished sqlite3_backups, then the database connection becomes
** an unusable "zombie" which will automatically be deallocated when the
** last prepared statement is finalized or the last sqlite3_backup is
** finished. The sqlite3_close_v2() interface is intended for use with
** host languages that are garbage collected, and where the order in which
** destructors are called is arbitrary.
**
** Applications should [sqlite3_finalize | finalize] all [prepared statements],
** [sqlite3_blob_close | close] all [BLOB handles], and
** Ideally, applications should [sqlite3_finalize | finalize] all
** [prepared statements], [sqlite3_blob_close | close] all [BLOB handles], and
** [sqlite3_backup_finish | finish] all [sqlite3_backup] objects associated
** with the [sqlite3] object prior to attempting to close the object. ^If
** sqlite3_close_v2() is called on a [database connection] that still has
** outstanding [prepared statements], [BLOB handles], and/or
** [sqlite3_backup] objects then it returns [SQLITE_OK] and the deallocation
** of resources is deferred until all [prepared statements], [BLOB handles],
** and [sqlite3_backup] objects are also destroyed.
** with the [sqlite3] object prior to attempting to close the object.
** ^If the database connection is associated with unfinalized prepared
** statements, BLOB handlers, and/or unfinished sqlite3_backup objects then
** sqlite3_close() will leave the database connection open and return
** [SQLITE_BUSY]. ^If sqlite3_close_v2() is called with unfinalized prepared
** statements, unclosed BLOB handlers, and/or unfinished sqlite3_backups,
** it returns [SQLITE_OK] regardless, but instead of deallocating the database
** connection immediately, it marks the database connection as an unusable
** "zombie" and makes arrangements to automatically deallocate the database
** connection after all prepared statements are finalized, all BLOB handles
** are closed, and all backups have finished. The sqlite3_close_v2() interface
** is intended for use with host languages that are garbage collected, and
** where the order in which destructors are called is arbitrary.
**
** ^If an [sqlite3] object is destroyed while a transaction is open,
** the transaction is automatically rolled back.
@@ -507,10 +503,13 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_IOERR_BEGIN_ATOMIC (SQLITE_IOERR | (29<<8))
#define SQLITE_IOERR_COMMIT_ATOMIC (SQLITE_IOERR | (30<<8))
#define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31<<8))
#define SQLITE_IOERR_DATA (SQLITE_IOERR | (32<<8))
#define SQLITE_IOERR_CORRUPTFS (SQLITE_IOERR | (33<<8))
#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
#define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8))
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
#define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8))
#define SQLITE_BUSY_TIMEOUT (SQLITE_BUSY | (3<<8))
#define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8))
#define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8))
#define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8))
@@ -519,6 +518,7 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_CANTOPEN_SYMLINK (SQLITE_CANTOPEN | (6<<8))
#define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8))
#define SQLITE_CORRUPT_SEQUENCE (SQLITE_CORRUPT | (2<<8))
#define SQLITE_CORRUPT_INDEX (SQLITE_CORRUPT | (3<<8))
#define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8))
#define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8))
#define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3<<8))
@@ -565,7 +565,7 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_OPEN_MAIN_JOURNAL 0x00000800 /* VFS only */
#define SQLITE_OPEN_TEMP_JOURNAL 0x00001000 /* VFS only */
#define SQLITE_OPEN_SUBJOURNAL 0x00002000 /* VFS only */
#define SQLITE_OPEN_MASTER_JOURNAL 0x00004000 /* VFS only */
#define SQLITE_OPEN_SUPER_JOURNAL 0x00004000 /* VFS only */
#define SQLITE_OPEN_NOMUTEX 0x00008000 /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_FULLMUTEX 0x00010000 /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_SHAREDCACHE 0x00020000 /* Ok for sqlite3_open_v2() */
@@ -574,6 +574,9 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_OPEN_NOFOLLOW 0x01000000 /* Ok for sqlite3_open_v2() */
/* Reserved: 0x00F00000 */
/* Legacy compatibility: */
#define SQLITE_OPEN_MASTER_JOURNAL 0x00004000 /* VFS only */
/*
** CAPI3REF: Device Characteristics
@@ -871,7 +874,7 @@ struct sqlite3_io_methods {
** of the xSync method. In most cases, the pointer argument passed with
** this file-control is NULL. However, if the database file is being synced
** as part of a multi-database commit, the argument points to a nul-terminated
** string containing the transactions master-journal file name. VFSes that
** string containing the transactions super-journal file name. VFSes that
** do not need this signal should silently ignore this opcode. Applications
** should not call [sqlite3_file_control()] with this opcode as doing so may
** disrupt the operation of the specialized VFSes that do require it.
@@ -1087,10 +1090,12 @@ struct sqlite3_io_methods {
** a prior successful call to [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE].
**
** <li>[[SQLITE_FCNTL_LOCK_TIMEOUT]]
** The [SQLITE_FCNTL_LOCK_TIMEOUT] opcode causes attempts to obtain
** a file lock using the xLock or xShmLock methods of the VFS to wait
** for up to M milliseconds before failing, where M is the single
** unsigned integer parameter.
** The [SQLITE_FCNTL_LOCK_TIMEOUT] opcode is used to configure a VFS
** to block for up to M milliseconds before failing when attempting to
** obtain a file lock using the xLock or xShmLock methods of the VFS.
** The parameter is a pointer to a 32-bit signed integer that contains
** the value that M is to be set to. Before returning, the 32-bit signed
** integer is overwritten with the previous value of M.
**
** <li>[[SQLITE_FCNTL_DATA_VERSION]]
** The [SQLITE_FCNTL_DATA_VERSION] opcode is used to detect changes to
@@ -1112,6 +1117,11 @@ struct sqlite3_io_methods {
** happen either internally or externally and that are associated with
** a particular attached database.
**
** <li>[[SQLITE_FCNTL_CKPT_START]]
** The [SQLITE_FCNTL_CKPT_START] opcode is invoked from within a checkpoint
** in wal mode before the client starts to copy pages from the wal
** file to the database file.
**
** <li>[[SQLITE_FCNTL_CKPT_DONE]]
** The [SQLITE_FCNTL_CKPT_DONE] opcode is invoked from within a checkpoint
** in wal mode after the client has finished copying pages from the wal
@@ -1155,6 +1165,8 @@ struct sqlite3_io_methods {
#define SQLITE_FCNTL_DATA_VERSION 35
#define SQLITE_FCNTL_SIZE_LIMIT 36
#define SQLITE_FCNTL_CKPT_DONE 37
#define SQLITE_FCNTL_RESERVE_BYTES 38
#define SQLITE_FCNTL_CKPT_START 39
/* deprecated names */
#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
@@ -1259,7 +1271,7 @@ typedef struct sqlite3_api_routines sqlite3_api_routines;
** <li> [SQLITE_OPEN_TEMP_JOURNAL]
** <li> [SQLITE_OPEN_TRANSIENT_DB]
** <li> [SQLITE_OPEN_SUBJOURNAL]
** <li> [SQLITE_OPEN_MASTER_JOURNAL]
** <li> [SQLITE_OPEN_SUPER_JOURNAL]
** <li> [SQLITE_OPEN_WAL]
** </ul>)^
**
@@ -1637,7 +1649,7 @@ SQLITE_API int sqlite3_db_config(sqlite3*, int op, ...);
** by xInit. The pAppData pointer is used as the only parameter to
** xInit and xShutdown.
**
** SQLite holds the [SQLITE_MUTEX_STATIC_MASTER] mutex when it invokes
** SQLite holds the [SQLITE_MUTEX_STATIC_MAIN] mutex when it invokes
** the xInit method, so the xInit method need not be threadsafe. The
** xShutdown method is only called from [sqlite3_shutdown()] so it does
** not need to be threadsafe either. For all other methods, SQLite
@@ -2275,8 +2287,7 @@ struct sqlite3_mem_methods {
** [[SQLITE_DBCONFIG_TRUSTED_SCHEMA]]
** <dt>SQLITE_DBCONFIG_TRUSTED_SCHEMA</td>
** <dd>The SQLITE_DBCONFIG_TRUSTED_SCHEMA option tells SQLite to
** assume that database schemas (the contents of the [sqlite_master] tables)
** are untainted by malicious content.
** assume that database schemas are untainted by malicious content.
** When the SQLITE_DBCONFIG_TRUSTED_SCHEMA option is disabled, SQLite
** takes additional defensive steps to protect the application from harm
** including:
@@ -3533,8 +3544,19 @@ SQLITE_API int sqlite3_open_v2(
** that check if a database file was a URI that contained a specific query
** parameter, and if so obtains the value of that query parameter.
**
** If F is the database filename pointer passed into the xOpen() method of
** a VFS implementation or it is the return value of [sqlite3_db_filename()]
** The first parameter to these interfaces (hereafter referred to
** as F) must be one of:
** <ul>
** <li> A database filename pointer created by the SQLite core and
** passed into the xOpen() method of a VFS implemention, or
** <li> A filename obtained from [sqlite3_db_filename()], or
** <li> A new filename constructed using [sqlite3_create_filename()].
** </ul>
** If the F parameter is not one of the above, then the behavior is
** undefined and probably undesirable. Older versions of SQLite were
** more tolerant of invalid F parameters than newer versions.
**
** If F is a suitable filename (as described in the previous paragraph)
** and if P is the name of the query parameter, then
** sqlite3_uri_parameter(F,P) returns the value of the P
** parameter if it exists or a NULL pointer if P does not appear as a
@@ -3617,6 +3639,78 @@ SQLITE_API const char *sqlite3_filename_database(const char*);
SQLITE_API const char *sqlite3_filename_journal(const char*);
SQLITE_API const char *sqlite3_filename_wal(const char*);
/*
** CAPI3REF: Database File Corresponding To A Journal
**
** ^If X is the name of a rollback or WAL-mode journal file that is
** passed into the xOpen method of [sqlite3_vfs], then
** sqlite3_database_file_object(X) returns a pointer to the [sqlite3_file]
** object that represents the main database file.
**
** This routine is intended for use in custom [VFS] implementations
** only. It is not a general-purpose interface.
** The argument sqlite3_file_object(X) must be a filename pointer that
** has been passed into [sqlite3_vfs].xOpen method where the
** flags parameter to xOpen contains one of the bits
** [SQLITE_OPEN_MAIN_JOURNAL] or [SQLITE_OPEN_WAL]. Any other use
** of this routine results in undefined and probably undesirable
** behavior.
*/
SQLITE_API sqlite3_file *sqlite3_database_file_object(const char*);
/*
** CAPI3REF: Create and Destroy VFS Filenames
**
** These interfces are provided for use by [VFS shim] implementations and
** are not useful outside of that context.
**
** The sqlite3_create_filename(D,J,W,N,P) allocates memory to hold a version of
** database filename D with corresponding journal file J and WAL file W and
** with N URI parameters key/values pairs in the array P. The result from
** sqlite3_create_filename(D,J,W,N,P) is a pointer to a database filename that
** is safe to pass to routines like:
** <ul>
** <li> [sqlite3_uri_parameter()],
** <li> [sqlite3_uri_boolean()],
** <li> [sqlite3_uri_int64()],
** <li> [sqlite3_uri_key()],
** <li> [sqlite3_filename_database()],
** <li> [sqlite3_filename_journal()], or
** <li> [sqlite3_filename_wal()].
** </ul>
** If a memory allocation error occurs, sqlite3_create_filename() might
** return a NULL pointer. The memory obtained from sqlite3_create_filename(X)
** must be released by a corresponding call to sqlite3_free_filename(Y).
**
** The P parameter in sqlite3_create_filename(D,J,W,N,P) should be an array
** of 2*N pointers to strings. Each pair of pointers in this array corresponds
** to a key and value for a query parameter. The P parameter may be a NULL
** pointer if N is zero. None of the 2*N pointers in the P array may be
** NULL pointers and key pointers should not be empty strings.
** None of the D, J, or W parameters to sqlite3_create_filename(D,J,W,N,P) may
** be NULL pointers, though they can be empty strings.
**
** The sqlite3_free_filename(Y) routine releases a memory allocation
** previously obtained from sqlite3_create_filename(). Invoking
** sqlite3_free_filename(Y) where Y is a NULL pointer is a harmless no-op.
**
** If the Y parameter to sqlite3_free_filename(Y) is anything other
** than a NULL pointer or a pointer previously acquired from
** sqlite3_create_filename(), then bad things such as heap
** corruption or segfaults may occur. The value Y should be
** used again after sqlite3_free_filename(Y) has been called. This means
** that if the [sqlite3_vfs.xOpen()] method of a VFS has been called using Y,
** then the corresponding [sqlite3_module.xClose() method should also be
** invoked prior to calling sqlite3_free_filename(Y).
*/
SQLITE_API char *sqlite3_create_filename(
const char *zDatabase,
const char *zJournal,
const char *zWal,
int nParam,
const char **azParam
);
SQLITE_API void sqlite3_free_filename(char*);
/*
** CAPI3REF: Error Codes And Messages
@@ -4199,12 +4293,30 @@ typedef struct sqlite3_context sqlite3_context;
** [sqlite3_bind_parameter_index()] API if desired. ^The index
** for "?NNN" parameters is the value of NNN.
** ^The NNN value must be between 1 and the [sqlite3_limit()]
** parameter [SQLITE_LIMIT_VARIABLE_NUMBER] (default value: 999).
** parameter [SQLITE_LIMIT_VARIABLE_NUMBER] (default value: 32766).
**
** ^The third argument is the value to bind to the parameter.
** ^If the third parameter to sqlite3_bind_text() or sqlite3_bind_text16()
** or sqlite3_bind_blob() is a NULL pointer then the fourth parameter
** is ignored and the end result is the same as sqlite3_bind_null().
** ^If the third parameter to sqlite3_bind_text() is not NULL, then
** it should be a pointer to well-formed UTF8 text.
** ^If the third parameter to sqlite3_bind_text16() is not NULL, then
** it should be a pointer to well-formed UTF16 text.
** ^If the third parameter to sqlite3_bind_text64() is not NULL, then
** it should be a pointer to a well-formed unicode string that is
** either UTF8 if the sixth parameter is SQLITE_UTF8, or UTF16
** otherwise.
**
** [[byte-order determination rules]] ^The byte-order of
** UTF16 input text is determined by the byte-order mark (BOM, U+FEFF)
** found in first character, which is removed, or in the absence of a BOM
** the byte order is the native byte order of the host
** machine for sqlite3_bind_text16() or the byte order specified in
** the 6th parameter for sqlite3_bind_text64().)^
** ^If UTF16 input text contains invalid unicode
** characters, then SQLite might change those invalid characters
** into the unicode replacement character: U+FFFD.
**
** ^(In those routines that have a fourth argument, its value is the
** number of bytes in the parameter. To be clear: the value is the
@@ -4218,7 +4330,7 @@ typedef struct sqlite3_context sqlite3_context;
** or sqlite3_bind_text16() or sqlite3_bind_text64() then
** that parameter must be the byte offset
** where the NUL terminator would occur assuming the string were NUL
** terminated. If any NUL characters occur at byte offsets less than
** terminated. If any NUL characters occurs at byte offsets less than
** the value of the fourth parameter then the resulting string value will
** contain embedded NULs. The result of expressions involving strings
** with embedded NULs is undefined.
@@ -5386,7 +5498,7 @@ SQLITE_API void sqlite3_value_free(sqlite3_value*);
**
** ^(The amount of space allocated by sqlite3_aggregate_context(C,N) is
** determined by the N parameter on first successful call. Changing the
** value of N in any subsequents call to sqlite3_aggregate_context() within
** value of N in any subsequent call to sqlite3_aggregate_context() within
** the same aggregate function instance will not resize the memory
** allocation.)^ Within the xFinal callback, it is customary to set
** N=0 in calls to sqlite3_aggregate_context(C,N) so that no
@@ -5543,8 +5655,9 @@ typedef void (*sqlite3_destructor_type)(void*);
** 2nd parameter of sqlite3_result_error() or sqlite3_result_error16()
** as the text of an error message. ^SQLite interprets the error
** message string from sqlite3_result_error() as UTF-8. ^SQLite
** interprets the string from sqlite3_result_error16() as UTF-16 in native
** byte order. ^If the third parameter to sqlite3_result_error()
** interprets the string from sqlite3_result_error16() as UTF-16 using
** the same [byte-order determination rules] as [sqlite3_bind_text16()].
** ^If the third parameter to sqlite3_result_error()
** or sqlite3_result_error16() is negative then SQLite takes as the error
** message all text up through the first zero character.
** ^If the third parameter to sqlite3_result_error() or
@@ -5612,6 +5725,25 @@ typedef void (*sqlite3_destructor_type)(void*);
** then SQLite makes a copy of the result into space obtained
** from [sqlite3_malloc()] before it returns.
**
** ^For the sqlite3_result_text16(), sqlite3_result_text16le(), and
** sqlite3_result_text16be() routines, and for sqlite3_result_text64()
** when the encoding is not UTF8, if the input UTF16 begins with a
** byte-order mark (BOM, U+FEFF) then the BOM is removed from the
** string and the rest of the string is interpreted according to the
** byte-order specified by the BOM. ^The byte-order specified by
** the BOM at the beginning of the text overrides the byte-order
** specified by the interface procedure. ^So, for example, if
** sqlite3_result_text16le() is invoked with text that begins
** with bytes 0xfe, 0xff (a big-endian byte-order mark) then the
** first two bytes of input are skipped and the remaining input
** is interpreted as UTF16BE text.
**
** ^For UTF16 input text to the sqlite3_result_text16(),
** sqlite3_result_text16be(), sqlite3_result_text16le(), and
** sqlite3_result_text64() routines, if the text contains invalid
** UTF16 characters, the invalid characters might be converted
** into the unicode replacement character, U+FFFD.
**
** ^The sqlite3_result_value() interface sets the result of
** the application-defined function to be a copy of the
** [unprotected sqlite3_value] object specified by the 2nd parameter. ^The
@@ -5817,51 +5949,6 @@ SQLITE_API int sqlite3_collation_needed16(
void(*)(void*,sqlite3*,int eTextRep,const void*)
);
#ifdef SQLITE_HAS_CODEC
/*
** Specify the key for an encrypted database. This routine should be
** called right after sqlite3_open().
**
** The code to implement this API is not available in the public release
** of SQLite.
*/
SQLITE_API int sqlite3_key(
sqlite3 *db, /* Database to be rekeyed */
const void *pKey, int nKey /* The key */
);
SQLITE_API int sqlite3_key_v2(
sqlite3 *db, /* Database to be rekeyed */
const char *zDbName, /* Name of the database */
const void *pKey, int nKey /* The key */
);
/*
** Change the key on an open database. If the current database is not
** encrypted, this routine will encrypt it. If pNew==0 or nNew==0, the
** database is decrypted.
**
** The code to implement this API is not available in the public release
** of SQLite.
*/
SQLITE_API int sqlite3_rekey(
sqlite3 *db, /* Database to be rekeyed */
const void *pKey, int nKey /* The new key */
);
SQLITE_API int sqlite3_rekey_v2(
sqlite3 *db, /* Database to be rekeyed */
const char *zDbName, /* Name of the database */
const void *pKey, int nKey /* The new key */
);
/*
** Specify the activation key for a SEE database. Unless
** activated, none of the SEE routines will work.
*/
SQLITE_API void sqlite3_activate_see(
const char *zPassPhrase /* Activation phrase */
);
#endif
#ifdef SQLITE_ENABLE_CEROD
/*
** Specify the activation key for a CEROD database. Unless
@@ -6100,6 +6187,57 @@ SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName);
*/
SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName);
/*
** CAPI3REF: Determine the transaction state of a database
** METHOD: sqlite3
**
** ^The sqlite3_txn_state(D,S) interface returns the current
** [transaction state] of schema S in database connection D. ^If S is NULL,
** then the highest transaction state of any schema on database connection D
** is returned. Transaction states are (in order of lowest to highest):
** <ol>
** <li value="0"> SQLITE_TXN_NONE
** <li value="1"> SQLITE_TXN_READ
** <li value="2"> SQLITE_TXN_WRITE
** </ol>
** ^If the S argument to sqlite3_txn_state(D,S) is not the name of
** a valid schema, then -1 is returned.
*/
SQLITE_API int sqlite3_txn_state(sqlite3*,const char *zSchema);
/*
** CAPI3REF: Allowed return values from [sqlite3_txn_state()]
** KEYWORDS: {transaction state}
**
** These constants define the current transaction state of a database file.
** ^The [sqlite3_txn_state(D,S)] interface returns one of these
** constants in order to describe the transaction state of schema S
** in [database connection] D.
**
** <dl>
** [[SQLITE_TXN_NONE]] <dt>SQLITE_TXN_NONE</dt>
** <dd>The SQLITE_TXN_NONE state means that no transaction is currently
** pending.</dd>
**
** [[SQLITE_TXN_READ]] <dt>SQLITE_TXN_READ</dt>
** <dd>The SQLITE_TXN_READ state means that the database is currently
** in a read transaction. Content has been read from the database file
** but nothing in the database file has changed. The transaction state
** will advanced to SQLITE_TXN_WRITE if any changes occur and there are
** no other conflicting concurrent write transactions. The transaction
** state will revert to SQLITE_TXN_NONE following a [ROLLBACK] or
** [COMMIT].</dd>
**
** [[SQLITE_TXN_WRITE]] <dt>SQLITE_TXN_WRITE</dt>
** <dd>The SQLITE_TXN_WRITE state means that the database is currently
** in a write transaction. Content has been written to the database file
** but has not yet committed. The transaction state will change to
** to SQLITE_TXN_NONE at the next [ROLLBACK] or [COMMIT].</dd>
*/
#define SQLITE_TXN_NONE 0
#define SQLITE_TXN_READ 1
#define SQLITE_TXN_WRITE 2
/*
** CAPI3REF: Find the next prepared statement
** METHOD: sqlite3
@@ -6190,7 +6328,7 @@ SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
** ^In the case of an update, this is the [rowid] after the update takes place.
**
** ^(The update hook is not invoked when internal system tables are
** modified (i.e. sqlite_master and sqlite_sequence).)^
** modified (i.e. sqlite_sequence).)^
** ^The update hook is not invoked when [WITHOUT ROWID] tables are modified.
**
** ^In the current implementation, the update hook
@@ -7292,7 +7430,7 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
** <ul>
** <li> SQLITE_MUTEX_FAST
** <li> SQLITE_MUTEX_RECURSIVE
** <li> SQLITE_MUTEX_STATIC_MASTER
** <li> SQLITE_MUTEX_STATIC_MAIN
** <li> SQLITE_MUTEX_STATIC_MEM
** <li> SQLITE_MUTEX_STATIC_OPEN
** <li> SQLITE_MUTEX_STATIC_PRNG
@@ -7494,7 +7632,7 @@ SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*);
*/
#define SQLITE_MUTEX_FAST 0
#define SQLITE_MUTEX_RECURSIVE 1
#define SQLITE_MUTEX_STATIC_MASTER 2
#define SQLITE_MUTEX_STATIC_MAIN 2
#define SQLITE_MUTEX_STATIC_MEM 3 /* sqlite3_malloc() */
#define SQLITE_MUTEX_STATIC_MEM2 4 /* NOT USED */
#define SQLITE_MUTEX_STATIC_OPEN 4 /* sqlite3BtreeOpen() */
@@ -7509,6 +7647,10 @@ SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*);
#define SQLITE_MUTEX_STATIC_VFS2 12 /* For use by extension VFS */
#define SQLITE_MUTEX_STATIC_VFS3 13 /* For use by application VFS */
/* Legacy compatibility: */
#define SQLITE_MUTEX_STATIC_MASTER 2
/*
** CAPI3REF: Retrieve the mutex for a database connection
** METHOD: sqlite3
@@ -7604,7 +7746,7 @@ SQLITE_API int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_PENDING_BYTE 11
#define SQLITE_TESTCTRL_ASSERT 12
#define SQLITE_TESTCTRL_ALWAYS 13
#define SQLITE_TESTCTRL_RESERVE 14
#define SQLITE_TESTCTRL_RESERVE 14 /* NOT USED */
#define SQLITE_TESTCTRL_OPTIMIZATIONS 15
#define SQLITE_TESTCTRL_ISKEYWORD 16 /* NOT USED */
#define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */
@@ -7622,7 +7764,8 @@ SQLITE_API int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_RESULT_INTREAL 27
#define SQLITE_TESTCTRL_PRNG_SEED 28
#define SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS 29
#define SQLITE_TESTCTRL_LAST 29 /* Largest TESTCTRL */
#define SQLITE_TESTCTRL_SEEK_COUNT 30
#define SQLITE_TESTCTRL_LAST 30 /* Largest TESTCTRL */
/*
** CAPI3REF: SQL Keyword Checking
@@ -9102,10 +9245,11 @@ SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *);
** CAPI3REF: Determine If Virtual Table Column Access Is For UPDATE
**
** If the sqlite3_vtab_nochange(X) routine is called within the [xColumn]
** method of a [virtual table], then it returns true if and only if the
** method of a [virtual table], then it might return true if the
** column is being fetched as part of an UPDATE operation during which the
** column value will not change. Applications might use this to substitute
** a return value that is less expensive to compute and that the corresponding
** column value will not change. The virtual table implementation can use
** this hint as permission to substitute a return value that is less
** expensive to compute and that the corresponding
** [xUpdate] method understands as a "no-change" value.
**
** If the [xColumn] method calls sqlite3_vtab_nochange() and finds that
@@ -9114,6 +9258,12 @@ SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *);
** any of the [sqlite3_result_int|sqlite3_result_xxxxx() interfaces].
** In that case, [sqlite3_value_nochange(X)] will return true for the
** same column in the [xUpdate] method.
**
** The sqlite3_vtab_nochange() routine is an optimization. Virtual table
** implementations should continue to give a correct answer even if the
** sqlite3_vtab_nochange() interface were to always return false. In the
** current implementation, the sqlite3_vtab_nochange() interface does always
** returns false for the enhanced [UPDATE FROM] statement.
*/
SQLITE_API int sqlite3_vtab_nochange(sqlite3_context*);
@@ -9255,6 +9405,7 @@ SQLITE_API void sqlite3_stmt_scanstatus_reset(sqlite3_stmt*);
/*
** CAPI3REF: Flush caches to disk mid-transaction
** METHOD: sqlite3
**
** ^If a write-transaction is open on [database connection] D when the
** [sqlite3_db_cacheflush(D)] interface invoked, any dirty
@@ -9287,6 +9438,7 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*);
/*
** CAPI3REF: The pre-update hook.
** METHOD: sqlite3
**
** ^These interfaces are only available if SQLite is compiled using the
** [SQLITE_ENABLE_PREUPDATE_HOOK] compile-time option.
@@ -9304,7 +9456,7 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*);
**
** ^The preupdate hook only fires for changes to real database tables; the
** preupdate hook is not invoked for changes to [virtual tables] or to
** system tables like sqlite_master or sqlite_stat1.
** system tables like sqlite_sequence or sqlite_stat1.
**
** ^The second parameter to the preupdate callback is a pointer to
** the [database connection] that registered the preupdate hook.
@@ -9327,7 +9479,7 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*);
** seventh parameter is the final rowid value of the row being inserted
** or updated. The value of the seventh parameter passed to the callback
** function is not defined for operations on WITHOUT ROWID tables, or for
** INSERT operations on rowid tables.
** DELETE operations on rowid tables.
**
** The [sqlite3_preupdate_old()], [sqlite3_preupdate_new()],
** [sqlite3_preupdate_count()], and [sqlite3_preupdate_depth()] interfaces
@@ -9389,6 +9541,7 @@ SQLITE_API int sqlite3_preupdate_new(sqlite3 *, int, sqlite3_value **);
/*
** CAPI3REF: Low-level system error code
** METHOD: sqlite3
**
** ^Attempt to return the underlying operating system error code or error
** number that caused the most recent I/O error or failure to open a file.

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);
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

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