Merge remote-tracking branch 'origin/4.13' into master

Conflicts:
	src/plugins/qmakeprojectmanager/qmakeproject.cpp

Change-Id: Ieb1c3e946f11d3c4fa1ee6b5afdf83cc532d8aed
This commit is contained in:
Eike Ziller
2020-09-17 10:28:19 +02:00
58 changed files with 2071 additions and 492 deletions

View File

@@ -584,7 +584,6 @@ SQLite (https://www.sqlite.org) is in the Public Domain.
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
\endcode
The class contains the UTF-8 Decoder from Bjoern Hoehrmann which is
licensed under the MIT License (see above). Copyright © 2008-2009 Björn
@@ -593,3 +592,70 @@ SQLite (https://www.sqlite.org) is in the Public Domain.
The class contains a slightly modified version of the Grisu2 algorithm
from Florian Loitsch which is licensed under the MIT License (see above).
Copyright © 2009 Florian Loitsch
### litehtml
The litehtml HTML/CSS rendering engine is used as a help viewer backend
to display help files.
The sources can be found in:
* QtCreator/src/plugins/help/qlitehtml
* https://github.com/litehtml
Copyright (c) 2013, Yuri Kobets (tordex)
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the <organization> nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
### gumbo
The litehtml HTML/CSS rendering engine uses the gumbo parser.
Copyright 2010, 2011 Google
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
### gumbo/utf8.c
The litehtml HTML/CSS rendering engine uses gumbo/utf8.c parser.
Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

108
dist/changes-4.13.1.md vendored Normal file
View File

@@ -0,0 +1,108 @@
Qt Creator 4.13.1
=================
Qt Creator version 4.13.1 contains bug fixes.
The most important changes are listed in this document. For a complete
list of changes, see the Git log for the Qt Creator sources that
you can check out from the public Git repository. For example:
git clone git://code.qt.io/qt-creator/qt-creator.git
git log --cherry-pick --pretty=oneline origin/v4.13.0..v4.13.1
Editing
-------
* Fixed whitespace cleaning (QTCREATORBUG-24565)
* Fixed selection color (QTCREATORBUG-24479)
### C++
* Fixed crash with adjacent raw string literals (QTCREATORBUG-24577)
### QML
* Fixed wrong diagnostics for `ListElement` (QDS-2602)
### Language Client
* Fixed performance issue
Projects
--------
* Fixed parsing of QTest application output (QTCREATORBUG-24560)
* Fixed visibility of output in output panes (QTCREATORBUG-24411)
### qmake
* Fixed handling of unset environment variables (QTCREATORBUG-21729)
### CMake
* Fixed removal of CMake tools
### Qbs
* Fixed install step
Debugging
---------
### GDB
* Fixed disabling of environment variables
Analyzer
--------
### Clang
* Updated Clazy to version 1.7
Qt Quick Designer
-----------------
* Improved composition of custom materials (QDS-2657)
* Fixed available items for MCU (QDS-2681, QDS-2512)
* Fixed visual artifacts when changing states
* Fixed rich text editor styling
* Fixed layout issues in state editor (QDS-2623, QDS-2615)
* Fixed support for `.hrd` images (QDS-2128)
Platforms
---------
### Android
* Fixed service handling in manifest editor (QTCREATORBUG-24557)
### macOS
* Fixed Clazy (QTCREATORBUG-24567)
Credits for these changes go to:
--------------------------------
Aleksei German
André Pönitz
Andy Shaw
Christian Kandeler
Christian Stenger
David Schulz
Dominik Holland
Eike Ziller
Henning Gruendl
Johanna Vanhatapio
Kai Köhne
Knud Dollereder
Leena Miettinen
Mahmoud Badri
Marco Bubke
Michael Winkelmann
Miikka Heikkinen
Orgad Shaneh
Sergey Belyashov
Thomas Hartmann
Venugopal Shivashankar
Vikas Pachdha
Ville Voutilainen

View File

@@ -935,7 +935,7 @@
\li \c value of type \c Value, wrapping either a
\l{https://sourceware.org/gdb/onlinedocs/gdb/Values-From-Inferior.html}
{gdb.Value} or an
\l{http://lldb.llvm.org/cpp_reference/html/classlldb_1_1SBValue.html}
\l{https://lldb.llvm.org/cpp_reference/classlldb_1_1SBValue.html}
{lldb.SBValue}.
\endlist
@@ -1440,9 +1440,9 @@
\uicontrol {Debugger Log} view. Browse the contents of the pane on
the right hand side to find out what went wrong. Always attach the
contents of the pane to debugger-related questions to the \QC
mailing list (qt-creator@trolltech.com) or paste them to
\l{http://creator.pastebin.com}{creator.pastebin.com} before asking
questions in the IRC (on the #qt-creator channel at FreeNode).
mailing list (qt-creator@qt-project.org) or paste them to a
\l{Pasting and Fetching Code Snippets}{code pasting service} before
asking questions in the IRC (on the #qt-creator channel at FreeNode).
\endlist

View File

@@ -84,7 +84,7 @@
as well as a ready-to-use QSyntaxHighlighter sub-class.
Distributed under the:
\code
\badcode
MIT License
Permission is hereby granted, free of charge, to any person obtaining
@@ -213,7 +213,7 @@
\l{https://spdx.org/licenses/BSD-3-Clause.html}
{BSD 3-clause "New" or "Revised" License}
\code
\badcode
Copyright (C) 2002-2013 The ANGLE Project Authors.
All rights reserved.
@@ -261,7 +261,7 @@
BSD 2-clause "Simplified" License.
\code
\badcode
Copyright (C) 2012 Apple Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -294,7 +294,7 @@
The sources can be found in
\c qtbase/src/3rdparty/angle/src/third_party/murmurhash.
\code
\badcode
MurmurHash3 was written by Austin Appleby, and is placed in the public
domain. The author hereby disclaims copyright to this source code.
\endcode
@@ -311,7 +311,7 @@
BSD 2-clause "Simplified" License.
\code
\badcode
Copyright (C) 2009 Apple Inc. All Rights Reserved.
Redistribution and use in source and binary forms, with or without
@@ -346,7 +346,7 @@
BSD 3-clause "New" or "Revised" License.
\code
\badcode
Copyright 2013 The Chromium Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -401,7 +401,7 @@
the OpenSSL License and the original SSLeay license apply to the toolkit.
See below for the actual license texts.
\code
\badcode
OpenSSL License
====================================================================
@@ -527,7 +527,7 @@
\l{https://spdx.org/licenses/MIT.html}{MIT License}:
\code
\badcode
Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining a
@@ -561,7 +561,7 @@
Copyright (C) 2013-2019 Niels Lohmann
\code
\badcode
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
@@ -589,5 +589,80 @@
from Florian Loitsch which is licensed under the MIT License (see above).
Copyright (C) 2009 Florian Loitsch
\li \b litehtml
The litehtml HTML/CSS rendering engine is used as a help viewer backend
to display help files.
The sources can be found in:
\list
\li \c QtCreator/src/plugins/help/qlitehtml
\li \l https://github.com/litehtml
\endlist
Copyright (c) 2013, Yuri Kobets (tordex)
\badcode
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the <organization> nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\endcode
\li \b gumbo
The litehtml HTML/CSS rendering engine uses the gumbo parser.
Copyright 2010, 2011 Google
\badcode
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
\endcode
\li \b {gumbo/utf8.c}
The litehtml HTML/CSS rendering engine uses gumbo/utf8.c parser.
Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
\badcode
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
\endcode
\endlist
*/

View File

@@ -94,7 +94,7 @@
compilers from the various KEIL development environments.
\note Currently supported architectures are \c 8051 and \c ARM.
\li \l{https://sdcc.sourceforge.net}{SDCC} is a retargetable, optimizing
\li \l{http://sdcc.sourceforge.net}{SDCC} is a retargetable, optimizing
C bare-metal compiler for various architectures.
\note Currently supported architectures are \c 8051 and \c STM8.

View File

@@ -60,8 +60,7 @@
\li Select \uicontrol {Force probes} to force re-execution of
the configure scripts of
\l{https://doc.qt.io/qbs/probe-item.html}{Probes}.
\li In the \uicontrol Flags field:
\l{https://doc.qt.io/qbs/qbsprobes-qmlmodule.html}{Probes}.
\endlist

View File

@@ -121,6 +121,8 @@ class Dumper(DumperBase):
self.process = None
self.target = None
self.fakeAddress_ = None
self.fakeLAddress_ = None
self.eventState = lldb.eStateInvalid
self.executable_ = None
@@ -258,10 +260,15 @@ class Dumper(DumperBase):
return align
def listMembers(self, value, nativeType):
#DumperBase.warn("ADDR: 0x%x" % self.fakeAddress)
fakeAddress = self.fakeAddress if value.laddress is None else value.laddress
sbaddr = lldb.SBAddress(fakeAddress, self.target)
fakeValue = self.target.CreateValueFromAddress('x', sbaddr, nativeType)
#DumperBase.warn("ADDR: 0x%x" % self.fakeAddress_)
if value.laddress:
fakeAddress = lldb.SBAddress(value.laddress, self.target)
fakeLAddress = value.laddress
else:
fakeAddress = self.fakeAddress_
fakeLAddress = self.fakeLAddress_
fakeValue = self.target.CreateValueFromAddress('x', fakeAddress, nativeType)
fakeValue.SetPreferSyntheticValue(False)
baseNames = {}
@@ -304,7 +311,7 @@ class Dumper(DumperBase):
fieldName = '#%s' % anonNumber
fakeMember = fakeValue.GetChildAtIndex(i)
fakeMemberAddress = fakeMember.GetLoadAddress()
offset = fakeMemberAddress - fakeAddress
offset = fakeMemberAddress - fakeLAddress
yield self.Field(self, name=fieldName, type=self.fromNativeType(nativeFieldType),
bitsize=fieldBitsize, bitpos=8 * offset)
@@ -1228,10 +1235,6 @@ class Dumper(DumperBase):
if not self.partialVariable:
self.resetPerStepCaches()
anyModule = self.target.GetModuleAtIndex(0)
anySymbol = anyModule.GetSymbolAtIndex(0)
self.fakeAddress = int(anySymbol.GetStartAddress())
frame = self.currentFrame()
if frame is None:
self.reportResult('error="No frame"', args)
@@ -1968,6 +1971,8 @@ class Tester(Dumper):
if line != 0:
self.report = savedReport
self.process.SetSelectedThread(stoppedThread)
self.fakeAddress_ = frame.GetPC()
self.fakeLAddress_ = frame.GetPCAddress()
self.fetchVariables(args)
#self.describeLocation(frame)
self.report('@NS@%s@' % self.qtNamespace())

View File

@@ -66,7 +66,10 @@ CapturedDataCommand::StateData collectStateData(ServerNodeInstance rootNodeInsta
nodeData.sceneTransform = instance.sceneTransform();
auto textProperty = instance.property("text");
if (!textProperty.isNull() && instance.holdsGraphical())
nodeData.properties.emplace_back(QString{"text"}, textProperty.toString());
nodeData.properties.emplace_back(QString{"text"}, textProperty);
auto colorProperty = instance.property("color");
if (!colorProperty.isNull())
nodeData.properties.emplace_back(QString{"color"}, colorProperty);
stateData.nodeData.push_back(std::move(nodeData));
}

View File

@@ -57,7 +57,7 @@ Section {
StudioControls.AbstractButton {
id: richTextEditorButton
buttonIcon: StudioTheme.Constants.textAlignTop
buttonIcon: StudioTheme.Constants.edit
onClicked: {
richTextDialogLoader.show()
}

View File

@@ -65,16 +65,8 @@ isEmpty(KSYNTAXHIGHLIGHTING_LIB_DIR) {
win32:SUBDIRS += utils/process_ctrlc_stub.pro
# Windows: Compile Qt Creator CDB extension if Debugging tools can be detected.
win32: isEmpty(QTC_SKIP_CDBEXT) {
include(qtcreatorcdbext/cdb_detect.pri)
!isEmpty(CDB_PATH): exists($$CDB_PATH) {
SUBDIRS += qtcreatorcdbext
} else {
message("Compiling Qt Creator without a CDB extension.")
message("If CDB is installed in a none default path define a CDB_PATH")
message("environment variable pointing to your CDB installation.")
}
SUBDIRS += qtcreatorcdbext
}
QMAKE_EXTRA_TARGETS += deployqt # dummy

View File

@@ -1838,7 +1838,10 @@ const Value *Check::checkScopeObjectMember(const UiQualifiedId *id)
const bool isListElementScope = (!m_typeStack.isEmpty() && m_typeStack.last() == "ListElement");
if (!value && !isListElementScope) {
if (isListElementScope)
return nullptr;
if (!value) {
addMessage(ErrInvalidPropertyName, id->identifierToken, propertyName);
return nullptr;
}

View File

@@ -2,30 +2,7 @@ if (NOT WIN32 OR NOT MSVC)
return()
endif()
find_path(WDbgExtsPath wdbgexts.h
HINTS
"$ENV{CDB_PATH}"
"$ENV{ProgramFiles}/Debugging Tools For Windows/sdk"
"$ENV{ProgramFiles}/Debugging Tools For Windows (x86)/sdk"
"$ENV{ProgramFiles}/Debugging Tools For Windows (x64)/sdk"
"$ENV{ProgramFiles}/Debugging Tools For Windows 64-bit/sdk"
"$ENV{ProgramW6432}/Debugging Tools For Windows (x86)/sdk"
"$ENV{ProgramW6432}/Debugging Tools For Windows (x64)/sdk"
"$ENV{ProgramW6432}/Debugging Tools For Windows 64-bit/sdk"
"$ENV{ProgramFiles}/Windows Kits/8.0/Debuggers"
"$ENV{ProgramFiles}/Windows Kits/8.1/Debuggers"
"$ENV{ProgramFiles}/Windows Kits/10/Debuggers"
"$ENV{ProgramFiles\(x86\)}/Windows Kits/8.0/Debuggers/inc"
"$ENV{ProgramFiles\(x86\)}/Windows Kits/8.1/Debuggers/inc"
"$ENV{ProgramFiles\(x86\)}/Windows Kits/10/Debuggers/inc"
)
if (NOT WDbgExtsPath)
message(WARNING "wdbgexts.h not found. Removing qtcreatorcdbext from build.")
return()
endif()
find_library(DbgEngLib dbgeng HINTS ${WDbgExtsPath})
find_library(DbgEngLib dbgeng)
set(ArchSuffix 32)
if (CMAKE_SIZEOF_VOID_P EQUAL 8)

View File

@@ -1,25 +0,0 @@
# Detect presence of "Debugging Tools For Windows"
# in case MS VS compilers are used.
CDB_PATH=""
msvc {
CDB_PATH="$$(CDB_PATH)"
isEmpty(CDB_PATH):CDB_PATH="$$(ProgramFiles)/Debugging Tools For Windows/sdk"
!exists($$CDB_PATH):CDB_PATH="$$(ProgramFiles)/Debugging Tools For Windows (x86)/sdk"
!exists($$CDB_PATH):CDB_PATH="$$(ProgramFiles)/Debugging Tools For Windows (x64)/sdk"
!exists($$CDB_PATH):CDB_PATH="$$(ProgramFiles)/Debugging Tools For Windows 64-bit/sdk"
!exists($$CDB_PATH):CDB_PATH="$$(ProgramW6432)/Debugging Tools For Windows (x86)/sdk"
!exists($$CDB_PATH):CDB_PATH="$$(ProgramW6432)/Debugging Tools For Windows (x64)/sdk"
!exists($$CDB_PATH):CDB_PATH="$$(ProgramW6432)/Debugging Tools For Windows 64-bit/sdk"
# Starting from Windows SDK 8, the headers and libs are under 'ProgramFiles (x86)'.
# The libraries are under 'ProgramFiles'as well, so, check for existence of 'inc'.
# 32bit qmake:
!exists($$CDB_PATH/inc):CDB_PATH="$$(ProgramFiles)/Windows Kits/8.0/Debuggers"
!exists($$CDB_PATH/inc):CDB_PATH="$$(ProgramFiles)/Windows Kits/8.1/Debuggers"
!exists($$CDB_PATH/inc):CDB_PATH="$$(ProgramFiles)/Windows Kits/10/Debuggers"
# 64bit qmake:
!exists($$CDB_PATH/inc):CDB_PATH="$$(ProgramFiles) (x86)/Windows Kits/8.0/Debuggers"
!exists($$CDB_PATH/inc):CDB_PATH="$$(ProgramFiles) (x86)/Windows Kits/8.1/Debuggers"
!exists($$CDB_PATH/inc):CDB_PATH="$$(ProgramFiles) (x86)/Windows Kits/10/Debuggers"
!exists($$CDB_PATH/inc):CDB_PATH=""
}

View File

@@ -2,7 +2,6 @@
TEMPLATE = lib
include(../../../qtcreator.pri)
include(cdb_detect.pri)
isEmpty(QTC_KEEP_CDBEXT_DEFAULT_CONFIG): CONFIG += release
@@ -30,45 +29,21 @@ DEF_FILE=$$PWD/qtcreatorcdbext.def
ENV_TARGET_ARCH=$$(VSCMD_ARG_TGT_ARCH)
isEmpty(ENV_TARGET_ARCH):ENV_TARGET_ARCH = $$(Platform)
ENV_LIBPATH=$$(LIBPATH)
contains(ENV_TARGET_ARCH, .*64$) {
DIRNAME=$${BASENAME}64
CDB_PLATFORM=amd64
exists($$CDB_PATH/lib/amd64) {
LIBS+= -L$$CDB_PATH/lib/amd64 -ldbgeng
} else {
LIBS+= -L$$CDB_PATH/lib/x64 -ldbgeng
}
} else:isEmpty(ENV_TARGET_ARCH):contains(ENV_LIBPATH, ^.*amd64.*$) {
DIRNAME=$${BASENAME}64
CDB_PLATFORM=amd64
exists($$CDB_PATH/lib/amd64) {
LIBS+= -L$$CDB_PATH/lib/amd64 -ldbgeng
} else {
LIBS+= -L$$CDB_PATH/lib/x64 -ldbgeng
}
} else {
DIRNAME=$${BASENAME}32
CDB_PLATFORM=i386
exists($$CDB_PATH/lib/i386}) {
LIBS+= -L$$CDB_PATH/lib/i386 -ldbgeng
} else {
LIBS+= -L$$CDB_PATH/lib/x86 -ldbgeng
}
}
LIBS+=-luser32
LIBS+=-ldbgeng -luser32
DESTDIR=$$IDE_BUILD_TREE/lib/$${DIRNAME}
TARGET = $$BASENAME
message("Compiling Qt Creator CDB extension $$TARGET $$DESTDIR for $$CDB_PLATFORM using $$CDB_PATH")
INCLUDEPATH += $$CDB_PATH/inc
message("Compiling Qt Creator CDB extension $$TARGET $$DESTDIR for $$CDB_PLATFORM")
CONFIG -= qt
QT -= gui

View File

@@ -6,47 +6,9 @@ import qbs.Process
import qbs.Utilities
QtcLibrary {
condition: qbs.toolchain.contains("msvc") && cdbPath
condition: qbs.toolchain.contains("msvc")
name: "qtcreatorcdbext"
targetName: name
property string cdbPath: {
var paths = [
Environment.getEnv("CDB_PATH"),
Environment.getEnv("ProgramFiles") + "/Debugging Tools For Windows/sdk",
Environment.getEnv("ProgramFiles") + "/Debugging Tools For Windows (x86)/sdk",
Environment.getEnv("ProgramFiles") + "/Debugging Tools For Windows (x64)/sdk",
Environment.getEnv("ProgramFiles") + "/Debugging Tools For Windows 64-bit/sdk",
Environment.getEnv("ProgramW6432") + "/Debugging Tools For Windows (x86)/sdk",
Environment.getEnv("ProgramW6432") + "/Debugging Tools For Windows (x64)/sdk",
Environment.getEnv("ProgramW6432") + "/Debugging Tools For Windows 64-bit/sdk",
Environment.getEnv("ProgramFiles") + "/Windows Kits/8.0/Debuggers",
Environment.getEnv("ProgramFiles") + "/Windows Kits/8.1/Debuggers",
Environment.getEnv("ProgramFiles") + "/Windows Kits/10/Debuggers",
Environment.getEnv("ProgramFiles(x86)") + "/Windows Kits/8.0/Debuggers/inc",
Environment.getEnv("ProgramFiles(x86)") + "/Windows Kits/8.1/Debuggers/inc",
Environment.getEnv("ProgramFiles(x86)") + "/Windows Kits/10/Debuggers/inc"
];
var c = paths.length;
for (var i = 0; i < c; ++i) {
if (File.exists(paths[i])) {
// The inc subdir is just used for detection. See qtcreatorcdbext.pro.
return paths[i].endsWith("/inc") ? paths[i].substr(0, paths[i].length - 4)
: paths[i];
}
}
return undefined;
}
property string cdbLibPath: {
var paths = qbs.architecture.contains("x86_64") ? ["x64", "amd64"] : ["x86", "i386"];
var c = paths.length;
for (var i = 0; i < c; ++i) {
var libPath = FileInfo.joinPaths(cdbPath, "lib", paths[i]);
if (File.exists(libPath)) {
return libPath;
}
}
return undefined;
}
property string pythonInstallDir: Environment.getEnv("PYTHON_INSTALL_DIR")
@@ -127,13 +89,12 @@ QtcLibrary {
cpp.defines: ["WITH_PYTHON=1"]
}
cpp.includePaths: {
var paths = [FileInfo.joinPaths(cdbPath, "inc")];
if (pythonDllProbe.found)
paths.push(FileInfo.joinPaths(pythonInstallDir, "include"));
return paths;
return [ FileInfo.joinPaths(pythonInstallDir, "include") ];
return [ ];
}
cpp.dynamicLibraries: {
var libs = [ "user32.lib", FileInfo.joinPaths(cdbLibPath, "dbgeng.lib") ];
var libs = [ "user32.lib", "dbgeng.lib" ];
if (pythonDllProbe.found)
libs.push(FileInfo.joinPaths(pythonInstallDir, "libs",
pythonDllProbe.fileNamePrefix + ".lib"));

View File

@@ -429,6 +429,7 @@ void OutputFormatter::append(const QString &text, const QTextCharFormat &format)
{
if (!plainTextEdit())
return;
flushTrailingNewline();
int startPos = 0;
int crPos = -1;
while ((crPos = text.indexOf('\r', startPos)) >= 0) {
@@ -437,7 +438,6 @@ void OutputFormatter::append(const QString &text, const QTextCharFormat &format)
d->cursor.movePosition(QTextCursor::StartOfBlock, QTextCursor::KeepAnchor);
startPos = crPos + 1;
}
flushTrailingNewline();
if (startPos < text.count())
d->cursor.insertText(text.mid(startPos), format);
}

View File

@@ -206,8 +206,6 @@ void BoostTestOutputReader::processOutputLine(const QByteArray &outputLine)
static QRegularExpression finish("^\\*{3} (\\d+) failure(s are| is) detected in the "
"test module \"(.*)\"$");
static QRegularExpression errDetect("^\\*{3} Errors where detected in the "
"test module \"(.*}\"; see standard output for details");
QString noErrors("*** No errors detected");
const QString line = removeCommandlineColors(QString::fromUtf8(outputLine));
@@ -340,8 +338,7 @@ void BoostTestOutputReader::processOutputLine(const QByteArray &outputLine)
BoostTestResult *result = new BoostTestResult(id(), m_projectFile, QString());
int failed = match.captured(1).toInt();
QString txt = tr("%1 failures detected in %2.").arg(failed).arg(match.captured(3));
int passed = (m_testCaseCount != -1)
? m_testCaseCount - failed - m_summary[ResultType::Skip] : -1;
int passed = (m_testCaseCount != -1) ? m_testCaseCount - failed : -1;
if (m_testCaseCount != -1)
txt.append(' ').append(tr("%1 tests passed.").arg(passed));
result->setDescription(txt);

View File

@@ -268,7 +268,7 @@ void TestRunner::cancelCurrent(TestRunner::CancelReason reason)
void TestRunner::onProcessFinished()
{
if (m_executingTests && QTC_GUARD(m_currentConfig)) {
if (m_executingTests && m_currentConfig) {
QTC_CHECK(m_fakeFutureInterface);
m_fakeFutureInterface->setProgressValue(m_fakeFutureInterface->progressValue()
+ m_currentConfig->testCaseCount());
@@ -286,13 +286,15 @@ void TestRunner::onProcessFinished()
}
}
}
const int disabled = m_currentOutputReader->disabledTests();
if (disabled > 0)
emit hadDisabledTests(disabled);
if (m_currentOutputReader->hasSummary())
emit reportSummary(m_currentOutputReader->id(), m_currentOutputReader->summary());
if (m_currentOutputReader) {
const int disabled = m_currentOutputReader->disabledTests();
if (disabled > 0)
emit hadDisabledTests(disabled);
if (m_currentOutputReader->hasSummary())
emit reportSummary(m_currentOutputReader->id(), m_currentOutputReader->summary());
m_currentOutputReader->resetCommandlineColor();
m_currentOutputReader->resetCommandlineColor();
}
resetInternalPointers();
if (!m_fakeFutureInterface) {

View File

@@ -590,7 +590,7 @@ class TestFormatterA : public OutputLineParser
private:
Result handleLine(const QString &text, OutputFormat) override
{
static const QString replacement = "handled by A\n";
static const QString replacement = "handled by A";
if (m_handling) {
if (text.startsWith("A")) {
m_handling = false;
@@ -615,7 +615,7 @@ private:
Result handleLine(const QString &text, OutputFormat) override
{
if (text.startsWith("B"))
return {Status::Done, {}, QString("handled by B\n")};
return {Status::Done, {}, QString("handled by B")};
return Status::NotHandled;
}
};
@@ -656,6 +656,7 @@ void Internal::CorePlugin::testOutputFormatter()
formatter.setLineParsers({new TestFormatterB, new TestFormatterA});
formatter.appendMessage(input.left(i), StdOutFormat);
formatter.appendMessage(input.mid(i), StdOutFormat);
formatter.flush();
QCOMPARE(textEdit.toPlainText(), output);
}
}

View File

@@ -204,11 +204,11 @@ void DoxygenTest::testBasic_data()
QTest::newRow("cpp_styleA_indented_preserve_mixed_indention_continuation") << _(
"\t bool preventFolding;\n"
"\t /// \brief a|\n"
"\t /// \\brief a|\n"
"\t int a;\n"
) << _(
"\t bool preventFolding;\n"
"\t /// \brief a\n"
"\t /// \\brief a\n"
"\t /// \n"
"\t int a;\n"
);

View File

@@ -1088,10 +1088,12 @@ void DebuggerEngine::gotoLocation(const Location &loc)
const QString file = loc.fileName().toString();
const int line = loc.lineNumber();
bool newEditor = false;
IEditor *editor = EditorManager::openEditor(
file, Id(),
EditorManager::IgnoreNavigationHistory | EditorManager::DoNotSwitchToDesignMode,
&newEditor);
IEditor *editor = EditorManager::openEditor(file,
Id(),
EditorManager::IgnoreNavigationHistory
| EditorManager::DoNotSwitchToDesignMode
| EditorManager::SwitchSplitIfAlreadyVisible,
&newEditor);
QTC_ASSERT(editor, return); // Unreadable file?
editor->gotoLine(line, 0, !boolSetting(StationaryEditorWhileStepping));

View File

@@ -64,7 +64,6 @@
#include <QFileDialog>
#include <limits>
#include <memory>
/*!
\class ProjectExplorer::Project
@@ -357,7 +356,8 @@ void Project::setNeedsInitialExpansion(bool needsExpansion)
d->m_needsInitialExpansion = needsExpansion;
}
void Project::setExtraProjectFiles(const QSet<Utils::FilePath> &projectDocumentPaths)
void Project::setExtraProjectFiles(const QSet<Utils::FilePath> &projectDocumentPaths,
const DocGenerator docGenerator)
{
QSet<Utils::FilePath> uniqueNewFiles = projectDocumentPaths;
uniqueNewFiles.remove(projectFilePath()); // Make sure to never add the main project file!
@@ -372,8 +372,14 @@ void Project::setExtraProjectFiles(const QSet<Utils::FilePath> &projectDocumentP
return toRemove.contains(d->filePath());
});
for (const Utils::FilePath &p : toAdd) {
d->m_extraProjectDocuments.emplace_back(
std::make_unique<ProjectDocument>(d->m_document->mimeType(), p, this));
if (docGenerator) {
std::unique_ptr<Core::IDocument> doc = docGenerator(p);
QTC_ASSERT(doc, continue);
d->m_extraProjectDocuments.push_back(std::move(doc));
} else {
d->m_extraProjectDocuments.emplace_back(std::make_unique<ProjectDocument>(
d->m_document->mimeType(), p, this));
}
}
}
@@ -802,6 +808,19 @@ bool Project::isKnownFile(const Utils::FilePath &filename) const
&element, nodeLessThan);
}
const Node *Project::nodeForFilePath(const Utils::FilePath &filePath,
const Project::NodeMatcher &extraMatcher)
{
const FileNode dummy(filePath, FileType::Unknown);
const auto range = std::equal_range(d->m_sortedNodeList.cbegin(), d->m_sortedNodeList.cend(),
&dummy, &nodeLessThan);
for (auto it = range.first; it != range.second; ++it) {
if ((*it)->filePath() == filePath && (!extraMatcher || extraMatcher(*it)))
return *it;
}
return nullptr;
}
void Project::setProjectLanguages(Core::Context language)
{
if (d->m_projectLanguages == language)

View File

@@ -39,6 +39,7 @@
#include <QFileSystemModel>
#include <functional>
#include <memory>
namespace Core { class Context; }
namespace Utils {
@@ -123,6 +124,8 @@ public:
Utils::FilePaths files(const NodeMatcher &matcher) const;
bool isKnownFile(const Utils::FilePath &filename) const;
const Node *nodeForFilePath(const Utils::FilePath &filePath,
const NodeMatcher &extraMatcher = {});
virtual QVariantMap toMap() const;
@@ -159,9 +162,11 @@ public:
void setRootProjectNode(std::unique_ptr<ProjectNode> &&root);
// Set project files that will be watched and trigger the same callback
// Set project files that will be watched and by default trigger the same callback
// as the main project file.
void setExtraProjectFiles(const QSet<Utils::FilePath> &projectDocumentPaths);
using DocGenerator = std::function<std::unique_ptr<Core::IDocument>(const Utils::FilePath &)>;
void setExtraProjectFiles(const QSet<Utils::FilePath> &projectDocumentPaths,
const DocGenerator docGenerator = {});
void setDisplayName(const QString &name);
void setProjectLanguage(Utils::Id id, bool enabled);

View File

@@ -281,6 +281,7 @@ PythonRunConfiguration::PythonRunConfiguration(Target *target, Utils::Id id)
const QString script = bti.targetFilePath.toUserOutput();
setDefaultDisplayName(tr("Run %1").arg(script));
scriptAspect->setValue(script);
aspect<WorkingDirectoryAspect>()->setDefaultWorkingDirectory(bti.targetFilePath.parentDir());
});
connect(target, &Target::buildSystemUpdated, this, &RunConfiguration::update);
@@ -298,9 +299,6 @@ void PythonRunConfiguration::updateLanguageServer()
PyLSConfigureAssistant::instance()->openDocumentWithPython(python, document);
}
}
aspect<WorkingDirectoryAspect>()->setDefaultWorkingDirectory(
Utils::FilePath::fromString(mainScript()).parentDir());
}
bool PythonRunConfiguration::supportsDebugger() const

View File

@@ -63,41 +63,6 @@ using namespace QmakeProjectManager::Internal;
using namespace QMakeInternal;
using namespace Utils;
namespace {
class QmakePriFileDocument : public Core::IDocument
{
public:
QmakePriFileDocument(QmakePriFile *qmakePriFile, const Utils::FilePath &filePath) :
IDocument(nullptr), m_priFile(qmakePriFile)
{
setId("Qmake.PriFile");
setMimeType(QLatin1String(QmakeProjectManager::Constants::PROFILE_MIMETYPE));
setFilePath(filePath);
}
ReloadBehavior reloadBehavior(ChangeTrigger state, ChangeType type) const override
{
Q_UNUSED(state)
Q_UNUSED(type)
return BehaviorSilent;
}
bool reload(QString *errorString, ReloadFlag flag, ChangeType type) override
{
Q_UNUSED(errorString)
Q_UNUSED(flag)
if (type == TypePermissions)
return true;
m_priFile->scheduleUpdate();
return true;
}
private:
QmakePriFile *m_priFile;
};
} // namespace
namespace QmakeProjectManager {
static Q_LOGGING_CATEGORY(qmakeParse, "qtc.qmake.parsing", QtWarningMsg);

View File

@@ -33,6 +33,7 @@
#include "qmakeprojectmanagerconstants.h"
#include "qmakestep.h"
#include <coreplugin/documentmanager.h>
#include <coreplugin/icontext.h>
#include <coreplugin/icore.h>
#include <coreplugin/progressmanager/progressmanager.h>
@@ -97,6 +98,38 @@ static Q_LOGGING_CATEGORY(qmakeBuildSystemLog, "qtc.qmake.buildsystem", QtWarnin
<< msg; \
}
class QmakePriFileDocument : public Core::IDocument
{
public:
QmakePriFileDocument(QmakePriFile *qmakePriFile, const Utils::FilePath &filePath) :
IDocument(nullptr), m_priFile(qmakePriFile)
{
setId("Qmake.PriFile");
setMimeType(QLatin1String(QmakeProjectManager::Constants::PROFILE_MIMETYPE));
setFilePath(filePath);
Core::DocumentManager::addDocument(this);
}
ReloadBehavior reloadBehavior(ChangeTrigger state, ChangeType type) const override
{
Q_UNUSED(state)
Q_UNUSED(type)
return BehaviorSilent;
}
bool reload(QString *errorString, ReloadFlag flag, ChangeType type) override
{
Q_UNUSED(errorString)
Q_UNUSED(flag)
if (type == TypePermissions)
return true;
m_priFile->scheduleUpdate();
return true;
}
private:
QmakePriFile *m_priFile;
};
/// Watches folders for QmakePriFile nodes
/// use one file system watcher to watch all folders
/// such minimizing system ressouce usage
@@ -266,8 +299,17 @@ void QmakeBuildSystem::updateDocuments()
QSet<FilePath> projectDocuments;
project()->rootProjectNode()->forEachProjectNode([&projectDocuments](const ProjectNode *n) {
projectDocuments.insert(n->filePath());
});
project()->setExtraProjectFiles(projectDocuments, [p = project()](const FilePath &fp)
-> std::unique_ptr<Core::IDocument> {
const Node * const n = p->nodeForFilePath(fp, [](const Node *n) {
return dynamic_cast<const QmakePriFileNode *>(n); });
QTC_ASSERT(n, return std::make_unique<Core::IDocument>());
QmakePriFile * const priFile = static_cast<const QmakePriFileNode *>(n)->priFile();
QTC_ASSERT(priFile, return std::make_unique<Core::IDocument>());
return std::make_unique<QmakePriFileDocument>(priFile, fp);
});
project()->setExtraProjectFiles(projectDocuments);
}
void QmakeBuildSystem::updateCppCodeModel()

View File

@@ -589,8 +589,11 @@ extend_qtc_plugin(QmlDesigner
SOURCES_PREFIX components/bindingeditor
SOURCES bindingeditor.cpp bindingeditor.h
actioneditor.cpp actioneditor.h
abstracteditordialog.cpp abstracteditordialog.h
actioneditordialog.cpp actioneditordialog.h
bindingeditordialog.cpp bindingeditordialog.h
bindingeditorwidget.cpp bindingeditorwidget.h
connectionvisitor.cpp connectionvisitor.h
)
extend_qtc_plugin(QmlDesigner

View File

@@ -0,0 +1,183 @@
/****************************************************************************
**
** 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 "abstracteditordialog.h"
#include <texteditor/texteditor.h>
#include <qmldesigner/qmldesignerplugin.h>
#include <qmljseditor/qmljseditor.h>
#include <qmljseditor/qmljseditordocument.h>
#include <texteditor/textdocument.h>
#include <QDialogButtonBox>
#include <QPushButton>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QPlainTextEdit>
namespace QmlDesigner {
AbstractEditorDialog::AbstractEditorDialog(QWidget *parent, const QString &title)
: QDialog(parent)
, m_titleString(title)
{
setWindowFlag(Qt::Tool, true);
setWindowTitle(defaultTitle());
setModal(false);
setupJSEditor();
setupUIComponents();
QObject::connect(m_buttonBox, &QDialogButtonBox::accepted,
this, &AbstractEditorDialog::accepted);
QObject::connect(m_buttonBox, &QDialogButtonBox::rejected,
this, &AbstractEditorDialog::rejected);
QObject::connect(m_editorWidget, &BindingEditorWidget::returnKeyClicked,
this, &AbstractEditorDialog::accepted);
QObject::connect(m_editorWidget, &QPlainTextEdit::textChanged,
this, &AbstractEditorDialog::textChanged);
}
AbstractEditorDialog::~AbstractEditorDialog()
{
delete m_editor; // m_editorWidget is handled by basetexteditor destructor
delete m_buttonBox;
delete m_comboBoxLayout;
delete m_verticalLayout;
}
void AbstractEditorDialog::showWidget()
{
this->show();
this->raise();
m_editorWidget->setFocus();
}
void AbstractEditorDialog::showWidget(int x, int y)
{
showWidget();
move(QPoint(x, y));
}
QString AbstractEditorDialog::editorValue() const
{
if (!m_editorWidget)
return {};
return m_editorWidget->document()->toPlainText();
}
void AbstractEditorDialog::setEditorValue(const QString &text)
{
if (m_editorWidget)
m_editorWidget->document()->setPlainText(text);
}
void AbstractEditorDialog::unregisterAutoCompletion()
{
if (m_editorWidget)
m_editorWidget->unregisterAutoCompletion();
}
QString AbstractEditorDialog::defaultTitle() const
{
return m_titleString;
}
void AbstractEditorDialog::setupJSEditor()
{
static BindingEditorFactory f;
m_editor = qobject_cast<TextEditor::BaseTextEditor*>(f.createEditor());
m_editorWidget = qobject_cast<BindingEditorWidget*>(m_editor->editorWidget());
Core::Context context = m_editor->context();
context.prepend(BINDINGEDITOR_CONTEXT_ID);
m_editorWidget->m_context->setContext(context);
auto qmlDesignerEditor = QmlDesignerPlugin::instance()->currentDesignDocument()->textEditor();
m_editorWidget->qmljsdocument = qobject_cast<QmlJSEditor::QmlJSEditorWidget *>(
qmlDesignerEditor->widget())->qmlJsEditorDocument();
m_editorWidget->setLineNumbersVisible(false);
m_editorWidget->setMarksVisible(false);
m_editorWidget->setCodeFoldingSupported(false);
m_editorWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
m_editorWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
m_editorWidget->setTabChangesFocus(true);
}
void AbstractEditorDialog::setupUIComponents()
{
m_verticalLayout = new QVBoxLayout(this);
m_comboBoxLayout = new QHBoxLayout;
m_editorWidget->setParent(this);
m_editorWidget->setFrameStyle(QFrame::StyledPanel | QFrame::Raised);
m_editorWidget->show();
m_buttonBox = new QDialogButtonBox(this);
m_buttonBox->setOrientation(Qt::Horizontal);
m_buttonBox->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
m_buttonBox->button(QDialogButtonBox::Ok)->setDefault(true);
m_verticalLayout->addLayout(m_comboBoxLayout);
m_verticalLayout->addWidget(m_editorWidget);
m_verticalLayout->addWidget(m_buttonBox);
this->resize(660, 240);
}
bool AbstractEditorDialog::isNumeric(const TypeName &type)
{
static QList<TypeName> numericTypes = {"double", "int", "real"};
return numericTypes.contains(type);
}
bool AbstractEditorDialog::isColor(const TypeName &type)
{
static QList<TypeName> colorTypes = {"QColor", "color"};
return colorTypes.contains(type);
}
bool AbstractEditorDialog::isVariant(const TypeName &type)
{
static QList<TypeName> variantTypes = {"alias", "unknown", "variant", "var"};
return variantTypes.contains(type);
}
void AbstractEditorDialog::textChanged()
{
if (m_lock)
return;
m_lock = true;
adjustProperties();
m_lock = false;
}
} // QmlDesigner namespace

View File

@@ -0,0 +1,93 @@
/****************************************************************************
**
** 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.
**
****************************************************************************/
#ifndef ABSTRACTEDITORDIALOG_H
#define ABSTRACTEDITORDIALOG_H
#include <bindingeditor/bindingeditorwidget.h>
#include <qmldesignercorelib_global.h>
#include <texteditor/texteditor.h>
#include <QDialog>
QT_BEGIN_NAMESPACE
class QDialogButtonBox;
class QVBoxLayout;
class QHBoxLayout;
QT_END_NAMESPACE
namespace QmlDesigner {
class AbstractEditorDialog : public QDialog
{
Q_OBJECT
public:
AbstractEditorDialog(QWidget *parent = nullptr, const QString &title = tr("Untitled Editor"));
~AbstractEditorDialog() override;
void showWidget();
void showWidget(int x, int y);
QString editorValue() const;
void setEditorValue(const QString &text);
virtual void adjustProperties()= 0;
void unregisterAutoCompletion();
QString defaultTitle() const;
BindingEditorWidget *bindingEditorWidget() const
{
return m_editorWidget;
}
protected:
void setupJSEditor();
void setupUIComponents();
static bool isNumeric(const TypeName &type);
static bool isColor(const TypeName &type);
static bool isVariant(const TypeName &type);
public slots:
void textChanged();
protected:
TextEditor::BaseTextEditor *m_editor = nullptr;
BindingEditorWidget *m_editorWidget = nullptr;
QVBoxLayout *m_verticalLayout = nullptr;
QDialogButtonBox *m_buttonBox = nullptr;
QHBoxLayout *m_comboBoxLayout = nullptr;
bool m_lock = false;
QString m_titleString;
const QString undefinedString = {"[Undefined]"};
};
}
#endif //ABSTRACTEDITORDIALOG_H

View File

@@ -28,6 +28,7 @@
#include <qmldesignerplugin.h>
#include <coreplugin/icore.h>
#include <coreplugin/actionmanager/actionmanager.h>
#include <bindingeditor/actioneditordialog.h>
#include <metainfo.h>
#include <qmlmodelnodeproxy.h>
@@ -35,6 +36,14 @@
#include <nodelistproperty.h>
#include <propertyeditorvalue.h>
#include <bindingproperty.h>
#include <variantproperty.h>
#include <qmljs/qmljsscopechain.h>
#include <qmljs/qmljsvalueowner.h>
static Q_LOGGING_CATEGORY(ceLog, "qtc.qmldesigner.connectioneditor", QtWarningMsg)
namespace QmlDesigner {
static ActionEditor *s_lastActionEditor = nullptr;
@@ -58,15 +67,14 @@ void ActionEditor::prepareDialog()
{
if (s_lastActionEditor)
s_lastActionEditor->hideWidget();
s_lastActionEditor = this;
m_dialog = new BindingEditorDialog(Core::ICore::dialogParent(),
BindingEditorDialog::DialogType::ActionDialog);
m_dialog = new ActionEditorDialog(Core::ICore::dialogParent());
QObject::connect(m_dialog, &BindingEditorDialog::accepted,
QObject::connect(m_dialog, &AbstractEditorDialog::accepted,
this, &ActionEditor::accepted);
QObject::connect(m_dialog, &BindingEditorDialog::rejected,
QObject::connect(m_dialog, &AbstractEditorDialog::rejected,
this, &ActionEditor::rejected);
m_dialog->setAttribute(Qt::WA_DeleteOnClose);
@@ -88,14 +96,14 @@ void ActionEditor::hideWidget()
{
if (s_lastActionEditor == this)
s_lastActionEditor = nullptr;
if (m_dialog)
{
m_dialog->unregisterAutoCompletion(); //we have to do it separately, otherwise we have an autocompletion action override
if (m_dialog) {
m_dialog->unregisterAutoCompletion(); // we have to do it separately, otherwise we have an autocompletion action override
m_dialog->close();
}
}
QString ActionEditor::bindingValue() const
QString ActionEditor::connectionValue() const
{
if (!m_dialog)
return {};
@@ -103,7 +111,7 @@ QString ActionEditor::bindingValue() const
return m_dialog->editorValue();
}
void ActionEditor::setBindingValue(const QString &text)
void ActionEditor::setConnectionValue(const QString &text)
{
if (m_dialog)
m_dialog->setEditorValue(text);
@@ -129,11 +137,160 @@ void ActionEditor::setModelIndex(const QModelIndex &index)
m_index = index;
}
void ActionEditor::setModelNode(const ModelNode &modelNode)
{
if (modelNode.isValid())
m_modelNode = modelNode;
}
bool isLiteral(QmlJS::AST::Node *ast)
{
if (QmlJS::AST::cast<QmlJS::AST::StringLiteral *>(ast)
|| QmlJS::AST::cast<QmlJS::AST::NumericLiteral *>(ast)
|| QmlJS::AST::cast<QmlJS::AST::TrueLiteral *>(ast)
|| QmlJS::AST::cast<QmlJS::AST::FalseLiteral *>(ast))
return true;
else
return false;
}
void ActionEditor::prepareConnections()
{
if (!m_modelNode.isValid())
return;
BindingEditorWidget *bindingEditorWidget = m_dialog->bindingEditorWidget();
if (!bindingEditorWidget) {
qCInfo(ceLog) << Q_FUNC_INFO << "BindingEditorWidget is missing!";
return;
}
if (!bindingEditorWidget->qmlJsEditorDocument()) {
qCInfo(ceLog) << Q_FUNC_INFO << "QmlJsEditorDocument is missing!";
return;
}
// Prepare objects for analysing slots
const QmlJSTools::SemanticInfo &semanticInfo = bindingEditorWidget->qmljsdocument->semanticInfo();
const QList<QmlJS::AST::Node *> path = semanticInfo.rangePath(0);
const QmlJS::ContextPtr &context = semanticInfo.context;
const QmlJS::ScopeChain &scopeChain = semanticInfo.scopeChain(path);
static QList<TypeName> typeWhiteList({"string",
"real", "int", "double",
"bool",
"QColor", "color",
"QtQuick.Item", "QQuickItem"});
static QList<PropertyName> methodBlackList({"toString", "destroy"});
QList<ActionEditorDialog::ConnectionOption> connections;
QList<ActionEditorDialog::SingletonOption> singletons;
QStringList states;
const QList<QmlDesigner::ModelNode> allNodes = m_modelNode.view()->allModelNodes();
for (const auto &modelNode : allNodes) {
// Skip nodes without specified id
if (!modelNode.hasId())
continue;
ActionEditorDialog::ConnectionOption connection(modelNode.id());
for (const auto &propertyName : modelNode.metaInfo().propertyNames()) {
if (!typeWhiteList.contains(modelNode.metaInfo().propertyTypeName(propertyName)))
continue;
const QString name = QString::fromUtf8(propertyName);
TypeName type = modelNode.metaInfo().propertyTypeName(propertyName);
if (type.contains("<cpp>."))
type.remove(0, 6);
connection.properties.append(ActionEditorDialog::PropertyOption(name, type));
}
for (const VariantProperty &variantProperty : modelNode.variantProperties()) {
if (variantProperty.isValid()) {
if (variantProperty.isDynamic()) {
if (!typeWhiteList.contains(variantProperty.dynamicTypeName()))
continue;
const QString name = QString::fromUtf8(variantProperty.name());
TypeName type = variantProperty.dynamicTypeName();
if (type.contains("<cpp>."))
type.remove(0, 6);
connection.properties.append(ActionEditorDialog::PropertyOption(name, type));
}
}
}
for (const auto &slotName : modelNode.metaInfo().slotNames()) {
QmlJS::Document::MutablePtr newDoc = QmlJS::Document::create(
QLatin1String("<expression>"), QmlJS::Dialect::JavaScript);
newDoc->setSource(QLatin1String(slotName));
newDoc->parseExpression();
QmlJS::AST::ExpressionNode *expression = newDoc->expression();
if (expression && !isLiteral(expression)) {
QmlJS::ValueOwner *interp = context->valueOwner();
const QmlJS::Value *value = interp->convertToObject(scopeChain.evaluate(expression));
if (const QmlJS::FunctionValue *f = value->asFunctionValue()) {
// Only add slots with zero arguments
if (f->namedArgumentCount() == 0 && !methodBlackList.contains(slotName))
connection.methods.append(QString::fromUtf8(slotName));
}
}
}
connection.methods.removeDuplicates();
connections.append(connection);
}
// Singletons
if (RewriterView *rv = m_modelNode.view()->rewriterView()) {
for (const QmlTypeData &data : rv->getQMLTypes()) {
if (!data.typeName.isEmpty()) {
NodeMetaInfo metaInfo = m_modelNode.view()->model()->metaInfo(data.typeName.toUtf8());
if (metaInfo.isValid()) {
ActionEditorDialog::SingletonOption singelton;
for (const PropertyName &propertyName : metaInfo.propertyNames()) {
TypeName type = metaInfo.propertyTypeName(propertyName);
if (!typeWhiteList.contains(type))
continue;
const QString name = QString::fromUtf8(propertyName);
if (type.contains("<cpp>."))
type.remove(0, 6);
singelton.properties.append(ActionEditorDialog::PropertyOption(name, type));
}
if (!singelton.properties.isEmpty()) {
singelton.item = data.typeName;
singletons.append(singelton);
}
}
}
}
}
// States
for (const QmlModelState &state : QmlItemNode(m_modelNode).states().allStates())
states.append(state.name());
if (!connections.isEmpty() && !m_dialog.isNull())
m_dialog->setAllConnections(connections, singletons, states);
}
void ActionEditor::updateWindowName()
{
if (!m_dialog.isNull())
{
m_dialog->setWindowTitle(tr("Connection Editor"));
if (!m_dialog.isNull()) {
m_dialog->setWindowTitle(m_dialog->defaultTitle());
m_dialog->raise();
}
}

View File

@@ -26,7 +26,7 @@
#ifndef ACTIONEDITOR_H
#define ACTIONEDITOR_H
#include <bindingeditor/bindingeditordialog.h>
#include <bindingeditor/actioneditordialog.h>
#include <qmldesignercorelib_global.h>
#include <modelnode.h>
@@ -40,7 +40,7 @@ class ActionEditor : public QObject
{
Q_OBJECT
Q_PROPERTY(QString text READ bindingValue WRITE setBindingValue)
Q_PROPERTY(QString text READ connectionValue WRITE setConnectionValue)
public:
ActionEditor(QObject *parent = nullptr);
@@ -52,14 +52,18 @@ public:
Q_INVOKABLE void showWidget(int x, int y);
Q_INVOKABLE void hideWidget();
QString bindingValue() const;
void setBindingValue(const QString &text);
QString connectionValue() const;
void setConnectionValue(const QString &text);
bool hasModelIndex() const;
void resetModelIndex();
QModelIndex modelIndex() const;
void setModelIndex(const QModelIndex &index);
void setModelNode(const ModelNode &modelNode);
void prepareConnections();
Q_INVOKABLE void updateWindowName();
signals:
@@ -67,14 +71,12 @@ signals:
void rejected();
private:
QVariant backendValue() const;
QVariant modelNodeBackend() const;
QVariant stateModelNode() const;
void prepareDialog();
private:
QPointer<BindingEditorDialog> m_dialog;
QPointer<ActionEditorDialog> m_dialog;
QModelIndex m_index;
QmlDesigner::ModelNode m_modelNode;
};
}

View File

@@ -0,0 +1,656 @@
/****************************************************************************
**
** 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 "actioneditordialog.h"
#include "connectionvisitor.h"
#include <texteditor/texteditor.h>
#include <qmldesigner/qmldesignerplugin.h>
#include <qmljseditor/qmljseditor.h>
#include <qmljseditor/qmljseditordocument.h>
#include <texteditor/textdocument.h>
#include <QDialogButtonBox>
#include <QPushButton>
#include <QHBoxLayout>
#include <QComboBox>
#include <QPlainTextEdit>
static Q_LOGGING_CATEGORY(ceLog, "qtc.qmldesigner.connectioneditor", QtWarningMsg)
namespace QmlDesigner {
ActionEditorDialog::ActionEditorDialog(QWidget *parent)
: AbstractEditorDialog(parent, tr("Connection Editor"))
{
setupUIComponents();
QObject::connect(m_comboBoxType, QOverload<int>::of(&QComboBox::activated),
[this] (int idx) { this->updateComboBoxes(idx, ComboBox::Type); });
// Action connections
QObject::connect(m_actionTargetItem, QOverload<int>::of(&QComboBox::activated),
[this] (int idx) { this->updateComboBoxes(idx, ComboBox::TargetItem); });
QObject::connect(m_actionMethod, QOverload<int>::of(&QComboBox::activated),
[this] (int idx) { this->updateComboBoxes(idx, ComboBox::TargetProperty); });
// Assignment connections
QObject::connect(m_assignmentTargetItem, QOverload<int>::of(&QComboBox::activated),
[this] (int idx) { this->updateComboBoxes(idx, ComboBox::TargetItem); });
QObject::connect(m_assignmentTargetProperty, QOverload<int>::of(&QComboBox::activated),
[this] (int idx) { this->updateComboBoxes(idx, ComboBox::TargetProperty); });
QObject::connect(m_assignmentSourceItem, QOverload<int>::of(&QComboBox::activated),
[this] (int idx) { this->updateComboBoxes(idx, ComboBox::SourceItem); });
QObject::connect(m_assignmentSourceProperty, QOverload<int>::of(&QComboBox::activated),
[this] (int idx) { this->updateComboBoxes(idx, ComboBox::SourceProperty); });
}
ActionEditorDialog::~ActionEditorDialog()
{
}
void ActionEditorDialog::adjustProperties()
{
// Analyze the current connection editor statement/expression
const auto qmlJSDocument = bindingEditorWidget()->qmlJsEditorDocument();
auto doc = QmlJS::Document::create(QLatin1String("<expression>"), QmlJS::Dialect::JavaScript);
doc->setSource(qmlJSDocument->plainText());
bool parseResult = doc->parseExpression();
if (!parseResult) {
qCInfo(ceLog) << Q_FUNC_INFO << "Couldn't parse the expression!";
return;
}
auto astNode = doc->ast();
if (!astNode) {
qCInfo(ceLog) << Q_FUNC_INFO << "There was no AST::Node in the document!";
return;
}
ConnectionVisitor qmlVisitor;
QmlJS::AST::Node::accept(astNode, &qmlVisitor);
const auto expression = qmlVisitor.expression();
if (expression.isEmpty()) {
// Set all ComboBoxes to [Undefined], add connections to target item ComboBox
fillAndSetTargetItem(undefinedString);
fillAndSetTargetProperty(undefinedString);
fillAndSetSourceItem(undefinedString);
fillAndSetSourceProperty(undefinedString);
return;
}
bool typeDone = false;
bool targetDone = false;
for (int i = 0; i < expression.count(); ++i) {
switch (expression[i].first) {
case QmlJS::AST::Node::Kind::Kind_CallExpression:
{
setType(ConnectionType::Action);
typeDone = true;
}
break;
case QmlJS::AST::Node::Kind::Kind_BinaryExpression:
{
setType(ConnectionType::Assignment);
typeDone = true;
}
break;
case QmlJS::AST::Node::Kind::Kind_FieldMemberExpression:
{
QString fieldMember = expression[i].second;
++i;// Increment index to get IdentifierExpression or next FieldMemberExpression
while (expression[i].first == QmlJS::AST::Node::Kind::Kind_FieldMemberExpression) {
fieldMember.prepend(expression[i].second + ".");
++i; // Increment index to get IdentifierExpression
}
if (targetDone && m_comboBoxType->currentIndex() != ConnectionType::Action) {
fillAndSetSourceItem(expression[i].second);
fillAndSetSourceProperty(fieldMember);
} else {
if (typeDone) {
fillAndSetTargetItem(expression[i].second);
fillAndSetTargetProperty(fieldMember);
} else { // e.g. 'element.width'
// In this case Assignment is more likley
setType(ConnectionType::Assignment);
fillAndSetTargetItem(expression[i].second);
fillAndSetTargetProperty(fieldMember);
fillAndSetSourceItem(undefinedString);
fillAndSetSourceProperty(undefinedString);
}
targetDone = true;
}
}
break;
case QmlJS::AST::Node::Kind::Kind_TrueLiteral:
case QmlJS::AST::Node::Kind::Kind_FalseLiteral:
case QmlJS::AST::Node::Kind::Kind_NumericLiteral:
case QmlJS::AST::Node::Kind::Kind_StringLiteral:
{
if (targetDone) {
fillAndSetSourceItem(undefinedString);
fillAndSetSourceProperty(expression[i].second, expression[i].first);
} else {
// In this case Assignment is more likley
setType(ConnectionType::Assignment);
fillAndSetTargetItem(undefinedString);
fillAndSetTargetProperty(undefinedString);
fillAndSetSourceItem(undefinedString);
fillAndSetSourceProperty(expression[i].second, expression[i].first);
}
}
break;
case QmlJS::AST::Node::Kind::Kind_IdentifierExpression:
{
if (typeDone) {
if (m_comboBoxType->currentIndex() == ConnectionType::Assignment) { // e.g. 'element = rectangle
if (targetDone) {
fillAndSetSourceItem(undefinedString);
fillAndSetSourceProperty(undefinedString);
} else {
fillAndSetTargetItem(expression[i].second);
fillAndSetTargetProperty(undefinedString);
targetDone = true;
}
} else { // e.g. 'print("blabla")'
fillAndSetTargetItem(undefinedString);
fillAndSetTargetProperty(undefinedString);
targetDone = true;
}
} else { // e.g. 'element'
// In this case Assignment is more likley
setType(ConnectionType::Assignment);
fillAndSetTargetItem(expression[i].second);
fillAndSetTargetProperty(undefinedString);
fillAndSetSourceItem(undefinedString);
fillAndSetSourceProperty(undefinedString);
}
}
break;
default:
{
fillAndSetTargetItem(undefinedString);
fillAndSetTargetProperty(undefinedString);
fillAndSetSourceItem(undefinedString);
fillAndSetSourceProperty(undefinedString);
}
break;
}
}
}
void ActionEditorDialog::setAllConnections(const QList<ConnectionOption> &connections,
const QList<SingletonOption> &singletons,
const QStringList &states)
{
m_lock = true;
m_connections = connections;
m_singletons = singletons;
m_states = states;
adjustProperties();
m_lock = false;
}
void ActionEditorDialog::updateComboBoxes(int index, ComboBox type)
{
Q_UNUSED(index)
const int currentType = m_comboBoxType->currentIndex();
const int currentStack = m_stackedLayout->currentIndex();
bool typeChanged = false;
if (type == ComboBox::Type) {
if (currentType != currentStack)
typeChanged = true;
else
return; // Prevent rebuild of expression if type didn't change
}
if (typeChanged) {
m_stackedLayout->setCurrentIndex(currentType);
if (currentStack == ConnectionType::Action) {
// Previous type was Action
const auto targetItem = m_actionTargetItem->currentText();
fillAndSetTargetItem(targetItem, true);
fillAndSetTargetProperty(QString(), true);
fillAndSetSourceItem(QString(), true);
fillAndSetSourceProperty(QString(), QmlJS::AST::Node::Kind::Kind_Undefined, true);
} else {
// Previous type was Assignment
const auto targetItem = m_assignmentTargetItem->currentText();
fillAndSetTargetItem(targetItem, true);
fillAndSetTargetProperty(QString(), true);
}
} else {
if (currentType == ConnectionType::Action) {
// Prevent rebuild of expression if undefinedString item was selected
switch (type) {
case ComboBox::TargetItem:
if (m_actionTargetItem->currentText() == undefinedString)
return;
break;
case ComboBox::TargetProperty:
if (m_actionMethod->currentText() == undefinedString)
return;
break;
default:
break;
}
fillAndSetTargetItem(m_actionTargetItem->currentText());
fillAndSetTargetProperty(m_actionMethod->currentText(), true);
} else { // ConnectionType::Assignment
const auto targetItem = m_assignmentTargetItem->currentText();
const auto targetProperty = m_assignmentTargetProperty->currentText();
const auto sourceItem = m_assignmentSourceItem->currentText();
const auto sourceProperty = m_assignmentSourceProperty->currentText();
// Prevent rebuild of expression if undefinedString item was selected
switch (type) {
case ComboBox::TargetItem:
if (targetItem == undefinedString)
return;
break;
case ComboBox::TargetProperty:
if (targetProperty == undefinedString)
return;
break;
case ComboBox::SourceItem:
if (sourceItem == undefinedString)
return;
break;
case ComboBox::SourceProperty:
if (sourceProperty == undefinedString)
return;
break;
default:
break;
}
fillAndSetTargetItem(targetItem, true);
fillAndSetTargetProperty(targetProperty, true);
const auto sourcePropertyType = m_assignmentSourceProperty->currentData().value<TypeName>();
if (type == ComboBox::SourceItem) {
fillAndSetSourceItem(sourceItem, true);
if (sourcePropertyType == specificItem)
fillAndSetSourceProperty(QString(),
QmlJS::AST::Node::Kind::Kind_Undefined,
true);
else
fillAndSetSourceProperty(sourceProperty,
QmlJS::AST::Node::Kind::Kind_Undefined,
true);
} else if (type == ComboBox::SourceProperty) {
if (sourcePropertyType == specificItem) {
fillAndSetSourceItem(QString(), false);
fillAndSetSourceProperty(sourceProperty,
QmlJS::AST::Node::Kind::Kind_StringLiteral,
false);
} else {
fillAndSetSourceProperty(sourceProperty);
}
} else {
if (sourcePropertyType == specificItem) {
fillAndSetSourceItem(QString(), false);
fillAndSetSourceProperty(sourceProperty,
QmlJS::AST::Node::Kind::Kind_StringLiteral,
false);
} else {
fillAndSetSourceItem(sourceItem, true);
fillAndSetSourceProperty(sourceProperty,
QmlJS::AST::Node::Kind::Kind_Undefined,
true);
}
}
}
}
// Compose expression
QString value;
if (currentType == ConnectionType::Action) {
const auto targetItem = m_actionTargetItem->currentText();
const auto method = m_actionMethod->currentText();
if (targetItem != undefinedString && method != undefinedString){
value = targetItem + "." + method + "()";
} else if (targetItem != undefinedString && method == undefinedString) {
value = targetItem;
}
} else { // ConnectionType::Assignment
const auto targetItem = m_assignmentTargetItem->currentText();
const auto targetProperty = m_assignmentTargetProperty->currentText();
const auto sourceItem = m_assignmentSourceItem->currentText();
const auto sourceProperty = m_assignmentSourceProperty->currentText();
QString lhs;
if (targetItem != undefinedString && targetProperty != undefinedString) {
lhs = targetItem + "." + targetProperty;
} else if (targetItem != undefinedString && targetProperty == undefinedString) {
lhs = targetItem;
}
QString rhs;
if (sourceItem != undefinedString && sourceProperty != undefinedString) {
rhs = sourceItem + "." + sourceProperty;
} else if (sourceItem != undefinedString && sourceProperty == undefinedString) {
rhs = sourceItem;
} else if (sourceItem == undefinedString && sourceProperty != undefinedString) {
const QString data = m_assignmentTargetProperty->currentData().toString();
if (data == "string") {
rhs = "\"" + sourceProperty + "\"";
} else {
rhs = sourceProperty;
}
}
if (!lhs.isEmpty() && !rhs.isEmpty()) {
value = lhs + " = " + rhs;
} else {
value = lhs + rhs;
}
}
{
const QSignalBlocker blocker(m_editorWidget);
setEditorValue(value);
}
}
void ActionEditorDialog::setupUIComponents()
{
m_comboBoxType = new QComboBox(this);
QMetaEnum metaEnum = QMetaEnum::fromType<ConnectionType>();
for (int i = 0; i != metaEnum.keyCount(); ++i) {
const char *key = QMetaEnum::fromType<ConnectionType>().valueToKey(i);
m_comboBoxType->addItem(QString::fromLatin1(key));
}
m_comboBoxLayout->addWidget(m_comboBoxType);
m_stackedLayout = new QStackedLayout();
m_actionLayout = new QHBoxLayout();
m_assignmentLayout = new QHBoxLayout();
m_actionPlaceholder = new QWidget(this);
m_actionPlaceholder->setLayout(m_actionLayout);
m_assignmentPlaceholder = new QWidget(this);
m_assignmentPlaceholder->setLayout(m_assignmentLayout);
// Setup action ComboBoxes
m_actionTargetItem = new QComboBox(this);
m_actionMethod = new QComboBox(this);
m_actionLayout->addWidget(m_actionTargetItem);
m_actionLayout->addWidget(m_actionMethod);
// Setup assignment ComboBoxes
m_assignmentTargetItem = new QComboBox(this);
m_assignmentTargetProperty = new QComboBox(this);
m_assignmentSourceItem = new QComboBox(this);
m_assignmentSourceProperty = new QComboBox(this);
m_assignmentLayout->addWidget(m_assignmentTargetItem);
m_assignmentLayout->addWidget(m_assignmentTargetProperty);
m_assignmentLayout->addWidget(m_assignmentSourceItem);
m_assignmentLayout->addWidget(m_assignmentSourceProperty);
m_stackedLayout->addWidget(m_actionPlaceholder);
m_stackedLayout->addWidget(m_assignmentPlaceholder);
m_comboBoxLayout->addItem(m_stackedLayout);
this->resize(720, 240);
}
void ActionEditorDialog::setType(ConnectionType type)
{
m_comboBoxType->setCurrentIndex(type);
m_stackedLayout->setCurrentIndex(type);
}
void ActionEditorDialog::fillAndSetTargetItem(const QString &value, bool useDefault)
{
if (m_comboBoxType->currentIndex() == ConnectionType::Action) {
m_actionTargetItem->clear();
for (const auto &connection : m_connections) {
if (!connection.methods.isEmpty())
m_actionTargetItem->addItem(connection.item);
}
if (m_actionTargetItem->findText(value) != -1) {
m_actionTargetItem->setCurrentText(value);
} else {
if (useDefault && m_actionTargetItem->count())
m_actionTargetItem->setCurrentIndex(0);
else
insertAndSetUndefined(m_actionTargetItem);
}
} else { // ConnectionType::Assignment
m_assignmentTargetItem->clear();
for (const auto &connection : m_connections) {
if (!connection.properties.isEmpty())
m_assignmentTargetItem->addItem(connection.item);
}
if (m_assignmentTargetItem->findText(value) != -1) {
m_assignmentTargetItem->setCurrentText(value);
} else {
if (useDefault && m_actionTargetItem->count())
m_actionTargetItem->setCurrentIndex(0);
else
insertAndSetUndefined(m_assignmentTargetItem);
}
}
}
void ActionEditorDialog::fillAndSetTargetProperty(const QString &value, bool useDefault)
{
if (m_comboBoxType->currentIndex() == ConnectionType::Action) {
m_actionMethod->clear();
const QString targetItem = m_actionTargetItem->currentText();
const int idx = m_connections.indexOf(targetItem);
if (idx == -1) {
insertAndSetUndefined(m_actionMethod);
} else {
m_actionMethod->addItems(m_connections[idx].methods);
if (m_actionMethod->findText(value) != -1) {
m_actionMethod->setCurrentText(value);
} else {
if (useDefault && m_actionMethod->count())
m_actionMethod->setCurrentIndex(0);
else
insertAndSetUndefined(m_actionMethod);
}
}
} else { // ConnectionType::Assignment
m_assignmentTargetProperty->clear();
const QString targetItem = m_assignmentTargetItem->currentText();
const int idx = m_connections.indexOf(targetItem);
if (idx == -1) {
insertAndSetUndefined(m_assignmentTargetProperty);
} else {
for (const auto &property : m_connections[idx].properties)
m_assignmentTargetProperty->addItem(property.name, property.type);
if (m_assignmentTargetProperty->findText(value) != -1) {
m_assignmentTargetProperty->setCurrentText(value);
} else {
if (useDefault && m_assignmentTargetProperty->count())
m_assignmentTargetProperty->setCurrentIndex(0);
else
insertAndSetUndefined(m_assignmentTargetProperty);
}
}
}
}
void ActionEditorDialog::fillAndSetSourceItem(const QString &value, bool useDefault)
{
m_assignmentSourceItem->clear();
const TypeName targetPropertyType = m_assignmentTargetProperty->currentData().value<TypeName>();
if (!targetPropertyType.isEmpty()) {
for (const ConnectionOption &connection : m_connections) {
if (!connection.containsType(targetPropertyType))
continue;
m_assignmentSourceItem->addItem(connection.item);
}
// Add Constants
for (const SingletonOption &singleton : m_singletons) {
if (!singleton.containsType(targetPropertyType))
continue;
m_assignmentSourceItem->addItem(singleton.item, singletonItem);
}
}
if (m_assignmentSourceItem->findText(value) != -1) {
m_assignmentSourceItem->setCurrentText(value);
} else {
if (useDefault && m_assignmentSourceItem->count())
m_assignmentSourceItem->setCurrentIndex(0);
else
insertAndSetUndefined(m_assignmentSourceItem);
}
}
void ActionEditorDialog::fillAndSetSourceProperty(const QString &value,
QmlJS::AST::Node::Kind kind,
bool useDefault)
{
m_assignmentSourceProperty->clear();
const TypeName targetPropertyType = m_assignmentTargetProperty->currentData().value<TypeName>();
const QString targetProperty = m_assignmentTargetProperty->currentText();
if (kind != QmlJS::AST::Node::Kind::Kind_Undefined) {
if (targetPropertyType == "bool") {
m_assignmentSourceProperty->addItem("true", specificItem);
m_assignmentSourceProperty->addItem("false", specificItem);
if (m_assignmentSourceProperty->findText(value) != -1)
m_assignmentSourceProperty->setCurrentText(value);
else
insertAndSetUndefined(m_assignmentSourceProperty);
} else if (targetProperty == "state") {
for (const auto &state : m_states)
m_assignmentSourceProperty->addItem(state, specificItem);
if (m_assignmentSourceProperty->findText(value) != -1)
m_assignmentSourceProperty->setCurrentText(value);
else
insertAndSetUndefined(m_assignmentSourceProperty);
} else {
m_assignmentSourceProperty->insertItem(0, value, specificItem);
m_assignmentSourceProperty->setCurrentIndex(0);
}
} else {
const TypeName sourceItemType = m_assignmentSourceItem->currentData().value<TypeName>();
const QString sourceItem = m_assignmentSourceItem->currentText();
// We need to distinguish between singleton (Constants) and standard item
const int idx = (sourceItemType == singletonItem) ? m_singletons.indexOf(sourceItem)
: m_connections.indexOf(sourceItem);
if (idx == -1) {
insertAndSetUndefined(m_assignmentSourceProperty);
} else {
int specificsEnd = -1;
// Add type specific items
if (targetPropertyType == "bool") {
m_assignmentSourceProperty->addItem("true", specificItem);
m_assignmentSourceProperty->addItem("false", specificItem);
specificsEnd = 2;
} else if (targetProperty == "state") {
for (const auto &state : m_states)
m_assignmentSourceProperty->addItem(state, specificItem);
specificsEnd = m_states.count();
}
if (specificsEnd != -1)
m_assignmentSourceProperty->insertSeparator(specificsEnd);
if (sourceItemType == singletonItem) {
for (const auto &property : m_singletons[idx].properties) {
if (targetPropertyType.isEmpty() // TODO isEmpty correct?!
|| property.type == targetPropertyType
|| (isNumeric(property.type) && isNumeric(targetPropertyType)))
m_assignmentSourceProperty->addItem(property.name, property.type);
}
} else {
for (const auto &property : m_connections[idx].properties) {
if (targetPropertyType.isEmpty() // TODO isEmpty correct?!
|| property.type == targetPropertyType
|| (isNumeric(property.type) && isNumeric(targetPropertyType)))
m_assignmentSourceProperty->addItem(property.name, property.type);
}
}
if (m_assignmentSourceProperty->findText(value) != -1 && !value.isEmpty()) {
m_assignmentSourceProperty->setCurrentText(value);
} else {
if (useDefault && m_assignmentSourceProperty->count())
m_assignmentSourceProperty->setCurrentIndex(specificsEnd + 1);
else
insertAndSetUndefined(m_assignmentSourceProperty);
}
}
}
}
void ActionEditorDialog::insertAndSetUndefined(QComboBox *comboBox)
{
comboBox->insertItem(0, undefinedString);
comboBox->setCurrentIndex(0);
}
} // QmlDesigner namespace

View File

@@ -0,0 +1,155 @@
/****************************************************************************
**
** 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.
**
****************************************************************************/
#ifndef ACTIONEDITORDIALOG_H
#define ACTIONEDITORDIALOG_H
#include <bindingeditor/abstracteditordialog.h>
#include <qmljs/parser/qmljsast_p.h>
#include <QStackedLayout>
QT_BEGIN_NAMESPACE
class QComboBox;
QT_END_NAMESPACE
namespace QmlDesigner {
class ActionEditorDialog : public AbstractEditorDialog
{
Q_OBJECT
public:
enum ConnectionType { Action, Assignment };
Q_ENUM(ConnectionType)
enum ComboBox { Type, TargetItem, TargetProperty, SourceItem, SourceProperty };
Q_ENUM(ComboBox)
class PropertyOption
{
public:
PropertyOption() {}
PropertyOption(const QString &n, const TypeName &t)
: name(n)
, type(t)
{}
bool operator==(const QString &value) const { return value == name; }
bool operator==(const PropertyOption &value) const { return value.name == name; }
QString name;
TypeName type;
};
class SingletonOption
{
public:
SingletonOption() {}
SingletonOption(const QString &value) { item = value; }
bool containsType(const TypeName &t) const
{
for (const auto &p : properties) {
if (t == p.type || (isNumeric(t) && isNumeric(p.type)))
return true;
}
return false;
}
bool operator==(const QString &value) const { return value == item; }
bool operator==(const SingletonOption &value) const { return value.item == item; }
QString item;
QList<PropertyOption> properties;
};
class ConnectionOption : public SingletonOption
{
public:
ConnectionOption() {}
ConnectionOption(const QString &value) : SingletonOption(value) {}
QStringList methods;
};
ActionEditorDialog(QWidget *parent = nullptr);
~ActionEditorDialog() override;
void adjustProperties() override;
void setAllConnections(const QList<ConnectionOption> &connections,
const QList<SingletonOption> &singeltons,
const QStringList &states);
void updateComboBoxes(int idx, ComboBox type);
private:
void setupUIComponents();
void setType(ConnectionType type);
void fillAndSetTargetItem(const QString &value, bool useDefault = false);
void fillAndSetTargetProperty(const QString &value, bool useDefault = false);
void fillAndSetSourceItem(const QString &value, bool useDefault = false);
void fillAndSetSourceProperty(const QString &value,
QmlJS::AST::Node::Kind kind = QmlJS::AST::Node::Kind::Kind_Undefined,
bool useDefault = false);
void insertAndSetUndefined(QComboBox *comboBox);
private:
QComboBox *m_comboBoxType = nullptr;
QStackedLayout *m_stackedLayout = nullptr;
QWidget *m_actionPlaceholder = nullptr;
QWidget *m_assignmentPlaceholder = nullptr;
QHBoxLayout *m_actionLayout = nullptr;
QHBoxLayout *m_assignmentLayout = nullptr;
QComboBox *m_actionTargetItem = nullptr;
QComboBox *m_actionMethod = nullptr;
QComboBox *m_assignmentTargetItem = nullptr;
QComboBox *m_assignmentTargetProperty = nullptr;
QComboBox *m_assignmentSourceItem = nullptr;
QComboBox *m_assignmentSourceProperty = nullptr; // Value
QList<ConnectionOption> m_connections;
QList<SingletonOption> m_singletons;
QStringList m_states;
const TypeName specificItem = {"specific"};
const TypeName singletonItem = {"singleton"};
};
}
#endif //ACTIONEDITORDIALOG_H

View File

@@ -28,6 +28,7 @@
#include <qmldesignerplugin.h>
#include <coreplugin/icore.h>
#include <coreplugin/actionmanager/actionmanager.h>
#include <bindingeditor/bindingeditordialog.h>
#include <metainfo.h>
#include <qmlmodelnodeproxy.h>
@@ -60,14 +61,14 @@ void BindingEditor::prepareDialog()
{
if (s_lastBindingEditor)
s_lastBindingEditor->hideWidget();
s_lastBindingEditor = this;
m_dialog = new BindingEditorDialog(Core::ICore::dialogParent());
QObject::connect(m_dialog, &BindingEditorDialog::accepted,
QObject::connect(m_dialog, &AbstractEditorDialog::accepted,
this, &BindingEditor::accepted);
QObject::connect(m_dialog, &BindingEditorDialog::rejected,
QObject::connect(m_dialog, &AbstractEditorDialog::rejected,
this, &BindingEditor::rejected);
m_dialog->setAttribute(Qt::WA_DeleteOnClose);
@@ -89,8 +90,8 @@ void BindingEditor::hideWidget()
{
if (s_lastBindingEditor == this)
s_lastBindingEditor = nullptr;
if (m_dialog)
{
if (m_dialog) {
m_dialog->unregisterAutoCompletion(); //we have to do it separately, otherwise we have an autocompletion action override
m_dialog->close();
}
@@ -118,8 +119,7 @@ void BindingEditor::setBackendValue(const QVariant &backendValue)
const PropertyEditorValue *propertyEditorValue = qobject_cast<const PropertyEditorValue *>(backendValueObj);
const ModelNode node = propertyEditorValue->modelNode();
if (node.isValid())
{
if (node.isValid()) {
m_backendValueTypeName = node.metaInfo().propertyTypeName(propertyEditorValue->name());
if (m_backendValueTypeName == "alias" || m_backendValueTypeName == "unknown")
@@ -141,9 +141,8 @@ void BindingEditor::setModelNodeBackend(const QVariant &modelNodeBackend)
const auto backendObjectCasted =
qobject_cast<const QmlDesigner::QmlModelNodeProxy *>(modelNodeBackendObject);
if (backendObjectCasted) {
if (backendObjectCasted)
m_modelNode = backendObjectCasted->qmlObjectNode().modelNode();
}
emit modelNodeBackendChanged();
}
@@ -151,8 +150,7 @@ void BindingEditor::setModelNodeBackend(const QVariant &modelNodeBackend)
void BindingEditor::setStateModelNode(const QVariant &stateModelNode)
{
if (stateModelNode.isValid())
{
if (stateModelNode.isValid()) {
m_stateModelNode = stateModelNode;
m_modelNode = m_stateModelNode.value<QmlDesigner::ModelNode>();
@@ -188,21 +186,21 @@ void BindingEditor::prepareBindings()
const QList<TypeName> variantTypes = {"alias", "unknown", "variant", "var"};
const QList<TypeName> numericTypes = {"double", "real", "int"};
const QList<TypeName> colorTypes = {"QColor", "color"};
auto isNumeric = [&numericTypes](TypeName compareType) { return numericTypes.contains(compareType); };
auto isColor = [&colorTypes](TypeName compareType) { return colorTypes.contains(compareType); };
auto isVariant = [&variantTypes](const TypeName &compareType) { return variantTypes.contains(compareType); };
auto isNumeric = [&numericTypes](const TypeName &compareType) { return numericTypes.contains(compareType); };
auto isColor = [&colorTypes](const TypeName &compareType) { return colorTypes.contains(compareType); };
const bool skipTypeFiltering = variantTypes.contains(m_backendValueTypeName);
const bool skipTypeFiltering = isVariant(m_backendValueTypeName);
const bool targetTypeIsNumeric = isNumeric(m_backendValueTypeName);
for (const auto &objnode : allNodes) {
BindingEditorDialog::BindingOption binding;
for (const auto &propertyName : objnode.metaInfo().propertyNames())
{
for (const auto &propertyName : objnode.metaInfo().propertyNames()) {
TypeName propertyTypeName = objnode.metaInfo().propertyTypeName(propertyName);
if (skipTypeFiltering
|| (m_backendValueTypeName == propertyTypeName)
|| variantTypes.contains(propertyTypeName)
|| isVariant(propertyTypeName)
|| (targetTypeIsNumeric && isNumeric(propertyTypeName))) {
binding.properties.append(QString::fromUtf8(propertyName));
}
@@ -215,7 +213,7 @@ void BindingEditor::prepareBindings()
const TypeName dynamicTypeName = bindingProperty.dynamicTypeName();
if (skipTypeFiltering
|| (dynamicTypeName == m_backendValueTypeName)
|| variantTypes.contains(dynamicTypeName)
|| isVariant(dynamicTypeName)
|| (targetTypeIsNumeric && isNumeric(dynamicTypeName))) {
binding.properties.append(QString::fromUtf8(bindingProperty.name()));
}
@@ -228,7 +226,7 @@ void BindingEditor::prepareBindings()
const TypeName dynamicTypeName = variantProperty.dynamicTypeName();
if (skipTypeFiltering
|| (dynamicTypeName == m_backendValueTypeName)
|| variantTypes.contains(dynamicTypeName)
|| isVariant(dynamicTypeName)
|| (targetTypeIsNumeric && isNumeric(dynamicTypeName))) {
binding.properties.append(QString::fromUtf8(variantProperty.name()));
}
@@ -243,7 +241,7 @@ void BindingEditor::prepareBindings()
}
//singletons:
if (RewriterView* rv = m_modelNode.view()->rewriterView()) {
if (RewriterView *rv = m_modelNode.view()->rewriterView()) {
for (const QmlTypeData &data : rv->getQMLTypes()) {
if (!data.typeName.isEmpty()) {
NodeMetaInfo metaInfo = m_modelNode.view()->model()->metaInfo(data.typeName.toUtf8());
@@ -256,7 +254,7 @@ void BindingEditor::prepareBindings()
if (skipTypeFiltering
|| (m_backendValueTypeName == propertyTypeName)
|| (variantTypes.contains(propertyTypeName))
|| (isVariant(propertyTypeName))
|| (targetTypeIsNumeric && isNumeric(propertyTypeName))
|| (isColor(m_backendValueTypeName) && isColor(propertyTypeName))) {
binding.properties.append(QString::fromUtf8(propertyName));
@@ -281,9 +279,7 @@ void BindingEditor::prepareBindings()
void BindingEditor::updateWindowName()
{
if (!m_dialog.isNull() && !m_backendValueTypeName.isEmpty())
{
m_dialog->setWindowTitle(m_dialog->defaultTitle() + " [" + m_backendValueTypeName + "]");
}
}
QVariant BindingEditor::backendValue() const

View File

@@ -1,9 +1,15 @@
HEADERS += $$PWD/bindingeditor.h
HEADERS += $$PWD/actioneditor.h
HEADERS += $$PWD/abstracteditordialog.h
HEADERS += $$PWD/actioneditordialog.h
HEADERS += $$PWD/bindingeditordialog.h
HEADERS += $$PWD/bindingeditorwidget.h
HEADERS += $$PWD/connectionvisitor.h
SOURCES += $$PWD/bindingeditor.cpp
SOURCES += $$PWD/actioneditor.cpp
SOURCES += $$PWD/abstracteditordialog.cpp
SOURCES += $$PWD/actioneditordialog.cpp
SOURCES += $$PWD/bindingeditordialog.cpp
SOURCES += $$PWD/bindingeditorwidget.cpp
SOURCES += $$PWD/connectionvisitor.cpp

View File

@@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
@@ -41,80 +41,19 @@
namespace QmlDesigner {
BindingEditorDialog::BindingEditorDialog(QWidget *parent, DialogType type)
: QDialog(parent)
, m_dialogType(type)
BindingEditorDialog::BindingEditorDialog(QWidget *parent)
: AbstractEditorDialog(parent, tr("Binding Editor"))
{
setWindowFlag(Qt::Tool, true);
setWindowTitle(defaultTitle());
setModal(false);
setupJSEditor();
setupUIComponents();
QObject::connect(m_buttonBox, &QDialogButtonBox::accepted,
this, &BindingEditorDialog::accepted);
QObject::connect(m_buttonBox, &QDialogButtonBox::rejected,
this, &BindingEditorDialog::rejected);
QObject::connect(m_editorWidget, &BindingEditorWidget::returnKeyClicked,
this, &BindingEditorDialog::accepted);
if (m_dialogType == DialogType::BindingDialog) {
QObject::connect(m_comboBoxItem, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &BindingEditorDialog::itemIDChanged);
QObject::connect(m_comboBoxProperty, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &BindingEditorDialog::propertyIDChanged);
QObject::connect(m_editorWidget, &QPlainTextEdit::textChanged,
this, &BindingEditorDialog::textChanged);
}
QObject::connect(m_comboBoxItem, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &BindingEditorDialog::itemIDChanged);
QObject::connect(m_comboBoxProperty, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &BindingEditorDialog::propertyIDChanged);
}
BindingEditorDialog::~BindingEditorDialog()
{
delete m_editor; //m_editorWidget is handled by basetexteditor destructor
delete m_buttonBox;
delete m_comboBoxItem;
delete m_comboBoxProperty;
delete m_comboBoxLayout;
delete m_verticalLayout;
}
void BindingEditorDialog::showWidget()
{
this->show();
this->raise();
m_editorWidget->setFocus();
}
void BindingEditorDialog::showWidget(int x, int y)
{
showWidget();
move(QPoint(x, y));
}
QString BindingEditorDialog::editorValue() const
{
if (!m_editorWidget)
return {};
return m_editorWidget->document()->toPlainText();
}
void BindingEditorDialog::setEditorValue(const QString &text)
{
if (m_editorWidget)
m_editorWidget->document()->setPlainText(text);
}
void BindingEditorDialog::setAllBindings(QList<BindingEditorDialog::BindingOption> bindings)
{
m_lock = true;
m_bindings = bindings;
setupComboBoxes();
adjustProperties();
m_lock = false;
}
void BindingEditorDialog::adjustProperties()
@@ -155,69 +94,26 @@ void BindingEditorDialog::adjustProperties()
m_comboBoxProperty->setCurrentText(property);
}
void BindingEditorDialog::unregisterAutoCompletion()
void BindingEditorDialog::setAllBindings(QList<BindingOption> bindings)
{
if (m_editorWidget)
m_editorWidget->unregisterAutoCompletion();
}
m_lock = true;
QString BindingEditorDialog::defaultTitle() const
{
return titleString;
}
m_bindings = bindings;
setupComboBoxes();
adjustProperties();
void BindingEditorDialog::setupJSEditor()
{
static BindingEditorFactory f;
m_editor = qobject_cast<TextEditor::BaseTextEditor*>(f.createEditor());
m_editorWidget = qobject_cast<BindingEditorWidget*>(m_editor->editorWidget());
Core::Context context = m_editor->context();
context.prepend(BINDINGEDITOR_CONTEXT_ID);
m_editorWidget->m_context->setContext(context);
auto qmlDesignerEditor = QmlDesignerPlugin::instance()->currentDesignDocument()->textEditor();
m_editorWidget->qmljsdocument = qobject_cast<QmlJSEditor::QmlJSEditorWidget *>(
qmlDesignerEditor->widget())->qmlJsEditorDocument();
m_editorWidget->setLineNumbersVisible(false);
m_editorWidget->setMarksVisible(false);
m_editorWidget->setCodeFoldingSupported(false);
m_editorWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
m_editorWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
m_editorWidget->setTabChangesFocus(true);
m_lock = false;
}
void BindingEditorDialog::setupUIComponents()
{
m_verticalLayout = new QVBoxLayout(this);
m_comboBoxItem = new QComboBox(this);
m_comboBoxProperty = new QComboBox(this);
if (m_dialogType == DialogType::BindingDialog) {
m_comboBoxLayout = new QHBoxLayout;
m_comboBoxItem = new QComboBox(this);
m_comboBoxProperty = new QComboBox(this);
}
m_comboBoxLayout->addWidget(m_comboBoxItem);
m_comboBoxLayout->addWidget(m_comboBoxProperty);
m_editorWidget->setParent(this);
m_editorWidget->setFrameStyle(QFrame::StyledPanel | QFrame::Raised);
m_editorWidget->show();
m_buttonBox = new QDialogButtonBox(this);
m_buttonBox->setOrientation(Qt::Horizontal);
m_buttonBox->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
m_buttonBox->button(QDialogButtonBox::Ok)->setDefault(true);
if (m_dialogType == DialogType::BindingDialog) {
m_comboBoxLayout->addWidget(m_comboBoxItem);
m_comboBoxLayout->addWidget(m_comboBoxProperty);
m_verticalLayout->addLayout(m_comboBoxLayout);
}
m_verticalLayout->addWidget(m_editorWidget);
m_verticalLayout->addWidget(m_buttonBox);
this->resize(660, 240);
//this->resize(660, 240);
}
void BindingEditorDialog::setupComboBoxes()
@@ -260,14 +156,4 @@ void BindingEditorDialog::propertyIDChanged(int propertyID)
m_comboBoxProperty->removeItem(undefinedProperty);
}
void BindingEditorDialog::textChanged()
{
if (m_lock)
return;
m_lock = true;
adjustProperties();
m_lock = false;
}
} // QmlDesigner namespace

View File

@@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
@@ -26,21 +26,15 @@
#ifndef BINDINGEDITORDIALOG_H
#define BINDINGEDITORDIALOG_H
#include <bindingeditor/bindingeditorwidget.h>
#include <texteditor/texteditor.h>
#include <QDialog>
#include <bindingeditor/abstracteditordialog.h>
QT_BEGIN_NAMESPACE
class QDialogButtonBox;
class QVBoxLayout;
class QHBoxLayout;
class QComboBox;
QT_END_NAMESPACE
namespace QmlDesigner {
class BindingEditorDialog : public QDialog
class BindingEditorDialog : public AbstractEditorDialog
{
Q_OBJECT
@@ -57,52 +51,26 @@ public:
QStringList properties;
};
enum DialogType {
Unknown = 0,
BindingDialog = 1,
ActionDialog = 2
};
public:
BindingEditorDialog(QWidget *parent = nullptr, DialogType type = DialogType::BindingDialog);
BindingEditorDialog(QWidget *parent = nullptr);
~BindingEditorDialog() override;
void showWidget();
void showWidget(int x, int y);
void adjustProperties() override;
QString editorValue() const;
void setEditorValue(const QString &text);
void setAllBindings(QList<BindingEditorDialog::BindingOption> bindings);
void adjustProperties();
void unregisterAutoCompletion();
QString defaultTitle() const;
void setAllBindings(QList<BindingOption> bindings);
private:
void setupJSEditor();
void setupUIComponents();
void setupComboBoxes();
public slots:
void itemIDChanged(int);
void propertyIDChanged(int);
void textChanged();
private:
DialogType m_dialogType = DialogType::BindingDialog;
TextEditor::BaseTextEditor *m_editor = nullptr;
BindingEditorWidget *m_editorWidget = nullptr;
QVBoxLayout *m_verticalLayout = nullptr;
QDialogButtonBox *m_buttonBox = nullptr;
QHBoxLayout *m_comboBoxLayout = nullptr;
QComboBox *m_comboBoxItem = nullptr;
QComboBox *m_comboBoxProperty = nullptr;
QList<BindingEditorDialog::BindingOption> m_bindings;
bool m_lock = false;
const QString undefinedString = {"[Undefined]"};
const QString titleString = {tr("Binding Editor")};
QList<BindingOption> m_bindings;
};
}

View File

@@ -0,0 +1,112 @@
/****************************************************************************
**
** 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 "connectionvisitor.h"
namespace QmlDesigner {
ConnectionVisitor::ConnectionVisitor()
{
}
bool ConnectionVisitor::visit(QmlJS::AST::StringLiteral *ast)
{
m_expression.append(qMakePair(QmlJS::AST::Node::Kind::Kind_StringLiteral,
ast->value.toString()));
return true;
}
bool ConnectionVisitor::visit(QmlJS::AST::NumericLiteral *ast)
{
m_expression.append(qMakePair(QmlJS::AST::Node::Kind::Kind_NumericLiteral,
QString::number(ast->value)));
return true;
}
bool ConnectionVisitor::visit(QmlJS::AST::TrueLiteral *ast)
{
Q_UNUSED(ast)
m_expression.append(qMakePair(QmlJS::AST::Node::Kind::Kind_TrueLiteral, QString("true")));
return true;
}
bool ConnectionVisitor::visit(QmlJS::AST::FalseLiteral *ast)
{
Q_UNUSED(ast)
m_expression.append(qMakePair(QmlJS::AST::Node::Kind::Kind_FalseLiteral, QString("false")));
return true;
}
bool ConnectionVisitor::visit(QmlJS::AST::BinaryExpression *ast)
{
Q_UNUSED(ast)
m_expression.append(qMakePair(QmlJS::AST::Node::Kind::Kind_BinaryExpression,
QString()));
return true;
}
bool ConnectionVisitor::visit(QmlJS::AST::CallExpression *ast)
{
Q_UNUSED(ast)
m_expression.append(qMakePair(QmlJS::AST::Node::Kind::Kind_CallExpression,
QString()));
return true;
}
bool ConnectionVisitor::visit(QmlJS::AST::ArgumentList *ast)
{
Q_UNUSED(ast)
m_expression.append(qMakePair(QmlJS::AST::Node::Kind::Kind_ArgumentList,
QString()));
return true;
}
bool ConnectionVisitor::visit(QmlJS::AST::FunctionExpression *ast)
{
m_expression.append(qMakePair(QmlJS::AST::Node::Kind::Kind_FunctionExpression,
ast->name.toString()));
return true;
}
bool ConnectionVisitor::visit(QmlJS::AST::FieldMemberExpression *ast)
{
m_expression.append(qMakePair(QmlJS::AST::Node::Kind::Kind_FieldMemberExpression,
ast->name.toString()));
return true;
}
bool ConnectionVisitor::visit(QmlJS::AST::IdentifierExpression *ast)
{
m_expression.append(qMakePair(QmlJS::AST::Node::Kind::Kind_IdentifierExpression,
ast->name.toString()));
return true;
}
void ConnectionVisitor::throwRecursionDepthError()
{
qWarning("Warning: Hit maximum recursion depth while visiting AST in ConnectionVisitor");
}
} // QmlDesigner namespace

View File

@@ -0,0 +1,66 @@
/****************************************************************************
**
** 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.
**
****************************************************************************/
#ifndef CONNECTIONVISITOR_H
#define CONNECTIONVISITOR_H
#include <qmljs/qmljsdocument.h>
#include <qmljs/parser/qmljsastvisitor_p.h>
#include <qmljs/parser/qmljsast_p.h>
namespace QmlDesigner {
class ConnectionVisitor : public QmlJS::AST::Visitor
{
public:
explicit ConnectionVisitor();
bool visit(QmlJS::AST::StringLiteral *ast) override;
bool visit(QmlJS::AST::NumericLiteral *ast) override;
bool visit(QmlJS::AST::TrueLiteral *ast) override;
bool visit(QmlJS::AST::FalseLiteral *ast) override;
bool visit(QmlJS::AST::BinaryExpression *ast) override;
bool visit(QmlJS::AST::CallExpression *ast) override;
bool visit(QmlJS::AST::ArgumentList *ast) override;
bool visit(QmlJS::AST::FunctionExpression *ast) override; // unused
bool visit(QmlJS::AST::FieldMemberExpression *ast) override;
bool visit(QmlJS::AST::IdentifierExpression *ast) override;
void throwRecursionDepthError() override;
const QList<QPair<QmlJS::AST::Node::Kind, QString>> &expression() const {
return m_expression;
}
private:
QList<QPair<QmlJS::AST::Node::Kind, QString>> m_expression;
};
}
#endif //CONNECTIONVISITOR_H

View File

@@ -26,14 +26,15 @@
#include "designeractionmanager.h"
#include "changestyleaction.h"
#include "modelnodecontextmenu_helper.h"
#include <bindingproperty.h>
#include <nodeproperty.h>
#include <nodelistproperty.h>
#include <nodehints.h>
#include <nodemetainfo.h>
#include "designeractionmanagerview.h"
#include "modelnodecontextmenu_helper.h"
#include "qmldesignerconstants.h"
#include "rewritingexception.h"
#include <bindingproperty.h>
#include <nodehints.h>
#include <nodelistproperty.h>
#include <nodemetainfo.h>
#include <nodeproperty.h>
#include <formeditortoolbutton.h>
@@ -44,8 +45,6 @@
#include <listmodeleditor/listmodeleditordialog.h>
#include <listmodeleditor/listmodeleditormodel.h>
#include <QHBoxLayout>
#include <QGraphicsLinearLayout>
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/icore.h>
@@ -53,6 +52,12 @@
#include <utils/qtcassert.h>
#include <utils/utilsicons.h>
#include <QGraphicsLinearLayout>
#include <QHBoxLayout>
#include <QMessageBox>
#include <exception>
namespace QmlDesigner {
static inline QString captionForModelNode(const ModelNode &modelNode)
@@ -387,6 +392,12 @@ public:
}
};
class DocumentError : public std::exception
{
public:
const char *what() const noexcept override { return "Current document contains errors."; }
};
class EditListModelAction final : public ModelNodeContextMenuAction
{
public:
@@ -432,6 +443,24 @@ public:
return view->createModelNode(elementMetaInfo.typeName(),
elementMetaInfo.majorVersion(),
elementMetaInfo.minorVersion());
},
[&](const ModelNode &node) {
bool isNowInComponent = ModelNodeOperations::goIntoComponent(
node);
Model *currentModel = QmlDesignerPlugin::instance()
->currentDesignDocument()
->currentModel();
if (currentModel->rewriterView()
&& currentModel->rewriterView()->inErrorState()) {
throw DocumentError{};
}
if (isNowInComponent)
return view->rootModelNode();
return node;
}};
model.setListView(targetNode);
@@ -439,7 +468,22 @@ public:
ListModelEditorDialog dialog{Core::ICore::mainWindow()};
dialog.setModel(&model);
dialog.exec();
try {
dialog.exec();
} catch (const DocumentError &) {
QMessageBox::warning(
Core::ICore::mainWindow(),
QCoreApplication::translate("DesignerActionManager", "Document has errors"),
QCoreApplication::translate("DesignerActionManager",
"The document which contains the list model "
"contains errors. So we cannot edit it."));
} catch (const RewritingException &) {
QMessageBox::warning(
Core::ICore::mainWindow(),
QCoreApplication::translate("DesignerActionManager", "Document cannot be written"),
QCoreApplication::translate("DesignerActionManager",
"An error occurred during a write attemp."));
}
}
};

View File

@@ -127,9 +127,9 @@ static void setUpperLeftPostionToNode(const ModelNode &layoutNode, const QList<M
namespace ModelNodeOperations {
void goIntoComponent(const ModelNode &modelNode)
bool goIntoComponent(const ModelNode &modelNode)
{
DocumentManager::goIntoComponent(modelNode);
return DocumentManager::goIntoComponent(modelNode);
}
void select(const SelectionContext &selectionState)

View File

@@ -30,7 +30,7 @@
namespace QmlDesigner {
namespace ModelNodeOperations {
void goIntoComponent(const ModelNode &modelNode);
bool goIntoComponent(const ModelNode &modelNode);
void select(const SelectionContext &selectionState);
void deSelect(const SelectionContext &selectionState);

View File

@@ -60,7 +60,7 @@ ConnectionViewWidget::ConnectionViewWidget(QWidget *parent) :
QFrame(parent),
ui(new Ui::ConnectionViewWidget)
{
m_connectonEditor = new QmlDesigner::ActionEditor(this);
m_connectionEditor = new QmlDesigner::ActionEditor(this);
m_bindingEditor = new QmlDesigner::BindingEditor(this);
m_dynamicEditor = new QmlDesigner::BindingEditor(this);
@@ -111,7 +111,7 @@ ConnectionViewWidget::ConnectionViewWidget(QWidget *parent) :
ConnectionViewWidget::~ConnectionViewWidget()
{
delete m_connectonEditor;
delete m_connectionEditor;
delete m_bindingEditor;
delete m_dynamicEditor;
delete ui;
@@ -161,10 +161,14 @@ void ConnectionViewWidget::contextMenuEvent(QContextMenuEvent *event)
menu.addAction(tr("Open Connection Editor"), [&]() {
if (index.isValid()) {
m_connectonEditor->showWidget();
m_connectonEditor->setBindingValue(index.data().toString());
m_connectonEditor->setModelIndex(index);
m_connectonEditor->updateWindowName();
auto *connectionModel = qobject_cast<ConnectionModel *>(targetView->model());
ModelNode node = connectionModel->connectionView()->rootModelNode();
m_connectionEditor->showWidget();
m_connectionEditor->setConnectionValue(index.data().toString());
m_connectionEditor->setModelIndex(index);
m_connectionEditor->setModelNode(node);
m_connectionEditor->prepareConnections();
m_connectionEditor->updateWindowName();
}
});
@@ -455,29 +459,29 @@ void ConnectionViewWidget::addButtonClicked()
void ConnectionViewWidget::editorForConnection()
{
QObject::connect(m_connectonEditor, &QmlDesigner::ActionEditor::accepted,
QObject::connect(m_connectionEditor, &QmlDesigner::ActionEditor::accepted,
[&]() {
if (m_connectonEditor->hasModelIndex()) {
if (m_connectionEditor->hasModelIndex()) {
ConnectionModel *connectionModel = qobject_cast<ConnectionModel *>(ui->connectionView->model());
if (connectionModel->connectionView()->isWidgetEnabled()
&& (connectionModel->rowCount() > m_connectonEditor->modelIndex().row())) {
&& (connectionModel->rowCount() > m_connectionEditor->modelIndex().row())) {
connectionModel->connectionView()
->executeInTransaction("ConnectionView::setSignal", [this, connectionModel]() {
SignalHandlerProperty signalHandler
= connectionModel->signalHandlerPropertyForRow(
m_connectonEditor->modelIndex().row());
signalHandler.setSource(m_connectonEditor->bindingValue());
m_connectionEditor->modelIndex().row());
signalHandler.setSource(m_connectionEditor->connectionValue());
});
}
m_connectonEditor->resetModelIndex();
m_connectionEditor->resetModelIndex();
}
m_connectonEditor->hideWidget();
m_connectionEditor->hideWidget();
});
QObject::connect(m_connectonEditor, &QmlDesigner::ActionEditor::rejected,
QObject::connect(m_connectionEditor, &QmlDesigner::ActionEditor::rejected,
[&]() {
m_connectonEditor->resetModelIndex();
m_connectonEditor->hideWidget();
m_connectionEditor->resetModelIndex();
m_connectionEditor->hideWidget();
});
}

View File

@@ -107,7 +107,7 @@ private:
private:
Ui::ConnectionViewWidget *ui;
QmlDesigner::ActionEditor *m_connectonEditor; //editor for connections in connection view
QmlDesigner::ActionEditor *m_connectionEditor; //editor for connections in connection view
QmlDesigner::BindingEditor *m_bindingEditor; //editor for properties in binding view
QmlDesigner::BindingEditor *m_dynamicEditor; //editor for properties in dynamic view

View File

@@ -199,13 +199,15 @@ void renameProperties(const QStandardItemModel *model,
}
ModelNode listModelNode(const ModelNode &listViewNode,
const std::function<ModelNode()> &createModelCallback)
const std::function<ModelNode()> &createModelCallback,
const std::function<ModelNode(const ModelNode &)> &goIntoComponentCallback)
{
if (listViewNode.hasProperty("model")) {
if (listViewNode.hasBindingProperty("model"))
return listViewNode.bindingProperty("model").resolveToModelNode();
else if (listViewNode.hasNodeProperty("model"))
return listViewNode.nodeProperty("model").modelNode();
if (listViewNode.hasBindingProperty("model")) {
return goIntoComponentCallback(listViewNode.bindingProperty("model").resolveToModelNode());
} else if (listViewNode.hasNodeProperty("model")) {
return goIntoComponentCallback(listViewNode.nodeProperty("model").modelNode());
}
}
ModelNode newModel = createModelCallback();
@@ -251,7 +253,7 @@ void ListModelEditorModel::setListModel(ModelNode node)
void ListModelEditorModel::setListView(ModelNode listView)
{
setListModel(listModelNode(listView, m_createModelCallback));
setListModel(listModelNode(listView, m_createModelCallback, m_goIntoComponentCallback));
}
void ListModelEditorModel::addRow()

View File

@@ -39,9 +39,11 @@ class ListModelEditorModel : public QStandardItemModel
public:
ListModelEditorModel(std::function<ModelNode()> createModelCallback,
std::function<ModelNode()> createElementCallback)
std::function<ModelNode()> createElementCallback,
std::function<ModelNode(const ModelNode &)> goIntoComponentCallback)
: m_createModelCallback(std::move(createModelCallback))
, m_createElementCallback(std::move(createElementCallback))
, m_goIntoComponentCallback(std::move(goIntoComponentCallback))
{}
void setListModel(ModelNode node);
@@ -76,6 +78,7 @@ private:
QList<QmlDesigner::PropertyName> m_propertyNames;
std::function<ModelNode()> m_createModelCallback;
std::function<ModelNode()> m_createElementCallback;
std::function<ModelNode(const ModelNode &)> m_goIntoComponentCallback;
};
} // namespace QmlDesigner

View File

@@ -271,7 +271,7 @@ void DocumentManager::removeEditors(const QList<Core::IEditor *> &editors)
delete m_designDocumentHash.take(editor).data();
}
void DocumentManager::goIntoComponent(const ModelNode &modelNode)
bool DocumentManager::goIntoComponent(const ModelNode &modelNode)
{
if (modelNode.isValid() && modelNode.isComponent() && designDocument()) {
QmlDesignerPlugin::instance()->viewManager().setComponentNode(modelNode);
@@ -286,9 +286,14 @@ void DocumentManager::goIntoComponent(const ModelNode &modelNode)
openComponentSourcePropertyOfLoader(modelNode);
else
openInlineComponent(modelNode);
ModelNode rootModelNode = designDocument()->rewriterView()->rootModelNode();
applyProperties(rootModelNode, oldProperties);
return true;
}
return false;
}
bool DocumentManager::createFile(const QString &filePath, const QString &contents)

View File

@@ -51,7 +51,7 @@ public:
void removeEditors(const QList<Core::IEditor *> &editors);
static void goIntoComponent(const ModelNode &modelNode);
static bool goIntoComponent(const ModelNode &modelNode);
static bool createFile(const QString &filePath, const QString &contents);
static void addFileToVersionControl(const QString &directoryPath, const QString &newFilePath);

View File

@@ -698,10 +698,16 @@ Project {
"bindingeditor/bindingeditor.h",
"bindingeditor/actioneditor.cpp",
"bindingeditor/actioneditor.h",
"bindingeditor/abstracteditordialog.cpp",
"bindingeditor/abstracteditordialog.h",
"bindingeditor/actioneditordialog.cpp",
"bindingeditor/actioneditordialog.h",
"bindingeditor/bindingeditordialog.cpp",
"bindingeditor/bindingeditordialog.h",
"bindingeditor/bindingeditorwidget.cpp",
"bindingeditor/bindingeditorwidget.h",
"bindingeditor/connectionvisitor.cpp",
"bindingeditor/connectionvisitor.h",
"colortool/colortool.cpp",
"colortool/colortool.h",
"connectioneditor/addnewbackenddialog.h",

View File

@@ -24,6 +24,8 @@
****************************************************************************/
#include "textmark.h"
#include "fontsettings.h"
#include "textdocument.h"
#include "texteditor.h"
#include "texteditorplugin.h"
@@ -139,8 +141,10 @@ void TextMark::paintAnnotation(QPainter &painter, QRectF *annotationRect,
const QColor &markColor = m_color.has_value()
? Utils::creatorTheme()->color(m_color.value()).toHsl()
: painter.pen().color();
const FontSettings &fontSettings = m_baseTextDocument->fontSettings();
const AnnotationColors &colors = AnnotationColors::getAnnotationColors(
markColor, painter.background().color());
markColor, fontSettings.toTextCharFormat(C_TEXT).background().color());
painter.save();
QLinearGradient grad(rects.fadeInRect.topLeft() - contentOffset,

View File

@@ -317,6 +317,7 @@ void TokenInfo::typeKind(const Cursor &cursor)
m_types.mixinHighlightingTypes.push_back(HighlightingType::Namespace);
return;
case CXCursor_TypeAliasDecl:
case CXCursor_TypeAliasTemplateDecl:
m_types.mixinHighlightingTypes.push_back(HighlightingType::TypeAlias);
return;
case CXCursor_TypedefDecl:

View File

@@ -1226,6 +1226,7 @@ void tst_Dumpers::initTestCase()
m_debuggerVersion = ba.toInt();
if (!m_debuggerVersion) {
if (output.startsWith("lldb version")) {
output = output.split('\n')[0]; // drop clang/llvm version
int pos1 = output.indexOf('.', 13);
int major = output.mid(13, pos1++ - 13).toInt();
int pos2 = output.indexOf(' ', pos1);

View File

@@ -695,3 +695,7 @@ protected:
private:
static int privateValue;
};
template <int i, int j> struct S { };
template <int i> using spec = S<i, 1>;
spec<2> s;

View File

@@ -63,6 +63,7 @@ using testing::Pair;
using testing::PrintToString;
using testing::Property;
using testing::Return;
using testing::ReturnArg;
using testing::ReturnRef;
using testing::SafeMatcherCast;
using testing::SaveArg;
@@ -74,3 +75,4 @@ using testing::Throw;
using testing::TypedEq;
using testing::UnorderedElementsAre;
using testing::VariantWith;
using testing::WithArg;

View File

@@ -99,17 +99,31 @@ public:
listViewNode = mockView.createModelNode("QtQuick.ListView", 2, 15);
listModelNode = mockView.createModelNode("QtQml.Models.ListModel", 2, 15);
mockView.rootModelNode().defaultNodeListProperty().reparentHere(listModelNode);
element1 = createElement({{"name", "foo"}, {"value", 1}, {"value2", 42}});
element2 = createElement({{"value", 4}, {"name", "bar"}, {"image", "pic.png"}});
element3 = createElement({{"image", "pic.png"}, {"name", "poo"}, {"value", 111}});
element1 = createElement({{"name", "foo"}, {"value", 1}, {"value2", 42}},
mockView,
listModelNode);
element2 = createElement({{"value", 4}, {"name", "bar"}, {"image", "pic.png"}},
mockView,
listModelNode);
element3 = createElement({{"image", "pic.png"}, {"name", "poo"}, {"value", 111}},
mockView,
listModelNode);
componentModel->attachView(&mockComponentView);
componentElement = createElement({{"name", "com"}, {"value", 11}, {"value2", 55}},
mockComponentView,
mockComponentView.rootModelNode());
ON_CALL(mockGoIntoComponent, Call(_)).WillByDefault([](ModelNode node) { return node; });
}
using Entry = std::pair<QmlDesigner::PropertyName, QVariant>;
ModelNode createElement(std::initializer_list<Entry> entries)
ModelNode createElement(std::initializer_list<Entry> entries, AbstractView &view, ModelNode listModel)
{
auto element = mockView.createModelNode("QtQml.Models/ListElement", 2, 15);
listModelNode.defaultNodeListProperty().reparentHere(element);
auto element = view.createModelNode("QtQml.Models/ListElement", 2, 15);
listModel.defaultNodeListProperty().reparentHere(element);
for (const auto &entry : entries) {
element.variantProperty(entry.first).setValue(entry.second);
@@ -184,17 +198,23 @@ public:
}
protected:
MockFunction<ModelNode(const ModelNode &)> mockGoIntoComponent;
std::unique_ptr<QmlDesigner::Model> designerModel{QmlDesigner::Model::create("QtQuick.Item", 1, 1)};
NiceMock<MockListModelEditorView> mockView;
QmlDesigner::ListModelEditorModel model{
[&] { return mockView.createModelNode("QtQml.Models.ListModel", 2, 15); },
[&] { return mockView.createModelNode("QtQml.Models.ListElement", 2, 15); }};
[&] { return mockView.createModelNode("QtQml.Models.ListElement", 2, 15); },
mockGoIntoComponent.AsStdFunction()};
ModelNode listViewNode;
ModelNode listModelNode;
ModelNode emptyListModelNode;
ModelNode element1;
ModelNode element2;
ModelNode element3;
std::unique_ptr<QmlDesigner::Model> componentModel{
QmlDesigner::Model::create("QtQml.Models.ListModel", 1, 1)};
NiceMock<MockListModelEditorView> mockComponentView;
ModelNode componentElement;
};
TEST_F(ListModelEditor, CreatePropertyNameSet)
@@ -1376,4 +1396,27 @@ TEST_F(ListModelEditor, AddFalseAsStringProperties)
IsVariantProperty("value", 111))));
}
TEST_F(ListModelEditor, GoIntoComponentForBinding)
{
EXPECT_CALL(mockGoIntoComponent, Call(Eq(listModelNode)))
.WillRepeatedly(Return(mockComponentView.rootModelNode()));
listModelNode.setIdWithoutRefactoring("listModel");
listViewNode.bindingProperty("model").setExpression("listModel");
model.setListView(listViewNode);
ASSERT_THAT(displayValues(), ElementsAre(ElementsAre("com", 11, 55)));
}
TEST_F(ListModelEditor, GoIntoComponentForModelNode)
{
EXPECT_CALL(mockGoIntoComponent, Call(Eq(listModelNode)))
.WillRepeatedly(Return(mockComponentView.rootModelNode()));
listViewNode.nodeProperty("model").reparentHere(listModelNode);
model.setListView(listViewNode);
ASSERT_THAT(displayValues(), ElementsAre(ElementsAre("com", 11, 55)));
}
} // namespace

View File

@@ -1722,6 +1722,13 @@ TEST_F(TokenProcessor, StaticPrivateMember)
ASSERT_THAT(container.extraInfo.accessSpecifier, ClangBackEnd::AccessSpecifier::Private);
}
TEST_F(TokenProcessor, TemplateAlias)
{
const auto infos = translationUnit.tokenInfosInRange(sourceRange(701, 8));
ASSERT_THAT(infos[0], HasTwoTypes(HighlightingType::Type, HighlightingType::TypeAlias));
}
Data *TokenProcessor::d;
void TokenProcessor::SetUpTestCase()

View File

@@ -173,12 +173,14 @@ SOURCES += \
diagnosticset-test.cpp \
diagnostic-test.cpp \
fixit-test.cpp \
gtest-clang-printing.cpp \
highlightingresultreporter-test.cpp \
senddocumenttracker-test.cpp \
skippedsourceranges-test.cpp \
sourcelocation-test.cpp \
sourcerange-test.cpp \
token-test.cpp \
tokenprocessor-test.cpp \
translationunitupdater-test.cpp \
unsavedfiles-test.cpp \
unsavedfile-test.cpp \
@@ -200,7 +202,6 @@ SOURCES += \
clangqueryprojectfindfilter-test.cpp \
clangquery-test.cpp \
clangreferencescollector-test.cpp \
gtest-clang-printing.cpp \
pchcreator-test.cpp \
refactoringclientserverinprocess-test.cpp \
refactoringclient-test.cpp \
@@ -211,8 +212,7 @@ SOURCES += \
symbolscollector-test.cpp \
testclangtool.cpp \
usedmacrocollector-test.cpp \
builddependencycollector-test.cpp \
tokenprocessor-test.cpp
builddependencycollector-test.cpp
!isEmpty(QTC_UNITTEST_BUILD_CPP_PARSER):SOURCES += refactoringengine-test.cpp
@@ -310,14 +310,14 @@ HEADERS += \
clangasyncjob-base.h \
clangcompareoperators.h \
diagnosticcontainer-matcher.h \
gtest-clang-printing.h
}
!isEmpty(LIBTOOLING_LIBS) {
HEADERS += \
gtest-clang-printing.h \
mockrefactoringclient.h \
mockrefactoringserver.h \
testclangtool.h \
testclangtool.h
}
OTHER_FILES += $$files(data/*) $$files(data/include/*)

View File

@@ -324,6 +324,8 @@ QtcProduct {
"diagnosticcontainer-matcher.h",
"diagnosticset-test.cpp",
"fixit-test.cpp",
"gtest-clang-printing.cpp",
"gtest-clang-printing.h",
"highlightingresultreporter-test.cpp",
"readexporteddiagnostics-test.cpp",
"senddocumenttracker-test.cpp",
@@ -331,6 +333,7 @@ QtcProduct {
"sourcelocation-test.cpp",
"sourcerange-test.cpp",
"token-test.cpp",
"tokenprocessor-test.cpp",
"translationunitupdater-test.cpp",
"unsavedfile-test.cpp",
"unsavedfiles-test.cpp",
@@ -348,8 +351,6 @@ QtcProduct {
"clangquerygatherer-test.cpp",
"clangqueryprojectfindfilter-test.cpp",
"clangreferencescollector-test.cpp",
"gtest-clang-printing.cpp",
"gtest-clang-printing.h",
"gtest-llvm-printing.cpp",
"mockrefactoringclient.h",
"mockrefactoringserver.h",
@@ -364,7 +365,6 @@ QtcProduct {
"symbolscollector-test.cpp",
"testclangtool.cpp",
"testclangtool.h",
"tokenprocessor-test.cpp",
"usedmacrocollector-test.cpp",
]
}