forked from qt-creator/qt-creator
Merge remote-tracking branch 'origin/4.13' into master
Conflicts: src/plugins/qmakeprojectmanager/qmakeproject.cpp Change-Id: Ieb1c3e946f11d3c4fa1ee6b5afdf83cc532d8aed
This commit is contained in:
68
README.md
68
README.md
@@ -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
108
dist/changes-4.13.1.md
vendored
Normal 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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ Section {
|
||||
|
||||
StudioControls.AbstractButton {
|
||||
id: richTextEditorButton
|
||||
buttonIcon: StudioTheme.Constants.textAlignTop
|
||||
buttonIcon: StudioTheme.Constants.edit
|
||||
onClicked: {
|
||||
richTextDialogLoader.show()
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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=""
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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"));
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
);
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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."));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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/*)
|
||||
|
||||
@@ -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",
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user